From 6ec3eaf54b4b07ab6cc722e142b7c74998473d95 Mon Sep 17 00:00:00 2001 From: Francis Beaudet Date: Sat, 12 Jun 1999 10:51:19 +0000 Subject: [PATCH] Fixed a few behaviors of the combobox that were broken. --- controls/combo.c | 70 ++++++++++++++++++++++++++++++++++------- controls/listbox.c | 78 +++++++++++++++++++++++++++++++++++++++++++++- include/combo.h | 2 ++ 3 files changed, 137 insertions(+), 13 deletions(-) diff --git a/controls/combo.c b/controls/combo.c index 150f858e200..63f8692ed1c 100644 --- a/controls/combo.c +++ b/controls/combo.c @@ -548,11 +548,28 @@ static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam) lphc->droppedRect.top, lphc->droppedRect.right - lphc->droppedRect.left, lphc->droppedRect.bottom - lphc->droppedRect.top, - lphc->self->hwndSelf, + lphc->self->hwndSelf, (lphc->dwStyle & CBS_DROPDOWN)? (HMENU)0 : (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; @@ -1040,6 +1057,9 @@ static void CBUpdateEdit( LPHEADCOMBO lphc , INT index ) { SendMessageA( lphc->hWndLBox, LB_GETTEXT, (WPARAM)index, (LPARAM)pText ); + + lphc->wState |= CBF_NOEDITNOTIFY; + SendMessageA( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText ); SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) ); HeapFree( GetProcessHeap(), 0, pText ); @@ -1055,7 +1075,6 @@ static void CBUpdateEdit( LPHEADCOMBO lphc , INT index ) */ static void CBDropDown( LPHEADCOMBO lphc ) { - INT index; RECT rect; TRACE("[%04x]: drop down\n", CB_HWND(lphc)); @@ -1067,14 +1086,19 @@ static void CBDropDown( LPHEADCOMBO lphc ) lphc->wState |= CBF_DROPPED; if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) { - index = CBUpdateLBox( lphc ); - if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index ); + lphc->droppedIndex = CBUpdateLBox( lphc ); + + if( !(lphc->wState & CBF_CAPTURE) ) + CBUpdateEdit( lphc, lphc->droppedIndex ); } else { - index = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 ); - if( index == LB_ERR ) index = 0; - SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)index, 0 ); + 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_CARETON, 0, 0 ); } @@ -1116,8 +1140,11 @@ static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton ) TRACE("[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT)ok ); - /* always send WM_LBUTTONUP? */ - SendMessageA( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) ); + /* + * It seems useful to send the WM_LBUTTONUP with (-1,-1) when cancelling + * and with (0,0) (anywhere in the listbox) when Oking. + */ + SendMessageA( lphc->hWndLBox, WM_LBUTTONUP, 0, ok ? (LPARAM)0 : (LPARAM)(-1) ); if( lphc->wState & CBF_DROPPED ) { @@ -1252,7 +1279,7 @@ static void COMBO_KillFocus( LPHEADCOMBO lphc ) */ static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd ) { - if( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd ) + if ( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd ) { /* ">> 8" makes gcc generate jump-table instead of cmp ladder */ @@ -1282,7 +1309,22 @@ static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd ) case (EN_CHANGE >> 8): - CB_NOTIFY( lphc, CBN_EDITCHANGE ); + /* + * In some circumstances (when the selection of the combobox + * is changed for example) we don't wans the EN_CHANGE notification + * to be forwarded to the parent of the combobox. This code + * checks a flag that is set in these occasions and ignores the + * notification. + */ + if (lphc->wState & CBF_NOEDITNOTIFY) + { + lphc->wState &= ~CBF_NOEDITNOTIFY; + } + else + { + CB_NOTIFY( lphc, CBN_EDITCHANGE ); + } + CBUpdateLBox( lphc ); break; @@ -1763,7 +1805,11 @@ static inline LRESULT WINAPI ComboWndProc_locked( WND* pWnd, UINT message, case WM_PASTE: case WM_COPY: if( lphc->wState & CBF_EDIT ) - return SendMessageA( lphc->hWndEdit, message, wParam, lParam ); + { + lphc->wState |= CBF_NOEDITNOTIFY; + + return SendMessageA( lphc->hWndEdit, message, wParam, lParam ); + } return CB_ERR; case WM_DRAWITEM: case WM_DELETEITEM: diff --git a/controls/listbox.c b/controls/listbox.c index 7cb45b97d2e..9d034371346 100644 --- a/controls/listbox.c +++ b/controls/listbox.c @@ -1281,7 +1281,7 @@ static void LISTBOX_MoveCaret( WND *wnd, LB_DESCR *descr, INT index, LISTBOX_SelectItemRange( wnd, descr, first, last, TRUE ); } } - else if (!(descr->style & LBS_MULTIPLESEL) && (descr->selected_item != -1)) + else if (!(descr->style & LBS_MULTIPLESEL)) { /* Set selection to new caret item */ LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE ); @@ -2611,6 +2611,82 @@ static inline LRESULT WINAPI ComboLBWndProc_locked( WND* wnd, UINT msg, lphc = (LPHEADCOMBO)(lpcs->lpCreateParams); #undef lpcs return LISTBOX_Create( wnd, lphc ); + case WM_MOUSEMOVE: + if ( (TWEAK_WineLook > WIN31_LOOK) && + (CB_GETTYPE(lphc) != CBS_SIMPLE) ) + { + POINT mousePos; + BOOL captured; + RECT clientRect; + + mousePos.x = (INT16)LOWORD(lParam); + mousePos.y = (INT16)HIWORD(lParam); + + /* + * If we are in a dropdown combobox, we simulate that + * the mouse is captured to show the tracking of the item. + */ + captured = descr->captured; + descr->captured = TRUE; + + LISTBOX_HandleMouseMove( wnd, + descr, + mousePos.x, mousePos.y); + + descr->captured = captured; + + /* + * However, when tracking, it is important that we do not + * perform a selection if the cursor is outside the list. + */ + GetClientRect(hwnd, &clientRect); + + if (!PtInRect( &clientRect, mousePos )) + { + LISTBOX_MoveCaret( wnd, descr, -1, FALSE ); + } + + return 0; + } + else + { + /* + * If we are in Win3.1 look, go with the default behavior. + */ + return ListBoxWndProc( hwnd, msg, wParam, lParam ); + } + case WM_LBUTTONUP: + if (TWEAK_WineLook > WIN31_LOOK) + { + POINT mousePos; + RECT clientRect; + + /* + * If the mouse button "up" is not in the listbox, + * we make sure there is no selection by re-selecting the + * item that was selected when the listbox was made visible. + */ + mousePos.x = (INT16)LOWORD(lParam); + mousePos.y = (INT16)HIWORD(lParam); + + GetClientRect(hwnd, &clientRect); + + /* + * When the user clicks outside the combobox and the focus + * is lost, the owning combobox will send a fake buttonup with + * 0xFFFFFFF as the mouse location, we must also revert the + * selection to the original selection. + */ + if ( (lParam == 0xFFFFFFFF) || + (!PtInRect( &clientRect, mousePos )) ) + { + LISTBOX_MoveCaret( wnd, + descr, + lphc->droppedIndex, + FALSE ); + } + } + return LISTBOX_HandleLButtonUp( wnd, descr ); case WM_LBUTTONDOWN: return LISTBOX_HandleLButtonDown( wnd, descr, wParam, (INT16)LOWORD(lParam), (INT16)HIWORD(lParam)); diff --git a/include/combo.h b/include/combo.h index 4886ba9e511..67d6ea86d19 100644 --- a/include/combo.h +++ b/include/combo.h @@ -21,6 +21,7 @@ #define CBF_NOTIFY 0x0100 #define CBF_NOREDRAW 0x0200 #define CBF_SELCHANGE 0x0400 +#define CBF_NOEDITNOTIFY 0x1000 #define CBF_EUI 0x8000 /* Combo state struct */ @@ -37,6 +38,7 @@ typedef struct RECT textRect; RECT buttonRect; RECT droppedRect; + INT droppedIndex; INT fixedOwnerDrawHeight; INT droppedWidth; /* last two are not used unless set */ INT editHeight; /* explicitly */