=?UTF-8?Q?Gabriel=20Iv=C4=83ncescu=20?=: comctl32/button: Implement command links.
Alexandre Julliard
julliard at winehq.org
Mon Apr 22 16:30:39 CDT 2019
Module: wine
Branch: master
Commit: 9fee8a7d258c1776d7358e6498afb3adc3d36812
URL: https://source.winehq.org/git/wine.git/?a=commit;h=9fee8a7d258c1776d7358e6498afb3adc3d36812
Author: Gabriel Ivăncescu <gabrielopcode at gmail.com>
Date: Fri Apr 19 15:14:00 2019 +0300
comctl32/button: Implement command links.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/comctl32/button.c | 191 +++++++++++++++++++++++++++++++++++++++++-
dlls/comctl32/comctl32.h | 3 +
dlls/comctl32/comctl32.rc | 3 +
dlls/comctl32/idb_cmdlink.bmp | Bin 0 -> 3522 bytes
4 files changed, 195 insertions(+), 2 deletions(-)
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c
index baa58d8..4f2fbce 100644
--- a/dlls/comctl32/button.c
+++ b/dlls/comctl32/button.c
@@ -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);
@@ -2298,6 +2305,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
*/
static void PB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, int state, UINT dtFlags, BOOL focused)
diff --git a/dlls/comctl32/comctl32.h b/dlls/comctl32/comctl32.h
index b68b914..f3e889c 100644
--- a/dlls/comctl32/comctl32.h
+++ b/dlls/comctl32/comctl32.h
@@ -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
diff --git a/dlls/comctl32/comctl32.rc b/dlls/comctl32/comctl32.rc
index 3f8e148..c9aa1ba 100644
--- a/dlls/comctl32/comctl32.rc
+++ b/dlls/comctl32/comctl32.rc
@@ -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
diff --git a/dlls/comctl32/idb_cmdlink.bmp b/dlls/comctl32/idb_cmdlink.bmp
new file mode 100644
index 0000000..4b3f07b
Binary files /dev/null and b/dlls/comctl32/idb_cmdlink.bmp differ
More information about the wine-cvs
mailing list