summaryrefslogtreecommitdiff
path: root/alf
diff options
context:
space:
mode:
Diffstat (limited to 'alf')
-rw-r--r--alf/alf.cpp36
-rw-r--r--alf/alf.h31
-rw-r--r--alf/alfcombobox.cpp270
-rw-r--r--alf/alfcompat.cpp11
-rw-r--r--alf/alfcompat.h2
-rw-r--r--alf/alfpriv.h7
6 files changed, 343 insertions, 14 deletions
diff --git a/alf/alf.cpp b/alf/alf.cpp
index ae6c8f9..9d1379c 100644
--- a/alf/alf.cpp
+++ b/alf/alf.cpp
@@ -519,10 +519,31 @@ ALF_CreateApplication(HINSTANCE hInstance)
InitCommonControlsEx(&icc);
app->compatFn = ALF_CreateCompatFuncTable();
+ ALF_RegisterComboClass(app);
return app;
}
+
+void
+ALF_BuildRandomClassName(const TCHAR *prefix, TCHAR *buf)
+{
+ UUID uuid;
+ UuidCreate(&uuid);
+
+#ifdef UNICODE
+ unsigned short *uuidstr = NULL;
+#else
+ unsigned char *uuidstr = NULL;
+#endif
+ UuidToString(&uuid, &uuidstr);
+
+ lstrcpy(buf, prefix);
+ lstrcat(buf, (LPCTSTR)uuidstr);
+
+ RpcStringFree(&uuidstr);
+}
+
LPTSTR
ALF_RegisterWindowClass(ALFAPP app, const ALFWindowClassParams *params)
{
@@ -535,20 +556,7 @@ ALF_RegisterWindowClass(ALFAPP app, const ALFWindowClassParams *params)
ZeroMemory(classNameBuf, sizeof(classNameBuf));
classNamePtr = classNameBuf;
- UUID uuid;
- UuidCreate(&uuid);
-
-#ifdef UNICODE
- unsigned short *uuidstr = NULL;
-#else
- unsigned char *uuidstr = NULL;
-#endif
- UuidToString(&uuid, &uuidstr);
-
- lstrcpy(classNameBuf, TEXT("ALFWindow."));
- lstrcat(classNameBuf, (LPCTSTR)uuidstr);
-
- RpcStringFree(&uuidstr);
+ ALF_BuildRandomClassName(TEXT("ALFWindow."), classNameBuf);
}
cls.style = params->classStyle;
diff --git a/alf/alf.h b/alf/alf.h
index 6d36aff..c6a7b77 100644
--- a/alf/alf.h
+++ b/alf/alf.h
@@ -142,6 +142,37 @@ ALF_SetModalResult(HWND win, int result);
int
ALF_GetModalResult(HWND win);
+// combo box
+
+HWND
+ALF_AddEditableComboBox(HWND win, WORD id, UINT x, UINT y, const TCHAR *defaultText);
+
+HWND
+ALF_AddSelectionOnlyComboBox(HWND win, WORD id, UINT x, UINT y);
+
+int /* index */
+ALF_ComboBoxAddString(HWND combo, const TCHAR *text);
+
+void
+ALF_ComboBoxInsertString(HWND combo, int index, const TCHAR *text);
+
+void
+ALF_ComboBoxRemoveString(HWND combo, int index);
+
+int
+ALF_ComboBoxCurrentIndex(HWND combo);
+
+void
+ALF_ComboBoxSetCurrentIndex(HWND combo);
+
+// NOTE: call HeapFree
+TCHAR *
+ALF_ComboBoxCurrentText(HWND combo);
+
+void
+ALF_ComboBoxSetText(HWND combo, const TCHAR *text);
+
+
#ifdef __cplusplus
} // extern C
#endif
diff --git a/alf/alfcombobox.cpp b/alf/alfcombobox.cpp
new file mode 100644
index 0000000..43c547a
--- /dev/null
+++ b/alf/alfcombobox.cpp
@@ -0,0 +1,270 @@
+#include "alfpriv.h"
+
+typedef struct {
+ ALFAPP app;
+ DWORD comboStyle;
+} ALFComboCreateParams;
+
+static int
+ALF__ComboItemHeight(HWND hwnd)
+{
+ int height = 0;
+ HDC hDc = GetDC(hwnd);
+ HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
+ if (font) {
+ HFONT oldfont = SelectFont(hDc, font);
+
+ TEXTMETRIC tm;
+ ZeroMemory(&tm, sizeof(tm));
+
+ if (GetTextMetrics(hDc, &tm)) {
+ height = tm.tmHeight;
+ }
+
+ SelectFont(hDc, oldfont);
+ }
+
+ ReleaseDC(hwnd, hDc);
+ return height;
+}
+
+static LRESULT CALLBACK
+ALF__ComboWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg == WM_NCCREATE) {
+ ALFComboCreateParams *params = (ALFComboCreateParams*)((CREATESTRUCT*)lParam)->lpCreateParams;
+
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR)params->app);
+ }
+
+ ALFAPP app = (ALFAPP)GetWindowLongPtr(hwnd, 0);
+ HWND hwndChild = (HWND)GetWindowLongPtr(hwnd, sizeof(void*));
+
+ if (uMsg == WM_CREATE) {
+ ALFComboCreateParams *params = (ALFComboCreateParams*)((CREATESTRUCT*)lParam)->lpCreateParams;
+ HWND hwndCombo = CreateWindowEx(0,
+ TEXT("COMBOBOX"),
+ TEXT(""),
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS | params->comboStyle,
+ 0, 0, 0, 200 /* FIXME needed for commctl32 v5, what is the best value here? */,
+ hwnd,
+ (HMENU) GetWindowLongPtrW(hwnd, GWLP_ID),
+ ((CREATESTRUCT*)lParam)->hInstance,
+ NULL);
+
+ SetWindowLongPtr(hwnd, sizeof(void*), (LONG_PTR)hwndCombo);
+ }
+ if (uMsg == WM_ENABLE && hwndChild) {
+ EnableWindow(hwndChild, (BOOL)wParam);
+ return 0;
+ }
+ if (uMsg == WM_SETTEXT && hwndChild) {
+ return SendMessage(hwndChild, WM_SETTEXT, wParam, lParam);
+ }
+ if (uMsg == WM_GETTEXTLENGTH && hwndChild) {
+ return SendMessage(hwndChild, WM_GETTEXTLENGTH, wParam, lParam);
+ }
+ if (uMsg == WM_GETTEXT && hwndChild) {
+ return SendMessage(hwndChild, WM_GETTEXT, wParam, lParam);
+ }
+ if (uMsg == WM_SETFONT && hwndChild) {
+ SendMessage(hwndChild, WM_SETFONT, wParam, lParam);
+
+ int h = ALF__ComboItemHeight(hwnd);
+ if (h)
+ SendMessage(hwndChild, CB_SETITEMHEIGHT, (WPARAM)0, h);
+
+ return 0;
+ }
+ if (uMsg == WM_GETFONT && hwndChild) {
+ return SendMessage(hwndChild, WM_GETFONT, wParam, lParam);
+ }
+ if (uMsg == CB_ADDSTRING && hwndChild) {
+ return SendMessage(hwndChild, CB_ADDSTRING, wParam, lParam);
+ }
+
+ if (uMsg == ALF_WM_QUERYSIZE) {
+ HDC hDc = GetDC(hwnd);
+ HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
+
+ if (font) {
+ HFONT oldfont = SelectFont(hDc, font);
+
+ TEXTMETRIC tm;
+ ZeroMemory(&tm, sizeof(tm));
+
+ if (GetTextMetrics(hDc, &tm)) {
+ SIZE *ps = (SIZE*)lParam;
+ if (!ps->cx) {
+ ps->cx = ALF_CentipointsToPixels(GetParent(hwnd), 12000);
+ }
+
+ if (!ps->cy) {
+ ps->cy = tm.tmHeight + 2*app->compatFn->GetSystemMetricsForDpi(
+ SM_CYEDGE, ALF_CentipointsToPixels(GetParent(hwnd), 7200))
+ + 4 /* padding internal to the edit control */
+ + 2 /* external padding to line up with themed button */;
+ }
+ }
+
+ SelectFont(hDc, oldfont);
+ }
+
+ ReleaseDC(hwnd, hDc);
+ return 0;
+ }
+
+ if (uMsg == WM_MEASUREITEM) {
+ PMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam;
+
+ int h = ALF__ComboItemHeight(hwnd);
+ if (h)
+ lpmis->itemHeight = h;
+
+ return TRUE;
+ }
+
+ if (uMsg == WM_DRAWITEM) {
+ LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) lParam;
+
+ if (lpdis->itemID != (UINT)-1) { // Empty item
+ DWORD clrForeground = SetTextColor(lpdis->hDC,
+ GetSysColor(lpdis->itemState & (ODS_SELECTED | ODS_FOCUS) ?
+ COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
+
+ DWORD clrBackground = SetBkColor(lpdis->hDC,
+ GetSysColor(lpdis->itemState & (ODS_SELECTED | ODS_FOCUS) ?
+ COLOR_HIGHLIGHT : COLOR_WINDOW));
+
+ LONG y = lpdis->rcItem.top;
+ LONG x = lpdis->rcItem.left;
+
+ // add left padding like an edit control
+ TEXTMETRIC tm;
+ ZeroMemory(&tm, sizeof(tm));
+ if (GetTextMetrics(lpdis->hDC, &tm)) {
+ if (tm.tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE))
+ x += ALF_GetAveCharWidth(lpdis->hDC) / 2;
+ }
+
+ // Get and display the text for the list item.
+ int len = (int)SendMessage(lpdis->hwndItem, CB_GETLBTEXTLEN, (WPARAM)lpdis->itemID, 0);
+ if (len != CB_ERR) {
+ TCHAR *buf = (TCHAR*)LocalAlloc(LPTR, (len+1) * sizeof(TCHAR));
+
+ SendMessage(lpdis->hwndItem, CB_GETLBTEXT,
+ lpdis->itemID, (LPARAM)buf);
+
+ ExtTextOut(lpdis->hDC, x, y,
+ ETO_CLIPPED | ETO_OPAQUE, &lpdis->rcItem,
+ buf, lstrlen(buf), NULL);
+
+ LocalFree(buf);
+ }
+
+ // Restore the previous colors.
+ SetTextColor(lpdis->hDC, clrForeground);
+ SetBkColor(lpdis->hDC, clrBackground);
+ }
+
+ // If the item has the focus, draw the focus rectangle.
+ if ((lpdis->itemState & ODS_FOCUS) && !(lpdis->itemState & ODS_NOFOCUSRECT))
+ DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
+
+ return TRUE;
+ }
+
+ if (uMsg == WM_WINDOWPOSCHANGED && hwndChild) {
+ WINDOWPOS *pos = (WINDOWPOS *)lParam;
+ if (!(pos->flags & SWP_NOSIZE)) {
+ RECT r;
+ GetWindowRect(hwndChild, &r);
+ SetWindowPos(hwndChild, NULL, 0, 1, pos->cx, r.bottom - r.top, SWP_NOZORDER|SWP_NOACTIVATE);
+
+ SendMessage(hwndChild, CB_SETITEMHEIGHT, (WPARAM)-1, pos->cy - 8);
+
+ int h = ALF__ComboItemHeight(hwnd);
+ if (h)
+ SendMessage(hwndChild, CB_SETITEMHEIGHT, (WPARAM)0, h);
+ }
+ }
+
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
+
+
+void
+ALF_RegisterComboClass(ALFAPP app)
+{
+ WNDCLASS cls;
+ ZeroMemory(&cls, sizeof(cls));
+
+ TCHAR classNameBuf[256];
+ ALF_BuildRandomClassName(TEXT("ALFComboBox."), classNameBuf);
+
+ cls.hInstance = app->hInstance;
+ cls.hCursor = LoadCursor(NULL, (LPTSTR)IDC_ARROW);
+ cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
+ cls.lpszClassName = classNameBuf;
+ cls.cbWndExtra = sizeof(void*)*2;
+ cls.lpfnWndProc = ALF__ComboWindowProc;
+
+ ATOM classatom = RegisterClass(&cls);
+ if (!classatom)
+ MessageBox(NULL, TEXT("FATAL: Could not register Combo class"), NULL, MB_OK);
+
+ app->comboClass = MAKEINTATOM(classatom);
+}
+
+static HWND
+ALF_InternalAddComboBox(HWND win, WORD id, UINT x, UINT y, DWORD style, const TCHAR *defaultText)
+{
+ ALFComboCreateParams cp;
+ cp.app = ALF_ApplicationFromWindow(win);
+ cp.comboStyle = style;
+
+ HWND hwndCombo = CreateWindowEx(WS_EX_CONTROLPARENT,
+ cp.app->comboClass,
+ TEXT(""),
+ WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
+ 0, 0, 0, 0,
+ win,
+ (HMENU)(int)id,
+ (HINSTANCE)GetWindowLongPtr(win, GWLP_HINSTANCE),
+ &cp);
+
+ if (defaultText)
+ SetWindowText(hwndCombo, defaultText);
+
+ ALFAddWidgetParams p;
+ ZeroMemory(&p, sizeof(p));
+ p.hwnd = hwndCombo;
+ p.x = x;
+ p.y = y;
+ p.width = 0;
+ p.height = 0;
+ p.flags = ALF_QUERYSIZE | ALF_MESSAGEFONT;
+
+ ALF_AddWidgetEx(win, &p);
+
+ return hwndCombo;
+}
+
+HWND
+ALF_AddEditableComboBox(HWND win, WORD id, UINT x, UINT y, const TCHAR *defaultText)
+{
+ return ALF_InternalAddComboBox(win, id, x, y, CBS_DROPDOWN, defaultText);
+}
+
+HWND
+ALF_AddSelectionOnlyComboBox(HWND win, WORD id, UINT x, UINT y)
+{
+ return ALF_InternalAddComboBox(win, id, x, y, CBS_DROPDOWNLIST, NULL);
+}
+
+int /* index */
+ALF_ComboBoxAddString(HWND combo, const TCHAR *text)
+{
+ return (int)SendMessage(combo, CB_ADDSTRING, 0, (LPARAM)text);
+}
+
diff --git a/alf/alfcompat.cpp b/alf/alfcompat.cpp
index e6a9851..269b9f4 100644
--- a/alf/alfcompat.cpp
+++ b/alf/alfcompat.cpp
@@ -123,3 +123,14 @@ ALF_CreateCompatFuncTable(void)
return compatfn;
}
+
+long
+ALF_GetAveCharWidth(HDC hdc)
+{
+ // see: HOWTO: Calculate Dialog Units When Not Using the System Font
+
+ SIZE s;
+ GetTextExtentPoint32A(hdc, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &s);
+
+ return (s.cx / 26 + 1) / 2;
+}
diff --git a/alf/alfcompat.h b/alf/alfcompat.h
index 8319dac..846590c 100644
--- a/alf/alfcompat.h
+++ b/alf/alfcompat.h
@@ -20,3 +20,5 @@ typedef struct {
ALFCompatFunctions *
ALF_CreateCompatFuncTable(void);
+long
+ALF_GetAveCharWidth(HDC hdc);
diff --git a/alf/alfpriv.h b/alf/alfpriv.h
index a398127..0d5be2f 100644
--- a/alf/alfpriv.h
+++ b/alf/alfpriv.h
@@ -61,7 +61,14 @@ typedef struct {
struct ALFAppPriv {
HINSTANCE hInstance;
ALFCompatFunctions *compatFn;
+ TCHAR *comboClass;
};
void
ALF_UpdateFontsPriv(HWND hwnd, ALFWindowPriv *priv);
+
+void
+ALF_RegisterComboClass(ALFAPP app);
+
+void
+ALF_BuildRandomClassName(const TCHAR *prefix, TCHAR *buf);