#include "alfpriv.h" /* LABEL */ typedef struct { DWORD style; HFONT font; } ALFLabelPriv; TCHAR *_alf_labelClass; static int ALF__LabelTopPadding(HWND hwnd) { // some pixels on top to align with the edit control // see also: alfedit.cpp return ALF_Compat_GetSystemMetricsForDpi( SM_CYEDGE, (UINT)ALF_CentipointsToPixels(GetParent(hwnd), 7200)) + (!ALF_Compat_IsMinWindowsVersion(4, 0) ? 2 : 1) /* internal padding in edit control */; } static int ALF__LabelLeftPadding(HWND hwnd, HDC hdc) { // some pixels on the left to align with the edit control // see also: alfedit.cpp int p = ALF_Compat_GetSystemMetricsForDpi( SM_CXEDGE, (UINT)ALF_CentipointsToPixels(GetParent(hwnd), 7200)); p += 1; TEXTMETRIC tm; ZeroMemory(&tm, sizeof(tm)); if (GetTextMetrics(hdc, &tm)) { if (tm.tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE)) p += ALF_GetAveCharWidth(hdc) / 2; } return p; } static BOOL CALLBACK ALF__Label_Text_DrawStateProc(HDC hdc, LPARAM lData, WPARAM wData, int cx, int cy) { (void)wData; int oldBkMode = SetBkMode(hdc, TRANSPARENT); RECT r = { 0, 0, cx, cy }; DrawText(hdc, (TCHAR*)lData, -1, &r, (UINT)wData); SetBkMode(hdc, oldBkMode); return TRUE; } static LRESULT CALLBACK ALF__LabelWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ALFLabelPriv *priv = (ALFLabelPriv*)GetWindowLongPtr(hwnd, 0); if (!priv) return DefWindowProc(hwnd, uMsg, wParam, lParam); if (uMsg == ALF_WM_LBL_GETSTYLE) { return (LRESULT)priv->style; } else if (uMsg == ALF_WM_LBL_SETSTYLE) { priv->style = (DWORD)lParam; InvalidateRect(hwnd, NULL, TRUE); return TRUE; } else if (uMsg == WM_SETTEXT) { InvalidateRect(hwnd, NULL, TRUE); ALF_InvalidateLayout(GetParent(hwnd)); } else if (uMsg == WM_GETDLGCODE) { return DLGC_STATIC; } else if (uMsg == WM_SETFONT) { priv->font = (HFONT)wParam; if (LOWORD(lParam) != 0) InvalidateRect(hwnd, NULL, TRUE); ALF_InvalidateLayout(GetParent(hwnd)); return 0; } else if (uMsg == WM_GETFONT) { return (LRESULT)priv->font; } else if (uMsg == WM_UPDATEUISTATE) { InvalidateRect(hwnd, NULL, TRUE); } else if (uMsg == WM_ERASEBKGND) { return 1; // do it in WM_PAINT } else if (uMsg == WM_PAINT) { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); ALF_Compat_DrawThemeParentBackground(hwnd, hdc, &ps.rcPaint); HFONT oldFont = NULL; if (priv->font) oldFont = SelectFont(hdc, priv->font); SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT)); SetBkMode(hdc, TRANSPARENT); // calc drawtext style UINT format = DT_EXPANDTABS; LRESULT uiState = SendMessage(hwnd, WM_QUERYUISTATE, 0, 0); if (uiState & UISF_HIDEACCEL) format |= DT_HIDEPREFIX; RECT rc; GetClientRect(hwnd, &rc); switch (priv->style & ALF_LABEL_HALIGN_MASK) { case ALF_LABEL_ALIGN_HCENTER: format |= DT_CENTER; break; case ALF_LABEL_ALIGN_RIGHT: format |= DT_RIGHT; break; } switch (priv->style & ALF_LABEL_VALIGN_MASK) { case ALF_LABEL_ALIGN_BOTTOM: format |= DT_BOTTOM; break; case ALF_LABEL_ALIGN_VCENTER: format |= DT_VCENTER; break; } if ((priv->style & ALF_LABEL_HALIGN_MASK) == ALF_LABEL_ALIGN_LEFT_LIKE_EDIT) rc.left += ALF__LabelLeftPadding(hwnd, hdc); if ((priv->style & ALF_LABEL_VALIGN_MASK) == ALF_LABEL_ALIGN_TOP_LIKE_EDIT) rc.top += ALF__LabelTopPadding(hwnd); TCHAR *text = ALF_Text(hwnd); if (!IsWindowEnabled(hwnd)) { if (!ALF_Compat_IsMinWindowsVersion(4, 0)) { // Win32s/NT 3.51 uses gray text, but a different gray than Win9x SetTextColor(hdc, GetSysColor(COLOR_BTNSHADOW)); DrawText(hdc, text, -1, &rc, format); } else if (ALF_Compat_IsWin9x()) { // Win9x just uses gray text. DSS_DISABLED is broken there, too, // so we can't get the NT look even if we wanted to SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); DrawText(hdc, text, -1, &rc, format); } else { // FIXME! This doesn't look good when using uxtheme, even though windows does it the same way // need to investigate whether drawing with disabled button style looks nicer DrawState(hdc, NULL, ALF__Label_Text_DrawStateProc, (LPARAM)text, (WPARAM)format, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, DST_COMPLEX | DSS_DISABLED); } } else { DrawText(hdc, text, -1, &rc, format); } ALF_Free(text); if (oldFont) SelectFont(hdc, oldFont); EndPaint(hwnd, &ps); return TRUE; } else if (uMsg == ALF_WM_QUERYSIZE) { int textlen = GetWindowTextLength(hwnd); SIZE *pSize = (SIZE*)(void*)lParam; if (textlen) { HDC hdcLabel = GetDC(hwnd); HFONT oldFont = SelectFont(hdcLabel, priv->font); // calc drawtext style UINT format = DT_LEFT | DT_EXPANDTABS | DT_CALCRECT; RECT r = { 0, 0, 100, 100 }; TCHAR *textbuf = ALF_New(TCHAR, (SIZE_T)textlen + 1); GetWindowText(hwnd, textbuf, textlen+1); DrawText(hdcLabel, textbuf, -1, &r, format); ALF_Free(textbuf); if (pSize->cx == 0) { pSize->cx = r.right - r.left; if ((priv->style & ALF_LABEL_HALIGN_MASK) == ALF_LABEL_ALIGN_LEFT_LIKE_EDIT) pSize->cx += ALF__LabelLeftPadding(hwnd, hdcLabel); } if (pSize->cy == 0) { pSize->cy = r.bottom - r.top; if ((priv->style & ALF_LABEL_VALIGN_MASK) == ALF_LABEL_ALIGN_TOP_LIKE_EDIT) pSize->cy += ALF__LabelTopPadding(hwnd); } SelectFont(hdcLabel, oldFont); ReleaseDC(hwnd, hdcLabel); } } else if (uMsg == WM_WINDOWPOSCHANGED) { WINDOWPOS *p = (WINDOWPOS *)lParam; if (!(p->flags & SWP_NOSIZE)) { // for left-top aligned labels, no redraw is necessary // right/bottom/center alignment basically needs to redraw the whole thing DWORD halign = priv->style & ALF_LABEL_HALIGN_MASK; DWORD valign = priv->style & ALF_LABEL_VALIGN_MASK; if ((halign != ALF_LABEL_ALIGN_LEFT && halign != ALF_LABEL_ALIGN_LEFT_LIKE_EDIT) || (valign != ALF_LABEL_ALIGN_TOP && valign != ALF_LABEL_ALIGN_TOP_LIKE_EDIT)) { InvalidateRect(hwnd, NULL, TRUE); } } } else if (uMsg == WM_DESTROY) { ALF_Free(priv); SetWindowLongPtr(hwnd, 0, 0); } return DefWindowProc(hwnd, uMsg, wParam, lParam); } HWND ALF_AddLabel(HWND win, WORD id, int x, int y, const TCHAR *text) { HWND hwndLabel = CreateWindow(_alf_labelClass, text, WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, win, (HMENU)(int)id, ALF_HINSTANCE, NULL); ALFLabelPriv *priv = ALF_New(ALFLabelPriv, 1); priv->style = ALF_LABEL_ALIGN_LEFT | ALF_LABEL_ALIGN_TOP_LIKE_EDIT; SetWindowLongPtr(hwndLabel, 0, (LONG_PTR)priv); ALF_AddWidget(win, x, y, hwndLabel, 0, 0, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT | ALF_LAYOUT_TRANSPARENTBG); return hwndLabel; } void ALF_RegisterLabelClass(void) { WNDCLASS cls; ZeroMemory(&cls, sizeof(cls)); TCHAR classNameBuf[256]; ALF_BuildUniqueName(classNameBuf, TEXT("ALFLabel."), (ULONG_PTR)&_alf_labelClass); cls.hInstance = ALF_HINSTANCE; cls.hCursor = LoadCursor(NULL, (LPTSTR)IDC_ARROW); cls.lpszClassName = classNameBuf; cls.cbWndExtra = sizeof(void*); cls.lpfnWndProc = ALF__LabelWindowProc; ATOM classatom = RegisterClass(&cls); if (!classatom) MessageBox(NULL, TEXT("FATAL: Could not register label class"), NULL, MB_OK); _alf_labelClass = MAKEINTATOM(classatom); }