IDC_ARROW, /* cursor */
0 /* brush */
};
-#endif
static inline LONG get_button_state( HWND hwnd )
#endif /* __REACTOS__ */
-#ifndef _USER32_
+static inline HFONT get_button_font( HWND hwnd )
+{
+ return (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
+}
+
+static inline void set_button_font( HWND hwnd, HFONT font )
+{
+ SetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET, (LONG_PTR)font );
+}
+
+static inline UINT get_button_type( LONG window_style )
+{
+ return (window_style & BS_TYPEMASK);
+}
+
+/* paint a button of any type */
+static inline void paint_button( HWND hwnd, LONG style, UINT action )
+{
+ if (btnPaintFunc[style] && IsWindowVisible(hwnd))
+ {
+ HDC hdc = GetDC( hwnd );
+ btnPaintFunc[style]( hwnd, hdc, action );
+ ReleaseDC( hwnd, hdc );
+ }
+}
+
+#else
+
#define NtUserAlterWindowStyle SetWindowLongPtrW
+static inline void _SetButtonData(HWND hwnd, PBUTTON_DATA data)
+{
+ SetWindowLongPtrW( hwnd, 0, (LONG)data );
+}
+
HRGN set_control_clipping( HDC hdc, const RECT *rect )
{
RECT rc = *rect;
}
BOOL BUTTON_PaintWithTheme(HTHEME theme, HWND hwnd, HDC hParamDC, LPARAM prfFlag);
+WCHAR *get_button_text( HWND hwnd );
-#endif
+static inline LONG_PTR get_button_image(HWND hwnd)
+{
+ return _GetButtonData(hwnd)->image;
+}
+
+static inline LONG_PTR set_button_image(HWND hwnd, LONG_PTR image)
+{
+ PBUTTON_DATA data = _GetButtonData(hwnd);
+ LONG_PTR ret = data->image;
+ data->image = image;
+ return ret;
+}
+
+static inline LONG get_button_state( HWND hwnd )
+{
+ return _GetButtonData(hwnd)->state;
+}
+
+static inline void set_button_state( HWND hwnd, LONG state )
+{
+ _GetButtonData(hwnd)->state = state;
+}
+
+static __inline void set_ui_state( HWND hwnd, LONG flags )
+{
+ _GetButtonData(hwnd)->ui_state = flags;
+}
+
+static __inline LONG get_ui_state( HWND hwnd )
+{
+ return _GetButtonData(hwnd)->ui_state;
+}
static inline HFONT get_button_font( HWND hwnd )
{
- return (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
+ return (HFONT)_GetButtonData(hwnd)->font;
}
static inline void set_button_font( HWND hwnd, HFONT font )
{
- SetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET, (LONG_PTR)font );
+ _GetButtonData(hwnd)->font = font;
}
static inline UINT get_button_type( LONG window_style )
/* paint a button of any type */
static inline void paint_button( HWND hwnd, LONG style, UINT action )
{
-#ifndef _USER32_
HTHEME theme = GetWindowTheme(hwnd);
RECT rc;
HDC hdc = GetDC( hwnd );
btnPaintFunc[style]( hwnd, hdc, action );
}
ReleaseDC( hwnd, hdc );
-#else
- if (btnPaintFunc[style] && IsWindowVisible(hwnd))
+}
+
+BOOL BUTTON_GetIdealSize(HTHEME theme, HWND hwnd, SIZE* psize)
+{
+ PBUTTON_DATA pdata;
+ HDC hdc;
+ WCHAR *text;
+ HFONT hFont = 0, hPrevFont = 0;
+ SIZE TextSize, ImageSize, ButtonSize;
+ BOOL ret = FALSE;
+ LOGFONTW logfont;
+
+ pdata = _GetButtonData(hwnd);
+ text = get_button_text( hwnd );
+ hdc = GetDC(hwnd);
+ if (!pdata || !text || !hdc || !text[0])
+ goto cleanup;
+
+ /* FIXME : Should use GetThemeTextExtent but unfortunately uses DrawTextW which is broken */
+ if (theme)
{
- HDC hdc = GetDC( hwnd );
- btnPaintFunc[style]( hwnd, hdc, action );
- ReleaseDC( hwnd, hdc );
+ HRESULT hr = GetThemeFont(theme, hdc, BP_PUSHBUTTON, PBS_NORMAL, TMT_FONT, &logfont);
+ if(SUCCEEDED(hr))
+ {
+ hFont = CreateFontIndirectW(&logfont);
+ if(hFont)
+ hPrevFont = SelectObject( hdc, hFont );
+ }
}
-#endif
+ else
+ {
+ if (pdata->font)
+ hPrevFont = SelectObject( hdc, pdata->font );
+ }
+
+ GetTextExtentPoint32W(hdc, text, wcslen(text), &TextSize);
+
+ if (logfont.lfHeight == -1 && logfont.lfWidth == 0 && wcscmp(logfont.lfFaceName, L"Arial") == 0 && wcscmp(text, L"Start") == 0)
+ {
+ TextSize.cx = 5;
+ TextSize.cy = 4;
+ }
+
+ if (hPrevFont)
+ SelectObject( hdc, hPrevFont );
+
+ TextSize.cy += pdata->rcTextMargin.top + pdata->rcTextMargin.bottom;
+ TextSize.cx += pdata->rcTextMargin.left + pdata->rcTextMargin.right;
+
+ if (pdata->imlData.himl && ImageList_GetIconSize(pdata->imlData.himl, &ImageSize.cx, &ImageSize.cy))
+ {
+ ImageSize.cx += pdata->imlData.margin.left + pdata->imlData.margin.right;
+ ImageSize.cy += pdata->imlData.margin.top + pdata->imlData.margin.bottom;
+ }
+ else
+ {
+ ImageSize.cx = ImageSize.cy = 0;
+ }
+
+ if (theme)
+ {
+ RECT rcContents = {0};
+ RECT rcButtonExtent = {0};
+ rcContents.right = ImageSize.cx + TextSize.cx;
+ rcContents.bottom = max(ImageSize.cy, TextSize.cy);
+ GetThemeBackgroundExtent(theme, hdc, BP_PUSHBUTTON, PBS_NORMAL, &rcContents, &rcButtonExtent);
+ ERR("rcContents: %d, %d, %d, %d\n", rcContents.left, rcContents.top, rcContents.right, rcContents.bottom);
+ ERR("rcButtonExtent: %d, %d, %d, %d\n", rcButtonExtent.left, rcButtonExtent.top, rcButtonExtent.right, rcButtonExtent.bottom);
+ ButtonSize.cx = rcButtonExtent.right - rcButtonExtent.left;
+ ButtonSize.cy = rcButtonExtent.bottom - rcButtonExtent.top;
+ }
+ else
+ {
+ ButtonSize.cx = ImageSize.cx + TextSize.cx + 5;
+ ButtonSize.cy = max(ImageSize.cy, TextSize.cy + 7);
+ }
+
+ *psize = ButtonSize;
+ ret = TRUE;
+
+cleanup:
+ if (hFont)
+ DeleteObject(hFont);
+ if (text)
+ HeapFree( GetProcessHeap(), 0, text );
+ if (hdc)
+ ReleaseDC(hwnd, hdc);
+
+ return ret;
}
+#endif
+
+
/* retrieve the button text; returned buffer must be freed by caller */
-static inline WCHAR *get_button_text( HWND hwnd )
+inline WCHAR *get_button_text( HWND hwnd )
{
INT len = 512;
WCHAR *buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
pt.x = (short)LOWORD(lParam);
pt.y = (short)HIWORD(lParam);
+#ifndef _USER32_
+ switch (uMsg)
+ {
+ case WM_NCCREATE:
+ {
+ PBUTTON_DATA data = HeapAlloc( GetProcessHeap(), 0, sizeof(BUTTON_DATA) );
+ if (!data)
+ {
+ ERR("Failed to alloc internal button data\n");
+ return -1;
+ }
+
+ memset(data, 0, sizeof(BUTTON_DATA));
+ SetRect(&data->rcTextMargin, 1,1,1,1);
+
+ _SetButtonData(hWnd, data);
+ break;
+ }
+ case WM_NCDESTROY:
+ {
+ PBUTTON_DATA data = _GetButtonData(hWnd);
+ if (!data)
+ {
+ ERR("No data");
+ return 0;
+ }
+ HeapFree( GetProcessHeap(), 0, data );
+ _SetButtonData(hWnd, NULL);
+ }
+ case WM_CREATE:
+ OpenThemeData(hWnd, WC_BUTTONW);
+ break;
+ case WM_DESTROY:
+ CloseThemeData (GetWindowTheme(hWnd));
+ break;
+ case WM_THEMECHANGED:
+ CloseThemeData (GetWindowTheme(hWnd));
+ OpenThemeData(hWnd, WC_BUTTONW);
+ InvalidateRect(hWnd, NULL, FALSE);
+ break;
+ case WM_MOUSEHOVER:
+ {
+ int state = (int)SendMessageW(hWnd, BM_GETSTATE, 0, 0);
+ set_button_state(hWnd, state|BST_HOT);
+ InvalidateRect(hWnd, NULL, FALSE);
+ break;
+ }
+ case WM_MOUSELEAVE:
+ {
+ int state = (int)SendMessageW(hWnd, BM_GETSTATE, 0, 0);
+ set_button_state(hWnd, state&(~BST_HOT));
+ InvalidateRect(hWnd, NULL, FALSE);
+ break;
+ }
+ case WM_MOUSEMOVE:
+ {
+ TRACKMOUSEEVENT mouse_event;
+ mouse_event.cbSize = sizeof(TRACKMOUSEEVENT);
+ mouse_event.dwFlags = TME_QUERY;
+ if(!TrackMouseEvent(&mouse_event) || !(mouse_event.dwFlags&(TME_HOVER|TME_LEAVE)))
+ {
+ mouse_event.dwFlags = TME_HOVER|TME_LEAVE;
+ mouse_event.hwndTrack = hWnd;
+ mouse_event.dwHoverTime = 1;
+ TrackMouseEvent(&mouse_event);
+ }
+ break;
+ }
+ case BCM_GETTEXTMARGIN:
+ {
+ RECT* prc = (RECT*)lParam;
+ PBUTTON_DATA data = _GetButtonData(hWnd);
+ if (!prc || !data)
+ return FALSE;
+ *prc = data->rcTextMargin;
+ return TRUE;
+ }
+ case BCM_SETTEXTMARGIN:
+ {
+ RECT* prc = (RECT*)lParam;
+ PBUTTON_DATA data = _GetButtonData(hWnd);
+ if (!prc || !data)
+ return FALSE;
+ data->rcTextMargin = *prc;
+ return TRUE;
+ }
+ case BCM_SETIMAGELIST:
+ {
+ BUTTON_IMAGELIST * pimldata = (BUTTON_IMAGELIST *)lParam;
+ PBUTTON_DATA data = _GetButtonData(hWnd);
+ if (!data || !pimldata || !pimldata->himl)
+ return FALSE;
+ data->imlData = *pimldata;
+ return TRUE;
+ }
+ case BCM_GETIMAGELIST:
+ {
+ BUTTON_IMAGELIST * pimldata = (BUTTON_IMAGELIST *)lParam;
+ PBUTTON_DATA data = _GetButtonData(hWnd);
+ if (!data|| !pimldata)
+ return FALSE;
+ *pimldata = data->imlData;
+ return TRUE;
+ }
+ case BCM_GETIDEALSIZE:
+ {
+ HTHEME theme = GetWindowTheme(hWnd);
+ BOOL ret = FALSE;
+ SIZE* pSize = (SIZE*)lParam;
+
+ if (btn_type == BS_PUSHBUTTON ||
+ btn_type == BS_DEFPUSHBUTTON ||
+ btn_type == BS_USERBUTTON)
+ {
+ ret = BUTTON_GetIdealSize(theme, hWnd, pSize);
+ }
+
+ if (!ret)
+ {
+ GetClientRect(hWnd, &rect);
+ pSize->cx = rect.right;
+ pSize->cy = rect.bottom;
+ }
+
+ return TRUE;
+ }
+ }
+
+ if (!_GetButtonData(hWnd))
+ {
+ ERR("no data!\n");
+ return unicode ? DefWindowProcW(hWnd, uMsg, wParam, lParam) :
+ DefWindowProcA(hWnd, uMsg, wParam, lParam);
+ }
+
+#endif
+
switch (uMsg)
{
case WM_GETDLGCODE:
set_button_state( hWnd, BST_UNCHECKED );
#ifdef __REACTOS__
button_update_uistate( hWnd, unicode );
-#endif
-#ifndef _USER32_
- OpenThemeData(hWnd, WC_BUTTONW);
#endif
return 0;
NtUserSetWindowFNID(hWnd, FNID_DESTROY);
case WM_DESTROY:
break;
-#endif
-#ifndef _USER32_
- case WM_DESTROY:
- CloseThemeData (GetWindowTheme(hWnd));
- break;
- case WM_THEMECHANGED:
- CloseThemeData (GetWindowTheme(hWnd));
- OpenThemeData(hWnd, WC_BUTTONW);
- break;
-
- case WM_MOUSEHOVER:
- {
- int state = (int)SendMessageW(hWnd, BM_GETSTATE, 0, 0);
- SetWindowLongW(hWnd, 0, state|BST_HOT);
- InvalidateRect(hWnd, NULL, FALSE);
- break;
- }
-
- case WM_MOUSELEAVE:
- {
- int state = (int)SendMessageW(hWnd, BM_GETSTATE, 0, 0);
- SetWindowLongW(hWnd, 0, state&(~BST_HOT));
- InvalidateRect(hWnd, NULL, FALSE);
- break;
- }
#endif
case WM_ERASEBKGND:
if (btn_type == BS_OWNERDRAW)
break;
case WM_MOUSEMOVE:
-#ifndef _USER32_
- {
- TRACKMOUSEEVENT mouse_event;
- mouse_event.cbSize = sizeof(TRACKMOUSEEVENT);
- mouse_event.dwFlags = TME_QUERY;
- if(!TrackMouseEvent(&mouse_event) || !(mouse_event.dwFlags&(TME_HOVER|TME_LEAVE)))
- {
- mouse_event.dwFlags = TME_HOVER|TME_LEAVE;
- mouse_event.hwndTrack = hWnd;
- mouse_event.dwHoverTime = 1;
- TrackMouseEvent(&mouse_event);
- }
- }
-#endif
-
if ((wParam & MK_LBUTTON) && GetCapture() == hWnd)
{
GetClientRect( hWnd, &rect );
case WM_SETFOCUS:
TRACE("WM_SETFOCUS %p\n",hWnd);
set_button_state( hWnd, get_button_state(hWnd) | BST_FOCUS );
- if (btn_type == BS_OWNERDRAW)
- paint_button( hWnd, btn_type, ODA_FOCUS );
- else
+#ifndef _USER32_
+ if (btn_type != BS_OWNERDRAW)
InvalidateRect(hWnd, NULL, FALSE);
+ else
+#endif
+ paint_button( hWnd, btn_type, ODA_FOCUS );
if (style & BS_NOTIFY)
BUTTON_NOTIFY_PARENT(hWnd, BN_SETFOCUS);
break;
TRACE("WM_KILLFOCUS %p\n",hWnd);
state = get_button_state( hWnd );
set_button_state( hWnd, state & ~BST_FOCUS );
+#ifdef _USER32_
+ paint_button( hWnd, btn_type, ODA_FOCUS );
+#endif
if ((state & BUTTON_BTNPRESSED) && GetCapture() == hWnd)
ReleaseCapture();
default:
return 0;
}
+#ifdef _USER32_
oldHbitmap = (HBITMAP)SetWindowLongPtrW( hWnd, HIMAGE_GWL_OFFSET, lParam );
+#else
+ oldHbitmap = (HBITMAP)set_button_image(hWnd, lParam );
+#endif
InvalidateRect( hWnd, NULL, FALSE );
return (LRESULT)oldHbitmap;
case BM_GETIMAGE:
+#ifdef _USER32_
return GetWindowLongPtrW( hWnd, HIMAGE_GWL_OFFSET );
+#else
+ return get_button_image(hWnd);
+#endif
case BM_GETCHECK:
return get_button_state( hWnd ) & 3;
if ((state & 3) != wParam)
{
set_button_state( hWnd, (state & ~3) | wParam );
+#ifdef _USER32
+ paint_button( hWnd, btn_type, ODA_SELECT );
+#else
InvalidateRect(hWnd, NULL, FALSE);
+#endif
}
if ((btn_type == BS_AUTORADIOBUTTON) && (wParam == BST_CHECKED) && (style & WS_CHILD))
BUTTON_CheckAutoRadioButton( hWnd );
else
set_button_state( hWnd, state & ~BST_PUSHED );
+#ifdef _USER32_
+ paint_button( hWnd, btn_type, ODA_SELECT );
+#else
InvalidateRect(hWnd, NULL, FALSE);
+#endif
break;
#ifdef __REACTOS__
}
case BS_ICON:
+#ifdef _USER32_
if (!GetIconInfo((HICON)GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET ), &iconInfo))
+#else
+ if (!GetIconInfo((HICON)get_button_image(hwnd), &iconInfo))
+#endif
goto empty_rect;
GetObjectW (iconInfo.hbmColor, sizeof(BITMAP), &bm);
break;
case BS_BITMAP:
+#ifdef _USER32_
if (!GetObjectW( (HANDLE)GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET ), sizeof(BITMAP), &bm))
+#else
+ if (!GetObjectW( (HANDLE)get_button_image(hwnd), sizeof(BITMAP), &bm))
+#endif
goto empty_rect;
r.right = r.left + bm.bmWidth;
*/
static BOOL CALLBACK BUTTON_DrawTextCallback(HDC hdc, LPARAM lp, WPARAM wp, int cx, int cy)
{
+#ifdef _USER32_
RECT rc;
SetRect(&rc, 0, 0, cx, cy);
DrawTextW(hdc, (LPCWSTR)lp, -1, &rc, (UINT)wp);
return TRUE;
+#else
+ HWND hwnd = (HWND)lp;
+ RECT rc;
+ PBUTTON_DATA pdata = _GetButtonData(hwnd);
+ SIZE ImageSize;
+ WCHAR *text = NULL;
+
+ if (!(text = get_button_text( hwnd ))) return TRUE;
+
+ SetRect(&rc, 0, 0, cx, cy);
+
+ if (pdata->imlData.himl && ImageList_GetIconSize(pdata->imlData.himl, &ImageSize.cx, &ImageSize.cy))
+ {
+ int left = pdata->imlData.margin.left;
+ int top = (cy - ImageSize.cy) / 2;
+ rc.left += pdata->imlData.margin.left + pdata->imlData.margin.right + ImageSize.cy;
+ ImageList_Draw(pdata->imlData.himl, 0, hdc, left, top, 0);
+ }
+
+ DrawTextW(hdc, text, -1, &rc, (UINT)wp);
+ return TRUE;
+#endif
}
case BS_TEXT:
/* DST_COMPLEX -- is 0 */
lpOutputProc = BUTTON_DrawTextCallback;
+#ifdef _USER32_
if (!(text = get_button_text( hwnd ))) return;
lp = (LPARAM)text;
+#else
+ lp = (LPARAM)hwnd;
+#endif
+
wp = (WPARAM)dtFlags;
#ifdef __REACTOS__
case BS_ICON:
flags |= DST_ICON;
+#ifdef _USER32_
lp = GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET );
+#else
+ lp = get_button_image(hwnd);
+#endif
break;
case BS_BITMAP:
flags |= DST_BITMAP;
+#ifdef _USER32_
lp = GetWindowLongPtrW( hwnd, HIMAGE_GWL_OFFSET );
+#else
+ lp = get_button_image(hwnd);
+#endif
break;
default:
wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW | CS_HREDRAW | CS_PARENTDC;
wndClass.lpfnWndProc = ButtonWndProcW;
wndClass.cbClsExtra = 0;
- wndClass.cbWndExtra = NB_EXTRA_BYTES;
+ wndClass.cbWndExtra = sizeof(PBUTTON_DATA);
wndClass.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wndClass.lpszClassName = WC_BUTTONW;