- 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.
This commit is contained in:
Serge Ivanov 2000-06-07 03:48:02 +00:00 committed by Alexandre Julliard
parent 9eedcf5852
commit 9926d33450
2 changed files with 83 additions and 99 deletions

View File

@ -527,7 +527,7 @@ static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
/* 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 @@ static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
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 @@ static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
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 @@ static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
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 @@ static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
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 @@ static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC hParamDC)
*
* 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 @@ static INT CBUpdateLBox( LPHEADCOMBO lphc )
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 @@ static void CBDropDown( LPHEADCOMBO lphc )
{
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 @@ static void CBDropDown( LPHEADCOMBO lphc )
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 @@ static void CBDropDown( LPHEADCOMBO lphc )
{
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 @@ static void CBDropDown( LPHEADCOMBO lphc )
/* 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 @@ static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
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 @@ static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
*
* 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;
}
@ -1275,19 +1250,6 @@ BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL bRedrawButton )
return TRUE;
}
/***********************************************************************
* COMBO_GetLBWindow
*
* Edit control helper.
*/
HWND COMBO_GetLBWindow( WND* pWnd )
{
LPHEADCOMBO lphc = CB_GETPTR(pWnd);
if( lphc ) return lphc->hWndLBox;
return 0;
}
/***********************************************************************
* CBRepaintButton
*/
@ -1393,7 +1355,7 @@ static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
}
else
{
CBUpdateLBox( lphc );
CBUpdateLBox( lphc, lphc->wState & CBF_DROPPED );
}
break;
@ -1434,18 +1396,22 @@ static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
}
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 @@ static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
/* 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 @@ static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
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 @@ static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM wParam, LPARAM lParam )
{
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 @@ static inline LRESULT WINAPI ComboWndProc_locked( WND* pWnd, UINT message,
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 @@ static inline LRESULT WINAPI ComboWndProc_locked( WND* pWnd, UINT message,
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

View File

@ -61,8 +61,7 @@ typedef struct
LRESULT WINAPI ComboWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
BOOL COMBO_FlipListbox( LPHEADCOMBO, BOOL );
HWND COMBO_GetLBWindow( struct tagWND * );
BOOL COMBO_FlipListbox( LPHEADCOMBO, BOOL, BOOL );
LRESULT COMBO_Directory( LPHEADCOMBO, UINT, LPSTR, BOOL );
#endif /* __WINE_COMBO_H */