📄 button.c
字号:
hbrush = (HBRUSH)SendMessageW(parent, WM_CTLCOLORSTATIC,
(WPARAM)hdc, (LPARAM)hWnd);
if (!hbrush) /* did the app forget to call DefWindowProc ? */
hbrush = (HBRUSH)DefWindowProcW(parent, WM_CTLCOLORSTATIC,
(WPARAM)hdc, (LPARAM)hWnd);
GetClientRect(hWnd, &client);
rc = client;
BUTTON_CalcLabelRect(hWnd, hdc, &rc);
/* Clip by client rect bounds */
if (rc.right > client.right) rc.right = client.right;
if (rc.bottom > client.bottom) rc.bottom = client.bottom;
FillRect(hdc, &rc, hbrush);
ReleaseDC(hWnd, hdc);
if (unicode) DefWindowProcW( hWnd, WM_SETTEXT, wParam, lParam );
else DefWindowProcA( hWnd, WM_SETTEXT, wParam, lParam );
if (btn_type == BS_GROUPBOX) /* Yes, only for BS_GROUPBOX */
InvalidateRect( hWnd, NULL, TRUE );
else
paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
return 1; /* success. FIXME: check text length */
}
case WM_SETFONT:
set_button_font( hWnd, (HFONT)wParam );
if (lParam) paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
break;
case WM_GETFONT:
return (LRESULT)get_button_font( hWnd );
case WM_SETFOCUS:
TRACE("WM_SETFOCUS %p\n",hWnd);
set_button_state( hWnd, get_button_state(hWnd) | BUTTON_HASFOCUS );
paint_button( hWnd, btn_type, ODA_FOCUS );
if (style & BS_NOTIFY)
BUTTON_NOTIFY_PARENT(hWnd, BN_SETFOCUS);
break;
case WM_KILLFOCUS:
TRACE("WM_KILLFOCUS %p\n",hWnd);
state = get_button_state( hWnd );
set_button_state( hWnd, state & ~BUTTON_HASFOCUS );
paint_button( hWnd, btn_type, ODA_FOCUS );
if ((state & BUTTON_BTNPRESSED) && GetCapture() == hWnd)
ReleaseCapture();
if (style & BS_NOTIFY)
BUTTON_NOTIFY_PARENT(hWnd, BN_KILLFOCUS);
break;
case WM_SYSCOLORCHANGE:
InvalidateRect( hWnd, NULL, FALSE );
break;
#ifndef __REACTOS__
case BM_SETSTYLE16:
#endif
case BM_SETSTYLE:
if ((wParam & 0x0f) >= MAX_BTN_TYPE) break;
btn_type = wParam & 0x0f;
style = (style & ~0x0f) | btn_type;
SetWindowLongW( hWnd, GWL_STYLE, style );
/* Only redraw if lParam flag is set.*/
if (lParam)
paint_button( hWnd, btn_type, ODA_DRAWENTIRE );
break;
case BM_CLICK:
SendMessageW( hWnd, WM_LBUTTONDOWN, 0, 0 );
SendMessageW( hWnd, WM_LBUTTONUP, 0, 0 );
break;
case BM_SETIMAGE:
/* Check that image format matches button style */
switch (style & (BS_BITMAP|BS_ICON))
{
case BS_BITMAP:
if (wParam != IMAGE_BITMAP) return 0;
break;
case BS_ICON:
if (wParam != IMAGE_ICON) return 0;
break;
default:
return 0;
}
oldHbitmap = (HBITMAP)SetWindowLongPtrW( hWnd, HIMAGE_GWL_OFFSET, lParam );
InvalidateRect( hWnd, NULL, FALSE );
return (LRESULT)oldHbitmap;
case BM_GETIMAGE:
return GetWindowLongPtrW( hWnd, HIMAGE_GWL_OFFSET );
#ifndef __REACTOS__
case BM_GETCHECK16:
#endif
case BM_GETCHECK:
return get_button_state( hWnd ) & 3;
#ifndef __REACTOS__
case BM_SETCHECK16:
#endif
case BM_SETCHECK:
if (wParam > maxCheckState[btn_type]) wParam = maxCheckState[btn_type];
state = get_button_state( hWnd );
if ((btn_type == BS_RADIOBUTTON) || (btn_type == BS_AUTORADIOBUTTON))
{
if (wParam) style |= WS_TABSTOP;
else style &= ~WS_TABSTOP;
SetWindowLongW( hWnd, GWL_STYLE, style );
}
if ((state & 3) != wParam)
{
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))
BUTTON_CheckAutoRadioButton( hWnd );
break;
#ifndef __REACTOS__
case BM_GETSTATE16:
#endif
case BM_GETSTATE:
return get_button_state( hWnd );
#ifndef __REACTOS__
case BM_SETSTATE16:
#endif
case BM_SETSTATE:
state = get_button_state( hWnd );
if (wParam)
{
if (state & BUTTON_HIGHLIGHTED) break;
set_button_state( hWnd, state | BUTTON_HIGHLIGHTED );
}
else
{
if (!(state & BUTTON_HIGHLIGHTED)) break;
set_button_state( hWnd, state & ~BUTTON_HIGHLIGHTED );
}
paint_button( hWnd, btn_type, ODA_SELECT );
break;
case WM_NCHITTEST:
if(btn_type == BS_GROUPBOX) return HTTRANSPARENT;
/* fall through */
default:
return unicode ? DefWindowProcW(hWnd, uMsg, wParam, lParam) :
DefWindowProcA(hWnd, uMsg, wParam, lParam);
}
return 0;
}
/***********************************************************************
* ButtonWndProcW
* The button window procedure. This is just a wrapper which locks
* the passed HWND and calls the real window procedure (with a WND*
* pointer pointing to the locked windowstructure).
*/
static LRESULT WINAPI ButtonWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if (!IsWindow( hWnd )) return 0;
return ButtonWndProc_common( hWnd, uMsg, wParam, lParam, TRUE );
}
/***********************************************************************
* ButtonWndProcA
*/
static LRESULT WINAPI ButtonWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
if (!IsWindow( hWnd )) return 0;
return ButtonWndProc_common( hWnd, uMsg, wParam, lParam, FALSE );
}
/**********************************************************************
* Convert button styles to flags used by DrawText.
* TODO: handle WS_EX_RIGHT extended style.
*/
static UINT BUTTON_BStoDT(DWORD style)
{
UINT dtStyle = DT_NOCLIP; /* We use SelectClipRgn to limit output */
/* "Convert" pushlike buttons to pushbuttons */
if (style & BS_PUSHLIKE)
style &= ~0x0F;
if (!(style & BS_MULTILINE))
dtStyle |= DT_SINGLELINE;
else
dtStyle |= DT_WORDBREAK;
switch (style & BS_CENTER)
{
case BS_LEFT: /* DT_LEFT is 0 */ break;
case BS_RIGHT: dtStyle |= DT_RIGHT; break;
case BS_CENTER: dtStyle |= DT_CENTER; break;
default:
/* Pushbutton's text is centered by default */
if (get_button_type(style) <= BS_DEFPUSHBUTTON) dtStyle |= DT_CENTER;
/* all other flavours have left aligned text */
}
/* DrawText ignores vertical alignment for multiline text,
* but we use these flags to align label manualy.
*/
if (get_button_type(style) != BS_GROUPBOX)
{
switch (style & BS_VCENTER)
{
case BS_TOP: /* DT_TOP is 0 */ break;
case BS_BOTTOM: dtStyle |= DT_BOTTOM; break;
case BS_VCENTER: /* fall through */
default: dtStyle |= DT_VCENTER; break;
}
}
else
/* GroupBox's text is always single line and is top aligned. */
dtStyle |= DT_SINGLELINE;
return dtStyle;
}
/**********************************************************************
* BUTTON_CalcLabelRect
*
* Calculates label's rectangle depending on button style.
*
* Returns flags to be passed to DrawText.
* Calculated rectangle doesn't take into account button state
* (pushed, etc.). If there is nothing to draw (no text/image) output
* rectangle is empty, and return value is (UINT)-1.
*/
static UINT BUTTON_CalcLabelRect(HWND hwnd, HDC hdc, RECT *rc)
{
LONG style = GetWindowLongW( hwnd, GWL_STYLE );
WCHAR *text;
ICONINFO iconInfo;
BITMAP bm;
UINT dtStyle = BUTTON_BStoDT(style);
RECT r = *rc;
INT n;
/* Calculate label rectangle according to label type */
switch (style & (BS_ICON|BS_BITMAP))
{
case BS_TEXT:
if (!(text = get_button_text( hwnd ))) goto empty_rect;
if (!text[0])
{
HeapFree( GetProcessHeap(), 0, text );
goto empty_rect;
}
DrawTextW(hdc, text, -1, &r, dtStyle | DT_CALCRECT);
HeapFree( GetProcessHeap(), 0, text );
break;
case BS_ICON:
if (!GetIconInfo((HICON)GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET ), &iconInfo))
goto empty_rect;
GetObjectW (iconInfo.hbmColor, sizeof(BITMAP), &bm);
r.right = r.left + bm.bmWidth;
r.bottom = r.top + bm.bmHeight;
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
break;
case BS_BITMAP:
if (!GetObjectW( (HANDLE)GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET ), sizeof(BITMAP), &bm))
goto empty_rect;
r.right = r.left + bm.bmWidth;
r.bottom = r.top + bm.bmHeight;
break;
default:
empty_rect:
rc->right = r.left;
rc->bottom = r.top;
return (UINT)(LONG)-1;
}
/* Position label inside bounding rectangle according to
* alignment flags. (calculated rect is always left-top aligned).
* If label is aligned to any side - shift label in opposite
* direction to leave extra space for focus rectangle.
*/
switch (dtStyle & (DT_CENTER|DT_RIGHT))
{
case DT_LEFT: r.left++; r.right++; break;
case DT_CENTER: n = r.right - r.left;
r.left = rc->left + ((rc->right - rc->left) - n) / 2;
r.right = r.left + n; break;
case DT_RIGHT: n = r.right - r.left;
r.right = rc->right - 1;
r.left = r.right - n;
break;
}
switch (dtStyle & (DT_VCENTER|DT_BOTTOM))
{
case DT_TOP: r.top++; r.bottom++; break;
case DT_VCENTER: n = r.bottom - r.top;
r.top = rc->top + ((rc->bottom - rc->top) - n) / 2;
r.bottom = r.top + n; break;
case DT_BOTTOM: n = r.bottom - r.top;
r.bottom = rc->bottom - 1;
r.top = r.bottom - n;
break;
}
*rc = r;
return dtStyle;
}
/**********************************************************************
* BUTTON_DrawTextCallback
*
* Callback function used by DrawStateW function.
*/
static BOOL CALLBACK BUTTON_DrawTextCallback(HDC hdc, LPARAM lp, WPARAM wp, int cx, int cy)
{
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = cx;
rc.bottom = cy;
DrawTextW(hdc, (LPCWSTR)lp, -1, &rc, (UINT)wp);
return TRUE;
}
/**********************************************************************
* BUTTON_DrawLabel
*
* Common function for drawing button label.
*/
static void BUTTON_DrawLabel(HWND hwnd, HDC hdc, UINT dtFlags, RECT *rc)
{
DRAWSTATEPROC lpOutputProc = NULL;
LPARAM lp;
WPARAM wp = 0;
HBRUSH hbr = 0;
UINT flags = IsWindowEnabled(hwnd) ? DSS_NORMAL : DSS_DISABLED;
LONG state = get_button_state( hwnd );
LONG style = GetWindowLongW( hwnd, GWL_STYLE );
WCHAR *text = NULL;
/* FIXME: To draw disabled label in Win31 look-and-feel, we probably
* must use DSS_MONO flag and COLOR_GRAYTEXT brush (or maybe DSS_UNION).
* I don't have Win31 on hand to verify that, so I leave it as is.
*/
if ((style & BS_PUSHLIKE) && (state & BUTTON_3STATE))
{
hbr = GetSysColorBrush(COLOR_GRAYTEXT);
flags |= DSS_MONO;
}
switch (style & (BS_ICON|BS_BITMAP))
{
case BS_TEXT:
/* DST_COMPLEX -- is 0 */
lpOutputProc = BUTTON_DrawTextCallback;
if (!(text = get_button_text( hwnd ))) return;
lp = (LPARAM)text;
wp = (WPARAM)dtFlags;
break;
case BS_ICON:
flags |= DST_ICON;
lp = GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -