comctl32/button: Implement command links.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Gabriel Ivăncescu 2019-04-19 15:14:00 +03:00 committed by Alexandre Julliard
parent 4fa7aa29b5
commit 9fee8a7d25
4 changed files with 195 additions and 2 deletions

View File

@ -105,6 +105,7 @@ static void GB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
static void UB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
static void OB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
static void SB_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
static void CL_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action );
static void BUTTON_CheckAutoRadioButton( HWND hwnd );
static void get_split_button_rects(const BUTTON_INFO*, const RECT*, RECT*, RECT*);
static BOOL notify_split_button_dropdown(const BUTTON_INFO*, const POINT*, HWND);
@ -161,8 +162,8 @@ static const pfPaint btnPaintFunc[MAX_BTN_TYPE] =
OB_Paint, /* BS_OWNERDRAW */
SB_Paint, /* BS_SPLITBUTTON */
SB_Paint, /* BS_DEFSPLITBUTTON */
PB_Paint, /* BS_COMMANDLINK */
PB_Paint /* BS_DEFCOMMANDLINK */
CL_Paint, /* BS_COMMANDLINK */
CL_Paint /* BS_DEFCOMMANDLINK */
};
typedef void (*pfThemedPaint)( HTHEME theme, const BUTTON_INFO *infoPtr, HDC hdc, int drawState, UINT dtflags, BOOL focused);
@ -219,6 +220,12 @@ static const pfGetIdealSize btnGetIdealSizeFunc[MAX_BTN_TYPE] = {
PB_GetIdealSize /* BS_DEFCOMMANDLINK */
};
/* Fixed margin for command links, regardless of DPI (based on tests done on Windows) */
enum { command_link_margin = 6 };
/* The width and height for the default command link glyph (when there's no image) */
enum { command_link_defglyph_size = 17 };
static inline UINT get_button_type( LONG window_style )
{
return (window_style & BS_TYPEMASK);
@ -2297,6 +2304,186 @@ static void draw_split_button_dropdown_glyph(const BUTTON_INFO *infoPtr, HDC hdc
}
/**********************************************************************
* Command Link Functions
*/
static void CL_Paint( const BUTTON_INFO *infoPtr, HDC hDC, UINT action )
{
LONG style = GetWindowLongW(infoPtr->hwnd, GWL_STYLE);
LONG state = infoPtr->state;
RECT rc, content_rect;
NMCUSTOMDRAW nmcd;
HPEN pen, old_pen;
HBRUSH old_brush;
INT old_bk_mode;
LRESULT cdrf;
HWND parent;
HRGN hrgn;
GetClientRect(infoPtr->hwnd, &rc);
/* Command Links are not affected by the button's font, and are based
on the default message font. Furthermore, they are not affected by
any of the alignment styles (and always align with the top-left). */
if (!(parent = GetParent(infoPtr->hwnd))) parent = infoPtr->hwnd;
SendMessageW(parent, WM_CTLCOLORBTN, (WPARAM)hDC, (LPARAM)infoPtr->hwnd);
hrgn = set_control_clipping(hDC, &rc);
pen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
old_pen = SelectObject(hDC, pen);
old_brush = SelectObject(hDC, GetSysColorBrush(COLOR_BTNFACE));
old_bk_mode = SetBkMode(hDC, TRANSPARENT);
init_custom_draw(&nmcd, infoPtr, hDC, &rc);
/* Send erase notifications */
cdrf = SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
if (cdrf & CDRF_SKIPDEFAULT) goto cleanup;
content_rect = rc;
if (get_button_type(style) == BS_DEFCOMMANDLINK)
{
if (action != ODA_FOCUS)
Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
InflateRect(&rc, -1, -1);
}
/* Skip the frame drawing if only focus has changed */
if (action != ODA_FOCUS)
{
if (!(state & (BST_HOT | BST_PUSHED | BST_CHECKED | BST_INDETERMINATE)))
FillRect(hDC, &rc, GetSysColorBrush(COLOR_BTNFACE));
else
{
UINT flags = DFCS_BUTTONPUSH;
if (style & BS_FLAT) flags |= DFCS_MONO;
else if (state & BST_PUSHED) flags |= DFCS_PUSHED;
if (state & (BST_CHECKED | BST_INDETERMINATE))
flags |= DFCS_CHECKED;
DrawFrameControl(hDC, &rc, DFC_BUTTON, flags);
}
}
if (cdrf & CDRF_NOTIFYPOSTERASE)
{
nmcd.dwDrawStage = CDDS_POSTERASE;
SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
}
/* Send paint notifications */
nmcd.dwDrawStage = CDDS_PREPAINT;
cdrf = SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
if (cdrf & CDRF_SKIPDEFAULT) goto cleanup;
if (!(cdrf & CDRF_DOERASE) && action != ODA_FOCUS)
{
UINT flags = IsWindowEnabled(infoPtr->hwnd) ? DSS_NORMAL : DSS_DISABLED;
COLORREF old_color = SetTextColor(hDC, GetSysColor(flags == DSS_NORMAL ?
COLOR_BTNTEXT : COLOR_GRAYTEXT));
HIMAGELIST defimg = NULL;
NONCLIENTMETRICSW ncm;
UINT txt_h = 0;
SIZE img_size;
/* Command Links ignore the margins of the image list or its alignment */
if (infoPtr->u.image || infoPtr->imagelist.himl)
img_size = BUTTON_GetImageSize(infoPtr);
else
{
img_size.cx = img_size.cy = command_link_defglyph_size;
defimg = ImageList_LoadImageW(COMCTL32_hModule, (LPCWSTR)MAKEINTRESOURCE(IDB_CMDLINK),
img_size.cx, 3, CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION);
}
/* Shrink rect by the command link margin, except on bottom (just the frame) */
InflateRect(&content_rect, -command_link_margin, -command_link_margin);
content_rect.bottom += command_link_margin - 2;
ncm.cbSize = sizeof(ncm);
if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
{
LONG note_weight = ncm.lfMessageFont.lfWeight;
RECT r = content_rect;
WCHAR *text;
HFONT font;
if (img_size.cx) r.left += img_size.cx + command_link_margin;
/* Draw the text */
ncm.lfMessageFont.lfWeight = FW_BOLD;
if ((font = CreateFontIndirectW(&ncm.lfMessageFont)))
{
if ((text = get_button_text(infoPtr)))
{
SelectObject(hDC, font);
txt_h = DrawTextW(hDC, text, -1, &r,
DT_TOP | DT_LEFT | DT_WORDBREAK | DT_END_ELLIPSIS);
heap_free(text);
}
DeleteObject(font);
}
/* Draw the note */
ncm.lfMessageFont.lfWeight = note_weight;
if (infoPtr->note && (font = CreateFontIndirectW(&ncm.lfMessageFont)))
{
r.top += txt_h + 2;
SelectObject(hDC, font);
DrawTextW(hDC, infoPtr->note, infoPtr->note_length, &r,
DT_TOP | DT_LEFT | DT_WORDBREAK | DT_NOPREFIX);
DeleteObject(font);
}
}
/* Position the image at the vertical center of the drawn text (not note) */
txt_h = min(txt_h, content_rect.bottom - content_rect.top);
if (img_size.cy < txt_h) content_rect.top += (txt_h - img_size.cy) / 2;
content_rect.right = content_rect.left + img_size.cx;
content_rect.bottom = content_rect.top + img_size.cy;
if (defimg)
{
int i = 0;
if (flags == DSS_DISABLED) i = 2;
else if (state & BST_HOT) i = 1;
ImageList_Draw(defimg, i, hDC, content_rect.left, content_rect.top, ILD_NORMAL);
ImageList_Destroy(defimg);
}
else
BUTTON_DrawImage(infoPtr, hDC, NULL, flags, &content_rect);
SetTextColor(hDC, old_color);
}
if (cdrf & CDRF_NOTIFYPOSTPAINT)
{
nmcd.dwDrawStage = CDDS_POSTPAINT;
SendMessageW(parent, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
}
if (cdrf & CDRF_SKIPPOSTPAINT) goto cleanup;
if (action == ODA_FOCUS || (state & BST_FOCUS))
{
InflateRect(&rc, -2, -2);
DrawFocusRect(hDC, &rc);
}
cleanup:
SelectObject(hDC, old_pen);
SelectObject(hDC, old_brush);
SetBkMode(hDC, old_bk_mode);
SelectClipRgn(hDC, hrgn);
if (hrgn) DeleteObject(hrgn);
DeleteObject(pen);
}
/**********************************************************************
* Themed Paint Functions
*/

View File

@ -80,6 +80,9 @@ extern HBRUSH COMCTL32_hPattern55AABrush DECLSPEC_HIDDEN;
#define IDT_CHECK 401
/* Command Link arrow */
#define IDB_CMDLINK 402
/* Cursors */
#define IDC_MOVEBUTTON 102

View File

@ -144,6 +144,9 @@ IDB_HIST_SMALL BITMAP idb_hist_small.bmp
/* @makedep: idb_hist_large.bmp */
IDB_HIST_LARGE BITMAP idb_hist_large.bmp
/* @makedep: idb_cmdlink.bmp */
IDB_CMDLINK BITMAP idb_cmdlink.bmp
/* @makedep: idc_copy.cur */
IDC_COPY CURSOR idc_copy.cur

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB