summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Kümmerlin <jonas@kuemmerlin.eu>2019-06-30 12:48:57 +0200
committerJonas Kümmerlin <jonas@kuemmerlin.eu>2019-06-30 12:48:57 +0200
commitfe078af239f3b73651c32bb1cdb158dcab39ad5c (patch)
treec855620ab6970e658ea662d2c36b81cb68f50992
parentecfb4b72fec0c25ef416038ef22db5d34d687ee4 (diff)
label reimplement
-rw-r--r--alf/alf.cpp2
-rw-r--r--alf/alf.h17
-rw-r--r--alf/alfcompat.cpp41
-rw-r--r--alf/alflabel.cpp233
-rw-r--r--alf/alfpriv.h4
-rw-r--r--widgetfactory.cpp2
6 files changed, 257 insertions, 42 deletions
diff --git a/alf/alf.cpp b/alf/alf.cpp
index 61ce4ee..932bd3b 100644
--- a/alf/alf.cpp
+++ b/alf/alf.cpp
@@ -364,6 +364,7 @@ ALF_Initialize(void)
ALF_RegisterComboClass();
ALF_RegisterPanelClass();
ALF_RegisterSpacerClass();
+ ALF_RegisterLabelClass();
ALF_Compat_BufferedPaintInit();
}
@@ -387,6 +388,7 @@ ALF_UnInitialize(void)
UnregisterClass(_alf_comboClass, ALF_HINSTANCE);
UnregisterClass(_alf_panelClass, ALF_HINSTANCE);
UnregisterClass(_alf_spacerClass, ALF_HINSTANCE);
+ UnregisterClass(_alf_labelClass, ALF_HINSTANCE);
ALF_UnloadCompatFunctions();
}
diff --git a/alf/alf.h b/alf/alf.h
index b9fe0be..d74553b 100644
--- a/alf/alf.h
+++ b/alf/alf.h
@@ -36,6 +36,19 @@ typedef struct {
// sends a ALF_WM_APPLYFONTS message to the widget with ALFWindowFonts* lparam
#define ALF_SENDAPPLYFONTS 0x80
+// label style flags
+#define ALF_LABEL_ALIGN_LEFT 0
+#define ALF_LABEL_ALIGN_LEFT_LIKE_EDIT 1
+#define ALF_LABEL_ALIGN_HCENTER 2
+#define ALF_LABEL_ALIGN_RIGHT 3
+#define ALF_LABEL_HALIGN_MASK 3
+#define ALF_LABEL_ALIGN_TOP 0
+#define ALF_LABEL_ALIGN_TOP_LIKE_EDIT 4
+#define ALF_LABEL_ALIGN_VCENTER 8
+#define ALF_LABEL_ALIGN_BOTTOM 12
+#define ALF_LABEL_VALIGN_MASK 12
+
+
// messages
#define ALF_WM__BASE 0x2800
#define ALF_WM_QUERYSIZE (ALF_WM__BASE + 1)
@@ -55,6 +68,10 @@ typedef struct {
#define ALF_WM_APPLYFONTS (ALF_WM__BASE + 16)
#define ALF_WM_PRETRANSLATEMSG (ALF_WM__BASE + 17)
+#define ALF_WM_LBL_GETSTYLE (ALF_WM__BASE + 201)
+#define ALF_WM_LBL_SETSTYLE (ALF_WM__BASE + 202)
+
+
typedef struct {
const TCHAR *className;
UINT classStyle;
diff --git a/alf/alfcompat.cpp b/alf/alfcompat.cpp
index 3895545..8672bb8 100644
--- a/alf/alfcompat.cpp
+++ b/alf/alfcompat.cpp
@@ -260,11 +260,44 @@ ALF_Compat_fallbackIsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPar
static HRESULT WINAPI
ALF_Compat_fallbackDrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc)
{
- (void)hwnd;
- (void)hdc;
- (void)prc;
+ HWND parent = GetParent(hwnd);
+ if (!parent)
+ return E_NOTIMPL;
+
+ RECT rc;
+ if (prc) {
+ rc = *prc;
+ } else {
+ GetClientRect(hwnd, &rc);
+ }
+ MapWindowRect(hwnd, parent, &rc);
- return E_NOTIMPL;
+ RECT childr;
+ GetClientRect(hwnd, &childr);
+ MapWindowRect(hwnd, parent, &childr);
+
+ POINT o;
+ OffsetViewportOrgEx(hdc, -childr.left, -childr.top, &o);
+
+ HRGN oldClipRgn = CreateRectRgn(0, 0, 0, 0);
+ if (!GetClipRgn(hdc, oldClipRgn)) {
+ DeleteObject(oldClipRgn);
+ oldClipRgn = NULL;
+ }
+
+ IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
+
+ SendMessage(parent, WM_ERASEBKGND, (WPARAM)hdc, 0);
+ SendMessage(parent, WM_PRINTCLIENT, (WPARAM)hdc, (LPARAM)PRF_CLIENT);
+
+ SelectClipRgn(hdc, oldClipRgn);
+ if (oldClipRgn) {
+ DeleteObject(oldClipRgn);
+ }
+
+ SetViewportOrgEx(hdc, o.x, o.y, NULL);
+
+ return S_OK;
}
static HRESULT WINAPI
diff --git a/alf/alflabel.cpp b/alf/alflabel.cpp
index e7550e4..208b033 100644
--- a/alf/alflabel.cpp
+++ b/alf/alflabel.cpp
@@ -2,8 +2,15 @@
/* LABEL */
-static
-int ALF__LabelTopPadding(HWND hwnd)
+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
@@ -12,28 +19,152 @@ int ALF__LabelTopPadding(HWND hwnd)
+ ((LOBYTE(LOWORD(GetVersion())) < 4) ? 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, 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__LabelSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
+ALF__LabelWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
- (void)uIdSubclass;
- (void)dwRefData;
+ ALFLabelPriv *priv = (ALFLabelPriv*)GetWindowLongPtr(hwnd, 0);
+ if (!priv)
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+
+ if (uMsg == ALF_WM_LBL_GETSTYLE) {
+ return priv->style;
+ } else if (uMsg == ALF_WM_LBL_SETSTYLE) {
+ priv->style = (DWORD)lParam;
+ InvalidateRect(hwnd, NULL, TRUE);
+ return TRUE;
+ } 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);
- if (uMsg == ALF_WM_QUERYSIZE) {
+ return 0;
+ } else if (uMsg == WM_GETFONT) {
+ return (LRESULT)priv->font;
+ } else if (uMsg == WM_UPDATEUISTATE) {
+ InvalidateRect(hwnd, NULL, TRUE);
+ } 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 (GetVersion() >= 0x80000000) {
+ // 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) {
HDC hdcLabel = GetDC(hwnd);
- HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
HFONT oldFont = 0;
- if (font)
- oldFont = SelectFont(hdcLabel, font);
+ if (priv->font)
+ oldFont = SelectFont(hdcLabel, priv->font);
// calc drawtext style
- DWORD style = GetWindowLong(hwnd, GWL_STYLE);
UINT format = DT_LEFT | DT_EXPANDTABS | DT_CALCRECT;
- if (style & SS_NOPREFIX)
- format |= DT_NOPREFIX;
- if (style & SS_EDITCONTROL)
- format |= DT_EDITCONTROL;
- if (style & SS_ENDELLIPSIS || style & SS_PATHELLIPSIS || style & SS_WORDELLIPSIS)
- format |= DT_SINGLELINE;
RECT r = { 0, 0, 100, 100 };
@@ -46,45 +177,44 @@ ALF__LabelSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_
ALF_Free(textbuf);
SIZE *pSize = (SIZE*)(void*)lParam;
- if (pSize->cx == 0)
+ if (pSize->cx == 0) {
pSize->cx = r.right - r.left;
- if (pSize->cy == 0)
- pSize->cy = r.bottom - r.top + ALF__LabelTopPadding(hwnd);
+ 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);
+ }
- if (font)
+ if (oldFont)
SelectFont(hdcLabel, oldFont);
ReleaseDC(hwnd, hdcLabel);
- } else if (uMsg == ALF_WM_APPLYSIZE) {
- RECT *p = (RECT *)lParam;
-
- int topPadding = ALF__LabelTopPadding(hwnd);
-
- return (LRESULT)DeferWindowPos((HDWP)wParam,
- hwnd, NULL,
- p->left, p->top + topPadding,
- p->right - p->left, p->bottom - p->top - topPadding,
- SWP_NOZORDER|SWP_NOACTIVATE);
} else if (uMsg == WM_DESTROY) {
- ALF_Compat_RemoveWindowSubclass(hwnd, ALF__LabelSubclassProc, 0);
+ ALF_Free(priv);
+ SetWindowLongPtr(hwnd, 0, 0);
}
- return ALF_Compat_DefSubclassProc(hwnd, uMsg, wParam, lParam);
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
HWND
ALF_AddLabel(HWND win, WORD id, UINT x, UINT y, const TCHAR *text)
{
- HWND hwndLabel = CreateWindow(TEXT("STATIC"),
+ HWND hwndLabel = CreateWindow(_alf_labelClass,
text,
- WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP,
+ WS_CHILD | WS_VISIBLE | SS_OWNERDRAW,
0, 0, 100, 100,
win,
(HMENU)(int)id,
- (HINSTANCE)GetWindowLongPtr(win, GWLP_HINSTANCE),
+ ALF_HINSTANCE,
NULL);
- ALF_Compat_SetWindowSubclass(hwndLabel, ALF__LabelSubclassProc, 0, 0);
+ ALFLabelPriv *priv = ALF_New(ALFLabelPriv, 1);
+ priv->style = ALF_LABEL_ALIGN_LEFT | ALF_LABEL_ALIGN_TOP_LIKE_EDIT;
+ SetWindowLongPtr(hwndLabel, 0, (LONG_PTR)priv);
ALFWidgetLayoutParams p;
ZeroMemory(&p, sizeof(p));
@@ -93,9 +223,38 @@ ALF_AddLabel(HWND win, WORD id, UINT x, UINT y, const TCHAR *text)
p.y = y;
p.width = 0;
p.height = 0;
- p.flags = ALF_QUERYSIZE | ALF_APPLYSIZE | ALF_MESSAGEFONT;
+ p.flags = ALF_QUERYSIZE | ALF_MESSAGEFONT;
ALF_AddWidgetEx(win, &p);
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);
+ if (LOBYTE(LOWORD(GetVersion())) >= 4) {
+ cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
+ } else {
+ // NT 3.x has white dialog backgrounds
+ cls.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ }
+ 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);
+}
diff --git a/alf/alfpriv.h b/alf/alfpriv.h
index aa0b39d..3d0f092 100644
--- a/alf/alfpriv.h
+++ b/alf/alfpriv.h
@@ -30,6 +30,7 @@ typedef struct {
extern TCHAR *_alf_comboClass;
extern TCHAR *_alf_panelClass;
extern TCHAR *_alf_spacerClass;
+extern TCHAR *_alf_labelClass;
int
ALF_CentipointsToPxPriv(ALFWindowPriv *priv, int cptValue);
@@ -53,6 +54,9 @@ void
ALF_RegisterSpacerClass(void);
void
+ALF_RegisterLabelClass(void);
+
+void
ALF_BuildUniqueName(TCHAR *buf, const TCHAR *prefix, ULONG_PTR uniquifier);
BOOL
diff --git a/widgetfactory.cpp b/widgetfactory.cpp
index 67e38d7..6fbd452 100644
--- a/widgetfactory.cpp
+++ b/widgetfactory.cpp
@@ -136,7 +136,7 @@ WinMain
ALF_AddButton(win, ID_B1, 2, 1, TEXT("&Go Go Go!"));
ALF_AddButton(win, ID_B2, 0, 2, TEXT("Oh m&y god,\r\nwho the hell cares?"));
- ALF_AddLabel(win, ID_LBL4, 0, 3, TEXT("Editable Combo Box:"));
+ ALF_AddLabel(win, ID_LBL4, 0, 3, TEXT("&Editable Combo Box:"));
HWND hwndCombo1 = ALF_AddEditableComboBox(win, ID_COMBO1, 1, 3, TEXT("Hello!"));
ALF_AddButton(win, ID_B3, 2, 3, TEXT("Ok"));