#include "alfpriv.h" /* LABEL */ typedef struct { DWORD style; HFONT font; ALFColor bgcolor; ALFColor textcolor; int dpi; } ALFLabelPriv; static int ALF__LabelTopPadding(HWND hwnd, ALFLabelPriv *priv) { (void)hwnd; // some pixels on top to align with the edit control // see also: alfedit.cpp return ALF_Compat_GetSystemMetricsForDpi( SM_CYEDGE, (UINT)priv->dpi) + (!ALF_Compat_IsMinWindowsVersion(4, 0) ? 2 : 1) /* internal padding in edit control */; } static int ALF__LabelLeftPadding(HWND hwnd, HDC hdc, ALFLabelPriv *priv) { (void)hwnd; // some pixels on the left to align with the edit control // see also: alfedit.cpp int p = ALF_Compat_GetSystemMetricsForDpi( SM_CXEDGE, (UINT)priv->dpi); 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 void ALF_Label_Paint(HWND hwnd, ALFLabelPriv *priv, HDC hdc, RECT *r) { if (priv->bgcolor == ALF_COLOR_TRANSPARENT) { ALF_Compat_DrawThemeParentBackground(hwnd, hdc, r); SetBkMode(hdc, TRANSPARENT); } else { ALF_FillRect(hdc, r, priv->bgcolor); SetBkMode(hdc, OPAQUE); SetBkColor(hdc, ALF_ColorToGdi(priv->bgcolor)); } HFONT oldFont = SelectFont(hdc, priv->font); SetTextColor(hdc, ALF_ColorToGdi(priv->textcolor)); TCHAR *text = ALF_Text(hwnd); // calc drawtext style UINT format = DT_EXPANDTABS | DT_NOCLIP; LRESULT uiState = SendMessage(hwnd, WM_QUERYUISTATE, 0, 0); if (uiState & UISF_HIDEACCEL) format |= DT_HIDEPREFIX; // calculate text position RECT rcClient = { 0, 0, 0, 0 }; GetClientRect(hwnd, &rcClient); RECT rcText = { 0, 0, 0, 0 }; DrawText(hdc, text, -1, &rcText, DT_EXPANDTABS | DT_CALCRECT); RECT rcTarget = { 0, 0, 0, 0 }; switch (priv->style & ALF_LABEL_HALIGN_MASK) { case ALF_LABEL_ALIGN_LEFT: format |= DT_LEFT; rcTarget.left = 0; rcTarget.right = rcText.right - rcText.left; break; case ALF_LABEL_ALIGN_LEFT_LIKE_EDIT: format |= DT_LEFT; rcTarget.left = ALF__LabelLeftPadding(hwnd, hdc, priv); rcTarget.right = rcTarget.left + rcText.right - rcText.left; break; case ALF_LABEL_ALIGN_HCENTER: format |= DT_CENTER; rcTarget.left = (rcClient.right - rcClient.left - rcText.right + rcText.left)/2; rcTarget.right = rcTarget.left + rcText.right - rcText.left; break; case ALF_LABEL_ALIGN_RIGHT: format |= DT_RIGHT; rcTarget.right = rcClient.right - rcClient.left; rcTarget.left = rcTarget.right - rcText.right + rcText.left; break; } switch (priv->style & ALF_LABEL_VALIGN_MASK) { case ALF_LABEL_ALIGN_TOP: format |= DT_TOP; rcTarget.top = 0; rcTarget.bottom = rcText.bottom - rcText.top; break; case ALF_LABEL_ALIGN_TOP_LIKE_EDIT: format |= DT_TOP; rcTarget.top = ALF__LabelTopPadding(hwnd, priv); rcTarget.bottom = rcTarget.top + rcText.bottom - rcText.top; break; case ALF_LABEL_ALIGN_BOTTOM: format |= DT_BOTTOM; rcTarget.bottom = rcClient.bottom - rcClient.top; rcTarget.top = rcTarget.bottom - rcText.bottom + rcText.top; break; case ALF_LABEL_ALIGN_VCENTER: format |= DT_VCENTER; rcTarget.top = (rcClient.bottom - rcClient.top - rcText.bottom + rcText.top) / 2; rcTarget.bottom = rcTarget.top + rcText.bottom - rcText.top; break; } if (!IsWindowEnabled(hwnd)) { ALF_Compat_DrawDisabledText(hdc, text, -1, &rcTarget, format); } else { DrawText(hdc, text, -1, &rcTarget, format); } ALF_Free(text); SelectFont(hdc, oldFont); } static void ALF_Label_CalculateSize(HWND hwnd, ALFLabelPriv *priv, SIZE *pSize) { int textlen = GetWindowTextLength(hwnd); 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); int cx = r.right - r.left; if ((priv->style & ALF_LABEL_HALIGN_MASK) == ALF_LABEL_ALIGN_LEFT_LIKE_EDIT) cx += ALF__LabelLeftPadding(hwnd, hdcLabel, priv); int cy = r.bottom - r.top; if ((priv->style & ALF_LABEL_VALIGN_MASK) == ALF_LABEL_ALIGN_TOP_LIKE_EDIT) cy += ALF__LabelTopPadding(hwnd, priv); if (pSize->cx < cx) pSize->cx = cx; if (pSize->cy < cy) pSize->cy = cy; SelectFont(hdcLabel, oldFont); ReleaseDC(hwnd, hdcLabel); } } 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) { DWORD newStyle = (DWORD)lParam; // if the ALF_LABEL_ALIGN_LEFT_LIKE_EDIT or ALF_LABEL_ALIGN_TOP_LIKE_EDIT // styles have been toggled, a new layout calculation is necessary if (((newStyle & ALF_LABEL_HALIGN_MASK) != (priv->style & ALF_LABEL_HALIGN_MASK) && ((newStyle & ALF_LABEL_HALIGN_MASK) == ALF_LABEL_ALIGN_LEFT_LIKE_EDIT || (priv->style & ALF_LABEL_HALIGN_MASK) == ALF_LABEL_ALIGN_LEFT_LIKE_EDIT)) || ((newStyle & ALF_LABEL_VALIGN_MASK) != (priv->style & ALF_LABEL_VALIGN_MASK) && ((newStyle & ALF_LABEL_VALIGN_MASK) == ALF_LABEL_ALIGN_TOP_LIKE_EDIT || (priv->style & ALF_LABEL_VALIGN_MASK) == ALF_LABEL_ALIGN_TOP_LIKE_EDIT))) { ALF_InvalidateLayout(GetParent(hwnd)); } priv->style = newStyle; 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_Label_Paint(hwnd, priv, hdc, &ps.rcPaint); EndPaint(hwnd, &ps); return TRUE; } else if (uMsg == WM_PRINTCLIENT) { RECT rc; GetClientRect(hwnd, &rc); ALF_Label_Paint(hwnd, priv, (HDC)wParam, &rc); } else if (uMsg == ALF_WM_QUERYSIZE) { ALF_Label_CalculateSize(hwnd, priv, (SIZE*)lParam); } 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 == ALF_WM_BACKGROUNDCHANGE) { if (priv->bgcolor == ALF_COLOR_TRANSPARENT) { InvalidateRect(hwnd, NULL, TRUE); } return TRUE; } else if (uMsg == ALF_WM_SETBGCOLOR) { ALFColor newcolor = (ALFColor)lParam; if (priv->bgcolor == newcolor) return TRUE; priv->bgcolor = newcolor; InvalidateRect(hwnd, NULL, TRUE); return TRUE; } else if (uMsg == ALF_WM_GETBGCOLOR) { return (LRESULT)priv->bgcolor; } else if (uMsg == ALF_WM_SETTEXTCOLOR) { ALFColor newcolor = (ALFColor)lParam; if (priv->textcolor == newcolor) return TRUE; priv->textcolor = newcolor; InvalidateRect(hwnd, NULL, TRUE); return TRUE; } else if (uMsg == ALF_WM_GETTEXTCOLOR) { return (LRESULT)priv->textcolor; } else if (uMsg == ALF_WM_DPICHANGE) { priv->dpi = (int)lParam; ALF_InvalidateLayout(GetParent(hwnd)); return 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 = ALF_CreateControlWindow(0, text, WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, win, (HMENU)(ULONG_PTR)id, ALF__LabelWindowProc, NULL); ALFLabelPriv *priv = ALF_New(ALFLabelPriv, 1); priv->style = ALF_LABEL_ALIGN_LEFT | ALF_LABEL_ALIGN_TOP_LIKE_EDIT; priv->bgcolor = ALF_COLOR_SYS(COLOR_BTNFACE); priv->textcolor = ALF_COLOR_SYS(COLOR_BTNTEXT); priv->dpi = 96; SetWindowLongPtr(hwndLabel, 0, (LONG_PTR)priv); ALF_AddWidget(win, x, y, hwndLabel, 0, 0, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT | ALF_LAYOUT_INHERITBGCOLOR | ALF_LAYOUT_SENDBGCHANGE | ALF_LAYOUT_SENDDPICHANGE); return hwndLabel; } DWORD ALF_LabelStyle(HWND hwndLabel) { return (DWORD)SendMessage(hwndLabel, ALF_WM_LBL_GETSTYLE, 0, 0); } void ALF_LabelSetStyle(HWND hwndLabel, DWORD style) { SendMessage(hwndLabel, ALF_WM_LBL_SETSTYLE, 0, (LPARAM)style); }