- ComboLBox is always created as child of ComboBox. If ComboBox has style
other than CBS_SIMPLE, parent of listbox is set to desktop.
- In CBDropDown. ComboBox uses only first item to calculate height of
dropped listbox. Also if listbox is empty its height is unmodified
(previously it was set to 0).
- Added correct handling of WM_GETDLGCODE and WM_(SYS)KEYDOWN messages.
- General clean-up. Message order is now more precise (at least
notifications to client); listbox - combobox interaction has slight
differences comparing to Windows.
diff --git a/controls/combo.c b/controls/combo.c
index a1a2967..b5d20b1 100644
--- a/controls/combo.c
+++ b/controls/combo.c
@@ -527,7 +527,7 @@
/* create listbox popup */
- lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) |
+ lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD) |
(lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
if( lphc->dwStyle & CBS_SORT )
@@ -541,7 +541,7 @@
if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */
{
- lbeStyle |= WS_CHILD | WS_VISIBLE;
+ lbeStyle |= WS_VISIBLE;
/*
* In win 95 look n feel, the listbox in the simple combobox has
@@ -553,12 +553,7 @@
lbeExStyle |= WS_EX_CLIENTEDGE;
}
}
- else /* popup listbox */
- lbeStyle |= WS_POPUP;
- /* Dropdown ComboLBox is not a child window and we cannot pass
- * ID_CB_LISTBOX directly because it will be treated as a menu handle.
- */
lphc->hWndLBox = CreateWindowExA(lbeExStyle,
clbName,
NULL,
@@ -568,31 +563,14 @@
lphc->droppedRect.right - lphc->droppedRect.left,
lphc->droppedRect.bottom - lphc->droppedRect.top,
lphc->self->hwndSelf,
- (lphc->dwStyle & CBS_DROPDOWN)? (HMENU)0 : (HMENU)ID_CB_LISTBOX,
+ (HMENU)ID_CB_LISTBOX,
lphc->self->hInstance,
(LPVOID)lphc );
- /*
- * The ComboLBox is a strange little beast (when it's not a CBS_SIMPLE)...
- * It's a popup window but, when you get the window style, you get WS_CHILD.
- * When created, it's parent is the combobox but, when you ask for it's parent
- * after that, you're supposed to get the desktop. (see MFC code function
- * AfxCancelModes)
- * To achieve this in Wine, we have to create it as a popup and change
- * it's style to child after the creation.
- */
- if ( (lphc->hWndLBox!= 0) &&
- (CB_GETTYPE(lphc) != CBS_SIMPLE) )
- {
- SetWindowLongA(lphc->hWndLBox,
- GWL_STYLE,
- (GetWindowLongA(lphc->hWndLBox, GWL_STYLE) | WS_CHILD) & ~WS_POPUP);
- }
-
if( lphc->hWndLBox )
{
BOOL bEdit = TRUE;
- lbeStyle = WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT;
+ lbeStyle = WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT | ES_COMBO;
/*
* In Win95 look, the border fo the edit control is
@@ -630,14 +608,16 @@
if( bEdit )
{
- /*
- * If the combo is a dropdown, we must resize the control to fit only
- * the text area and button. To do this, we send a dummy resize and the
- * WM_WINDOWPOSCHANGING message will take care of setting the height for
- * us.
- */
if( CB_GETTYPE(lphc) != CBS_SIMPLE )
{
+ /* Now do the trick with parent */
+ SetParent(lphc->hWndLBox, HWND_DESKTOP);
+ /*
+ * If the combo is a dropdown, we must resize the control to fit only
+ * the text area and button. To do this, we send a dummy resize and the
+ * WM_WINDOWPOSCHANGING message will take care of setting the height for
+ * us.
+ */
CBForceDummyResize(lphc);
}
@@ -1053,7 +1033,7 @@
*
* Select listbox entry according to the contents of the edit control.
*/
-static INT CBUpdateLBox( LPHEADCOMBO lphc )
+static INT CBUpdateLBox( LPHEADCOMBO lphc, BOOL bSelect )
{
INT length, idx;
LPSTR pText = NULL;
@@ -1075,12 +1055,11 @@
HeapFree( GetProcessHeap(), 0, pText );
}
- if( idx >= 0 )
- {
- SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)idx, 0 );
+ SendMessageA( lphc->hWndLBox, LB_SETCURSEL, (WPARAM)(bSelect ? idx : -1), 0 );
+
/* probably superfluous but Windows sends this too */
- SendMessageA( lphc->hWndLBox, LB_SETCARETINDEX, (WPARAM)idx, 0 );
- }
+ SendMessageA( lphc->hWndLBox, LB_SETCARETINDEX, (WPARAM)(idx < 0 ? 0 : idx), 0 );
+ SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)(idx < 0 ? 0 : idx), 0 );
return idx;
}
@@ -1129,9 +1108,7 @@
{
RECT rect;
int nItems = 0;
- int i;
- int nHeight;
- int nDroppedHeight, nTempDroppedHeight;
+ int nDroppedHeight;
TRACE("[%04x]: drop down\n", CB_HWND(lphc));
@@ -1142,7 +1119,7 @@
lphc->wState |= CBF_DROPPED;
if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
{
- lphc->droppedIndex = CBUpdateLBox( lphc );
+ lphc->droppedIndex = CBUpdateLBox( lphc, TRUE );
if( !(lphc->wState & CBF_CAPTURE) )
CBUpdateEdit( lphc, lphc->droppedIndex );
@@ -1151,10 +1128,8 @@
{
lphc->droppedIndex = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
- if( lphc->droppedIndex == LB_ERR )
- lphc->droppedIndex = 0;
-
- SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)lphc->droppedIndex, 0 );
+ SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX,
+ (WPARAM)(lphc->droppedIndex == LB_ERR ? 0 : lphc->droppedIndex), 0 );
SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 );
}
@@ -1174,33 +1149,35 @@
/* And Remove any extra space (Best Fit) */
nDroppedHeight = lphc->droppedRect.bottom - lphc->droppedRect.top;
nItems = (int)SendMessageA (lphc->hWndLBox, LB_GETCOUNT, 0, 0);
- nHeight = COMBO_YBORDERSIZE();
- nTempDroppedHeight = 0;
- for (i = 0; i < nItems; i++)
+
+ if (nItems > 0)
{
- nHeight += (int)SendMessageA (lphc->hWndLBox, LB_GETITEMHEIGHT, i, 0);
+ int nHeight;
- /* Did we pass the limit of what can be displayed */
- if (nHeight > nDroppedHeight)
- {
- break;
- }
- nTempDroppedHeight = nHeight;
+ nHeight = (int)SendMessageA (lphc->hWndLBox, LB_GETITEMHEIGHT, 0, 0);
+ nHeight *= nItems;
+
+ if (nHeight < nDroppedHeight - COMBO_YBORDERSIZE())
+ nDroppedHeight = nHeight + COMBO_YBORDERSIZE();
}
- nDroppedHeight = nTempDroppedHeight;
+ /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
+ if( (rect.bottom + nDroppedHeight) >= GetSystemMetrics( SM_CYSCREEN ) )
+ rect.bottom = rect.top - nDroppedHeight;
SetWindowPos( lphc->hWndLBox, HWND_TOP, rect.left, rect.bottom,
lphc->droppedRect.right - lphc->droppedRect.left,
- nDroppedHeight,
- SWP_NOACTIVATE | SWP_NOREDRAW);
+ nDroppedHeight,
+ SWP_NOACTIVATE | SWP_SHOWWINDOW);
+
if( !(lphc->wState & CBF_NOREDRAW) )
RedrawWindow( lphc->self->hwndSelf, NULL, 0, RDW_INVALIDATE |
RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
EnableWindow( lphc->hWndLBox, TRUE );
- ShowWindow( lphc->hWndLBox, SW_SHOW);
+ if (GetCapture() != lphc->self->hwndSelf)
+ SetCapture(lphc->hWndLBox);
}
/***********************************************************************
@@ -1232,8 +1209,6 @@
if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
{
- INT index = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
- CBUpdateEdit( lphc, index );
rect = lphc->buttonRect;
}
else
@@ -1263,11 +1238,11 @@
*
* Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
*/
-BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL bRedrawButton )
+BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL ok, BOOL bRedrawButton )
{
if( lphc->wState & CBF_DROPPED )
{
- CBRollUp( lphc, TRUE, bRedrawButton );
+ CBRollUp( lphc, ok, bRedrawButton );
return FALSE;
}
@@ -1276,19 +1251,6 @@
}
/***********************************************************************
- * COMBO_GetLBWindow
- *
- * Edit control helper.
- */
-HWND COMBO_GetLBWindow( WND* pWnd )
-{
- LPHEADCOMBO lphc = CB_GETPTR(pWnd);
- if( lphc ) return lphc->hWndLBox;
- return 0;
-}
-
-
-/***********************************************************************
* CBRepaintButton
*/
static void CBRepaintButton( LPHEADCOMBO lphc )
@@ -1393,7 +1355,7 @@
}
else
{
- CBUpdateLBox( lphc );
+ CBUpdateLBox( lphc, lphc->wState & CBF_DROPPED );
}
break;
@@ -1434,18 +1396,22 @@
}
else lphc->wState &= ~CBF_NOROLLUP;
- if( lphc->wState & CBF_EDIT )
- {
- INT index = SendMessageA(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
- lphc->wState |= CBF_NOLBSELECT;
- CBUpdateEdit( lphc, index );
- /* select text in edit, as Windows does */
- SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) );
- }
- else
- InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
-
CB_NOTIFY( lphc, CBN_SELCHANGE );
+
+ if( HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ if( lphc->wState & CBF_EDIT )
+ {
+ INT index = SendMessageA(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
+ lphc->wState |= CBF_NOLBSELECT;
+ CBUpdateEdit( lphc, index );
+ /* select text in edit, as Windows does */
+ SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) );
+ }
+ else
+ InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
+ }
+
/* fall through */
case LBN_SETFOCUS:
@@ -1738,8 +1704,8 @@
/* drop down the listbox and start tracking */
lphc->wState |= CBF_CAPTURE;
- CBDropDown( lphc );
SetCapture( hWnd );
+ CBDropDown( lphc );
}
if( bButton ) CBRepaintButton( lphc );
}
@@ -1757,8 +1723,10 @@
lphc->wState &= ~CBF_CAPTURE;
if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
{
- INT index = CBUpdateLBox( lphc );
+ INT index = CBUpdateLBox( lphc, TRUE );
+ lphc->wState |= CBF_NOLBSELECT;
CBUpdateEdit( lphc, index );
+ lphc->wState &= ~CBF_NOLBSELECT;
}
ReleaseCapture();
SetCapture(lphc->hWndLBox);
@@ -1805,7 +1773,7 @@
{
lphc->wState &= ~CBF_CAPTURE;
ReleaseCapture();
- if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
+ if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc, TRUE );
/* hand over pointer tracking */
SendMessageA( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
@@ -1853,9 +1821,19 @@
return COMBO_Paint(lphc, wParam);
case WM_ERASEBKGND:
return COMBO_EraseBackground(hwnd, lphc, wParam);
- case WM_GETDLGCODE:
- return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
- case WM_WINDOWPOSCHANGING:
+ case WM_GETDLGCODE:
+ {
+ LRESULT result = DLGC_WANTARROWS | DLGC_WANTCHARS;
+ if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
+ {
+ int vk = (int)((LPMSG)lParam)->wParam;
+
+ if ((vk == VK_RETURN || vk == VK_ESCAPE) && (lphc->wState & CBF_DROPPED))
+ result |= DLGC_WANTMESSAGE;
+ }
+ return result;
+ }
+ case WM_WINDOWPOSCHANGING:
return COMBO_WindowPosChanging(hwnd, lphc, (LPWINDOWPOS)lParam);
case WM_SIZE:
if( lphc->hWndLBox &&
@@ -1931,11 +1909,18 @@
case WM_SYSKEYDOWN:
if( KEYDATA_ALT & HIWORD(lParam) )
if( wParam == VK_UP || wParam == VK_DOWN )
- COMBO_FlipListbox( lphc, TRUE );
- break;/* -> DefWindowProc */
+ COMBO_FlipListbox( lphc, FALSE, FALSE );
+ return 0;
case WM_CHAR:
case WM_KEYDOWN:
+ if (((CHAR)wParam == VK_RETURN || (CHAR)wParam == VK_ESCAPE) &&
+ (lphc->wState & CBF_DROPPED))
+ {
+ CBRollUp( lphc, (CHAR)wParam == VK_RETURN, FALSE );
+ return TRUE;
+ }
+
if( lphc->wState & CBF_EDIT )
return SendMessageA( lphc->hWndEdit, message, wParam, lParam );
else