From 6855cd15c2254cd7717ce55a3deb7d1c55780678 Mon Sep 17 00:00:00 2001 From: Giannis Adamopoulos Date: Sun, 17 Jul 2011 15:18:11 +0000 Subject: [PATCH] [user32] - Partly sync button handling with wine. Needed for hot tracking svn path=/branches/GSoC_2011/ThemesSupport/; revision=52715 --- dll/win32/user32/controls/button.c | 203 ++++++++++------------------- 1 file changed, 72 insertions(+), 131 deletions(-) diff --git a/dll/win32/user32/controls/button.c b/dll/win32/user32/controls/button.c index 3fef42efc56..66d97c3998a 100644 --- a/dll/win32/user32/controls/button.c +++ b/dll/win32/user32/controls/button.c @@ -31,7 +31,6 @@ * Styles * - BS_NOTIFY: is it complete? * - BS_RIGHTBUTTON: same as BS_LEFTTEXT - * - BS_TYPEMASK * * Messages * - WM_CHAR: Checks a (manual or automatic) check box on '+' or '=', clears it on '-' key. @@ -72,17 +71,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(button); #define STATE_GWL_OFFSET 0 #define HFONT_GWL_OFFSET (sizeof(LONG)) #define HIMAGE_GWL_OFFSET (HFONT_GWL_OFFSET+sizeof(HFONT)) -#define UISTATE_GWL_OFFSET (HIMAGE_GWL_OFFSET+sizeof(HFONT)) -#define NB_EXTRA_BYTES (UISTATE_GWL_OFFSET+sizeof(LONG)) +#define NB_EXTRA_BYTES (HIMAGE_GWL_OFFSET+sizeof(HANDLE)) - /* Button state values */ -#define BUTTON_UNCHECKED 0x00 -#define BUTTON_CHECKED 0x01 -#define BUTTON_3STATE 0x02 -#define BUTTON_HIGHLIGHTED 0x04 -#define BUTTON_HASFOCUS 0x08 +/* undocumented flags */ #define BUTTON_NSTATES 0x0F - /* undocumented flags */ #define BUTTON_BTNPRESSED 0x40 #define BUTTON_UNKNOWN2 0x20 #define BUTTON_UNKNOWN3 0x10 @@ -103,22 +95,22 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action ); static void OB_Paint( HWND hwnd, HDC hDC, UINT action ); static void BUTTON_CheckAutoRadioButton( HWND hwnd ); -#define MAX_BTN_TYPE 12 +#define MAX_BTN_TYPE 16 static const WORD maxCheckState[MAX_BTN_TYPE] = { - BUTTON_UNCHECKED, /* BS_PUSHBUTTON */ - BUTTON_UNCHECKED, /* BS_DEFPUSHBUTTON */ - BUTTON_CHECKED, /* BS_CHECKBOX */ - BUTTON_CHECKED, /* BS_AUTOCHECKBOX */ - BUTTON_CHECKED, /* BS_RADIOBUTTON */ - BUTTON_3STATE, /* BS_3STATE */ - BUTTON_3STATE, /* BS_AUTO3STATE */ - BUTTON_UNCHECKED, /* BS_GROUPBOX */ - BUTTON_UNCHECKED, /* BS_USERBUTTON */ - BUTTON_CHECKED, /* BS_AUTORADIOBUTTON */ - BUTTON_UNCHECKED, /* Not defined */ - BUTTON_UNCHECKED /* BS_OWNERDRAW */ + BST_UNCHECKED, /* BS_PUSHBUTTON */ + BST_UNCHECKED, /* BS_DEFPUSHBUTTON */ + BST_CHECKED, /* BS_CHECKBOX */ + BST_CHECKED, /* BS_AUTOCHECKBOX */ + BST_CHECKED, /* BS_RADIOBUTTON */ + BST_INDETERMINATE, /* BS_3STATE */ + BST_INDETERMINATE, /* BS_AUTO3STATE */ + BST_UNCHECKED, /* BS_GROUPBOX */ + BST_UNCHECKED, /* BS_USERBUTTON */ + BST_CHECKED, /* BS_AUTORADIOBUTTON */ + BST_UNCHECKED, /* BS_PUSHBOX */ + BST_UNCHECKED /* BS_OWNERDRAW */ }; typedef void (*pfPaint)( HWND hwnd, HDC hdc, UINT action ); @@ -135,7 +127,7 @@ static const pfPaint btnPaintFunc[MAX_BTN_TYPE] = GB_Paint, /* BS_GROUPBOX */ UB_Paint, /* BS_USERBUTTON */ CB_Paint, /* BS_AUTORADIOBUTTON */ - NULL, /* Not defined */ + NULL, /* BS_PUSHBOX */ OB_Paint /* BS_OWNERDRAW */ }; @@ -169,17 +161,7 @@ static inline void set_button_state( HWND hwnd, LONG state ) SetWindowLongPtrW( hwnd, STATE_GWL_OFFSET, state ); } -static __inline void set_ui_state( HWND hwnd, LONG flags ) -{ - SetWindowLongPtrW( hwnd, UISTATE_GWL_OFFSET, flags ); -} - -static __inline LONG get_ui_state( HWND hwnd ) -{ - return GetWindowLongPtrW( hwnd, UISTATE_GWL_OFFSET ); -} - -__inline static HFONT get_button_font( HWND hwnd ) +static inline HFONT get_button_font( HWND hwnd ) { return (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET ); } @@ -191,7 +173,7 @@ static inline void set_button_font( HWND hwnd, HFONT font ) static inline UINT get_button_type( LONG window_style ) { - return (window_style & 0x0f); + return (window_style & BS_TYPEMASK); } /* paint a button of any type */ @@ -223,27 +205,6 @@ static void setup_clipping( HWND hwnd, HDC hdc ) IntersectClipRect( hdc, rc.left, rc.top, rc.right, rc.bottom ); } -/* Retrieve the UI state for the control */ -static BOOL button_update_uistate(HWND hwnd, BOOL unicode) -{ - LONG flags, prevflags; - - if (unicode) - flags = DefWindowProcW(hwnd, WM_QUERYUISTATE, 0, 0); - else - flags = DefWindowProcA(hwnd, WM_QUERYUISTATE, 0, 0); - - prevflags = get_ui_state(hwnd); - - if (prevflags != flags) - { - set_ui_state(hwnd, flags); - return TRUE; - } - - return FALSE; -} - /*********************************************************************** * ButtonWndProc_common */ @@ -256,6 +217,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, UINT btn_type = get_button_type( style ); LONG state; HANDLE oldHbitmap; + #ifdef __REACTOS__ PWND pWnd; @@ -269,6 +231,8 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, } #endif + if (!IsWindow( hWnd )) return 0; + pt.x = (short)LOWORD(lParam); pt.y = (short)HIWORD(lParam); @@ -305,11 +269,10 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, /* XP turns a BS_USERBUTTON into BS_PUSHBUTTON */ if (btn_type == BS_USERBUTTON ) { - style = (style & ~0x0f) | BS_PUSHBUTTON; + style = (style & ~BS_TYPEMASK) | BS_PUSHBUTTON; SetWindowLongPtrW( hWnd, GWL_STYLE, style ); } - set_button_state( hWnd, BUTTON_UNCHECKED ); - button_update_uistate( hWnd, unicode ); + set_button_state( hWnd, BST_UNCHECKED ); return 0; #ifdef __REACTOS__ @@ -384,7 +347,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, if (!(state & BUTTON_BTNPRESSED)) break; state &= BUTTON_NSTATES; set_button_state( hWnd, state ); - if (!(state & BUTTON_HIGHLIGHTED)) + if (!(state & BST_PUSHED)) { ReleaseCapture(); break; @@ -398,14 +361,14 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, switch(btn_type) { case BS_AUTOCHECKBOX: - SendMessageW( hWnd, BM_SETCHECK, !(state & BUTTON_CHECKED), 0 ); + SendMessageW( hWnd, BM_SETCHECK, !(state & BST_CHECKED), 0 ); break; case BS_AUTORADIOBUTTON: SendMessageW( hWnd, BM_SETCHECK, TRUE, 0 ); break; case BS_AUTO3STATE: SendMessageW( hWnd, BM_SETCHECK, - (state & BUTTON_3STATE) ? 0 : ((state & 3) + 1), 0 ); + (state & BST_INDETERMINATE) ? 0 : ((state & 3) + 1), 0 ); break; } BUTTON_NOTIFY_PARENT(hWnd, BN_CLICKED); @@ -419,7 +382,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, { state &= BUTTON_NSTATES; set_button_state( hWnd, state ); - if (state & BUTTON_HIGHLIGHTED) SendMessageW( hWnd, BM_SETSTATE, FALSE, 0 ); + if (state & BST_PUSHED) SendMessageW( hWnd, BM_SETSTATE, FALSE, 0 ); } break; @@ -474,7 +437,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, case WM_SETFOCUS: TRACE("WM_SETFOCUS %p\n",hWnd); - set_button_state( hWnd, get_button_state(hWnd) | BUTTON_HASFOCUS ); + set_button_state( hWnd, get_button_state(hWnd) | BST_FOCUS ); paint_button( hWnd, btn_type, ODA_FOCUS ); if (style & BS_NOTIFY) BUTTON_NOTIFY_PARENT(hWnd, BN_SETFOCUS); @@ -483,7 +446,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, case WM_KILLFOCUS: TRACE("WM_KILLFOCUS %p\n",hWnd); state = get_button_state( hWnd ); - set_button_state( hWnd, state & ~BUTTON_HASFOCUS ); + set_button_state( hWnd, state & ~BST_FOCUS ); paint_button( hWnd, btn_type, ODA_FOCUS ); if ((state & BUTTON_BTNPRESSED) && GetCapture() == hWnd) @@ -499,9 +462,9 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, break; case BM_SETSTYLE: - if ((wParam & 0x0f) >= MAX_BTN_TYPE) break; - btn_type = wParam & 0x0f; - style = (style & ~0x0f) | btn_type; + if ((wParam & BS_TYPEMASK) >= MAX_BTN_TYPE) break; + btn_type = wParam & BS_TYPEMASK; + style = (style & ~BS_TYPEMASK) | btn_type; SetWindowLongPtrW( hWnd, GWL_STYLE, style ); /* Only redraw if lParam flag is set.*/ @@ -552,7 +515,7 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, set_button_state( hWnd, (state & ~3) | wParam ); paint_button( hWnd, btn_type, ODA_SELECT ); } - if ((btn_type == BS_AUTORADIOBUTTON) && (wParam == BUTTON_CHECKED) && (style & WS_CHILD)) + if ((btn_type == BS_AUTORADIOBUTTON) && (wParam == BST_CHECKED) && (style & WS_CHILD)) BUTTON_CheckAutoRadioButton( hWnd ); break; @@ -562,28 +525,13 @@ LRESULT WINAPI ButtonWndProc_common(HWND hWnd, UINT uMsg, case BM_SETSTATE: state = get_button_state( hWnd ); if (wParam) - { - if (state & BUTTON_HIGHLIGHTED) break; - set_button_state( hWnd, state | BUTTON_HIGHLIGHTED ); - } + set_button_state( hWnd, state | BST_PUSHED ); else - { - if (!(state & BUTTON_HIGHLIGHTED)) break; - set_button_state( hWnd, state & ~BUTTON_HIGHLIGHTED ); - } + set_button_state( hWnd, state & ~BST_PUSHED ); + paint_button( hWnd, btn_type, ODA_SELECT ); break; - case WM_UPDATEUISTATE: - if (unicode) - DefWindowProcW(hWnd, uMsg, wParam, lParam); - else - DefWindowProcA(hWnd, uMsg, wParam, lParam); - - if (button_update_uistate(hWnd, unicode)) - paint_button( hWnd, btn_type, ODA_DRAWENTIRE ); - break; - case WM_NCHITTEST: if(btn_type == BS_GROUPBOX) return HTTRANSPARENT; /* fall through */ @@ -626,7 +574,7 @@ static UINT BUTTON_BStoDT( DWORD style, DWORD ex_style ) /* "Convert" pushlike buttons to pushbuttons */ if (style & BS_PUSHLIKE) - style &= ~0x0F; + style &= ~BS_TYPEMASK; if (!(style & BS_MULTILINE)) dtStyle |= DT_SINGLELINE; @@ -699,9 +647,6 @@ static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc) } DrawTextW(hdc, text, -1, &r, dtStyle | DT_CALCRECT); HeapFree( GetProcessHeap(), 0, text ); - - if (get_ui_state( hwnd ) & UISF_HIDEACCEL) - dtStyle |= DT_HIDEPREFIX; break; case BS_ICON: @@ -805,7 +750,7 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, const RECT *rc) * I don't have Win31 on hand to verify that, so I leave it as is. */ - if ((style & BS_PUSHLIKE) && (state & BUTTON_3STATE)) + if ((style & BS_PUSHLIKE) && (state & BST_INDETERMINATE)) { hbr = GetSysColorBrush(COLOR_GRAYTEXT); flags |= DSS_MONO; @@ -818,10 +763,7 @@ static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, const RECT *rc) lpOutputProc = BUTTON_DrawTextCallback; if (!(text = get_button_text( hwnd ))) return; lp = (LPARAM)text; - wp = (WPARAM)dtFlags; - - if (dtFlags & DT_HIDEPREFIX) - flags |= DSS_HIDEPREFIX; + wp = dtFlags; break; case BS_ICON: @@ -857,7 +799,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action ) HFONT hFont; LONG state = get_button_state( hwnd ); LONG style = GetWindowLongPtrW( hwnd, GWL_STYLE ); - BOOL pushedState = (state & BUTTON_HIGHLIGHTED); + BOOL pushedState = (state & BST_PUSHED); HWND parent; GetClientRect( hwnd, &rc ); @@ -900,7 +842,7 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action ) uState |= DFCS_PUSHED; } - if (state & (BUTTON_CHECKED | BUTTON_3STATE)) + if (state & (BST_CHECKED | BST_INDETERMINATE)) uState |= DFCS_CHECKED; DrawFrameControl( hDC, &rc, DFC_BUTTON, uState ); @@ -922,14 +864,10 @@ static void PB_Paint( HWND hwnd, HDC hDC, UINT action ) SetTextColor( hDC, oldTxtColor ); draw_focus: - if ((action == ODA_FOCUS) || - ((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS))) + if (action == ODA_FOCUS || (state & BST_FOCUS)) { - if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS)) - { - InflateRect( &rc, -2, -2 ); - DrawFocusRect( hDC, &rc ); - } + InflateRect( &rc, -2, -2 ); + DrawFocusRect( hDC, &rc ); } cleanup: @@ -1008,11 +946,11 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action ) if ((get_button_type(style) == BS_RADIOBUTTON) || (get_button_type(style) == BS_AUTORADIOBUTTON)) flags = DFCS_BUTTONRADIO; - else if (state & BUTTON_3STATE) flags = DFCS_BUTTON3STATE; + else if (state & BST_INDETERMINATE) flags = DFCS_BUTTON3STATE; else flags = DFCS_BUTTONCHECK; - if (state & (BUTTON_CHECKED | BUTTON_3STATE)) flags |= DFCS_CHECKED; - if (state & BUTTON_HIGHLIGHTED) flags |= DFCS_PUSHED; + if (state & (BST_CHECKED | BST_INDETERMINATE)) flags |= DFCS_CHECKED; + if (state & BST_PUSHED) flags |= DFCS_PUSHED; if (style & WS_DISABLED) flags |= DFCS_INACTIVE; @@ -1055,16 +993,12 @@ static void CB_Paint( HWND hwnd, HDC hDC, UINT action ) BUTTON_DrawLabel(hwnd, hDC, dtFlags, &rtext); /* ... and focus */ - if ((action == ODA_FOCUS) || - ((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS))) + if (action == ODA_FOCUS || (state & BST_FOCUS)) { - if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS)) - { - rtext.left--; - rtext.right++; - IntersectRect(&rtext, &rtext, &client); - DrawFocusRect( hDC, &rtext ); - } + rtext.left--; + rtext.right++; + IntersectRect(&rtext, &rtext, &client); + DrawFocusRect( hDC, &rtext ); } } @@ -1085,8 +1019,8 @@ static void BUTTON_CheckAutoRadioButton( HWND hwnd ) { if (!sibling) break; if ((hwnd != sibling) && - ((GetWindowLongPtrW( sibling, GWL_STYLE) & 0x0f) == BS_AUTORADIOBUTTON)) - SendMessageW( sibling, BM_SETCHECK, BUTTON_UNCHECKED, 0 ); + ((GetWindowLongPtrW( sibling, GWL_STYLE) & BS_TYPEMASK) == BS_AUTORADIOBUTTON)) + SendMessageW( sibling, BM_SETCHECK, BST_UNCHECKED, 0 ); sibling = GetNextDlgGroupItem( parent, sibling, FALSE ); } while (sibling != start); } @@ -1155,8 +1089,6 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action ) LONG state = get_button_state( hwnd ); HWND parent; - if (action == ODA_SELECT) return; - GetClientRect( hwnd, &rc); if ((hFont = get_button_font( hwnd ))) SelectObject( hDC, hFont ); @@ -1169,14 +1101,23 @@ static void UB_Paint( HWND hwnd, HDC hDC, UINT action ) (WPARAM)hDC, (LPARAM)hwnd); FillRect( hDC, &rc, hBrush ); - if ((action == ODA_FOCUS) || - ((action == ODA_DRAWENTIRE) && (state & BUTTON_HASFOCUS))) - { - if (!(get_ui_state(hwnd) & UISF_HIDEFOCUS)) - DrawFocusRect( hDC, &rc ); - } + if (action == ODA_FOCUS || (state & BST_FOCUS)) + DrawFocusRect( hDC, &rc ); - BUTTON_NOTIFY_PARENT( hwnd, BN_PAINT ); + switch (action) + { + case ODA_FOCUS: + BUTTON_NOTIFY_PARENT( hwnd, (state & BST_FOCUS) ? BN_SETFOCUS : BN_KILLFOCUS ); + break; + + case ODA_SELECT: + BUTTON_NOTIFY_PARENT( hwnd, (state & BST_PUSHED) ? BN_HILITE : BN_UNHILITE ); + break; + + default: + BUTTON_NOTIFY_PARENT( hwnd, BN_PAINT ); + break; + } } @@ -1196,8 +1137,8 @@ static void OB_Paint( HWND hwnd, HDC hDC, UINT action ) dis.CtlID = id; dis.itemID = 0; dis.itemAction = action; - dis.itemState = ((state & BUTTON_HASFOCUS) ? ODS_FOCUS : 0) | - ((state & BUTTON_HIGHLIGHTED) ? ODS_SELECTED : 0) | + dis.itemState = ((state & BST_FOCUS) ? ODS_FOCUS : 0) | + ((state & BST_PUSHED) ? ODS_SELECTED : 0) | (IsWindowEnabled(hwnd) ? 0: ODS_DISABLED); dis.hwndItem = hwnd; dis.hDC = hDC;