From 29393896e21cab201646352cce017992cf0b2ddb Mon Sep 17 00:00:00 2001 From: Jonas Kümmerlin Date: Sun, 7 Jul 2019 18:59:26 +0200 Subject: first notebook implementation --- alf/alf.cpp | 2 + alf/alf.h | 22 ++++ alf/alfnotebook.cpp | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++++ alf/alfpanel.cpp | 36 +++++-- alf/alfpriv.h | 7 ++ 5 files changed, 361 insertions(+), 10 deletions(-) create mode 100644 alf/alfnotebook.cpp (limited to 'alf') diff --git a/alf/alf.cpp b/alf/alf.cpp index 9120399..ecf2e7f 100644 --- a/alf/alf.cpp +++ b/alf/alf.cpp @@ -400,6 +400,7 @@ ALF_Initialize(void) ALF_RegisterPanelClass(); ALF_RegisterSpacerClass(); ALF_RegisterLabelClass(); + ALF_RegisterNotebookClass(); ALF_Compat_BufferedPaintInit(); } @@ -424,6 +425,7 @@ ALF_UnInitialize(void) UnregisterClass(_alf_panelClass, ALF_HINSTANCE); UnregisterClass(_alf_spacerClass, ALF_HINSTANCE); UnregisterClass(_alf_labelClass, ALF_HINSTANCE); + UnregisterClass(_alf_notebookClass, ALF_HINSTANCE); ALF_UnloadCompatFunctions(); } diff --git a/alf/alf.h b/alf/alf.h index d74553b..e30d360 100644 --- a/alf/alf.h +++ b/alf/alf.h @@ -282,6 +282,28 @@ ALF_AddPanel(HWND parent, WORD id, UINT x, UINT y); HWND ALF_AddSpacer(HWND parent, WORD id, UINT x, UINT y, UINT cptWidth, UINT cptHeight, DWORD layoutFlags); +// tab control +HWND +ALF_AddNotebook(HWND parent, WORD id, UINT x, UINT y); + +HWND +ALF_NotebookAddTab(HWND notebook, const TCHAR *title); + +int +ALF_NotebookTabCount(HWND notebook); + +int +ALF_NotebookTabIndex(HWND notebook, HWND tabPanel); + +int +ALF_NotebookSelectedIndex(HWND notebook); + +HWND +ALF_NotebookSelectedPanel(HWND notebook); + +HWND +ALF_NotebookTabPanel(HWND notebook, int index); + #ifdef __cplusplus } // extern C #endif diff --git a/alf/alfnotebook.cpp b/alf/alfnotebook.cpp new file mode 100644 index 0000000..82b2201 --- /dev/null +++ b/alf/alfnotebook.cpp @@ -0,0 +1,304 @@ +#include "alfpriv.h" +#include "alfcompat.h" + +#define ALF_NB_ADDTAB (ALF_WM__BASE + 200) +#define ALF_NB_TABCOUNT (ALF_WM__BASE + 201) +#define ALF_NB_GETPANEL (ALF_WM__BASE + 202) +#define ALF_NB_GETSELINDEX (ALF_WM__BASE + 203) +#define ALF_NB_GETPNLINDEX (ALF_WM__BASE + 204) + +TCHAR *_alf_notebookClass = NULL; + +static int +ALF_Notebook_InternalTabCount(HWND notebook, HWND tabControl) +{ + (void)notebook; + return TabCtrl_GetItemCount(tabControl); +} + +static HWND +ALF_Notebook_InternalTabPanel(HWND notebook, HWND tabControl, int index) +{ + (void)notebook; + + TCITEM tci; + ZeroMemory(&tci, sizeof(tci)); + + tci.mask = TCIF_PARAM; + + if (TabCtrl_GetItem(tabControl, index, &tci)) { + return (HWND)tci.lParam; + } else { + return NULL; + } +} + +static int +ALF_Notebook_InternalSelectedIndex(HWND notebook, HWND tabControl) +{ + (void)notebook; + + return TabCtrl_GetCurSel(tabControl); +} + + +static void +ALF_Notebook_InternalHandleTabChange(HWND hwndNotebook, HWND hwndTabCtrl) +{ + int selectedIndex = ALF_Notebook_InternalSelectedIndex(hwndNotebook, hwndTabCtrl); + int n = ALF_Notebook_InternalTabCount(hwndNotebook, hwndTabCtrl); + + for (int i = 0; i < n; ++i) { + if (i == selectedIndex) { + ShowWindow(ALF_Notebook_InternalTabPanel(hwndNotebook, hwndTabCtrl, i), SW_SHOW); + } else { + ShowWindow(ALF_Notebook_InternalTabPanel(hwndNotebook, hwndTabCtrl, i), SW_HIDE); + } + } +} + + +static HWND +ALF_Notebook_InternalAddTab(HWND notebook, HWND tabControl, const TCHAR *title) +{ + RECT r; + GetClientRect(tabControl, &r); + TabCtrl_AdjustRect(tabControl, FALSE, &r); + MapWindowRect(tabControl, notebook, &r); + + HWND hwndPanel = ALF_CreatePanelWindow(notebook, (WORD)-1); + SetWindowPos(hwndPanel, NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOOWNERZORDER); + + TCITEM tie; + ZeroMemory(&tie, sizeof(tie)); + + tie.mask = TCIF_TEXT | TCIF_PARAM; + tie.pszText = (TCHAR*)title; + tie.lParam = (LPARAM)hwndPanel; + + TabCtrl_InsertItem(tabControl, ALF_Notebook_InternalTabCount(notebook, tabControl), &tie); + ALF_Notebook_InternalHandleTabChange(notebook, tabControl); + + return hwndPanel; +} + + +static LRESULT CALLBACK +ALF_Notebook_TabCtrlSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + (void)uIdSubclass; + (void)dwRefData; + + if (uMsg == WM_ERASEBKGND) { + // see: http://www.virtualdub.org/blog/pivot/entry.php?id=291 + HDC hdc = (HDC)wParam; + + RECT r; + GetClientRect(hwnd, &r); + TabCtrl_AdjustRect(hwnd, FALSE, &r); + + ExcludeClipRect(hdc, r.left, r.top, r.right, r.bottom); + } + if (uMsg == 0x2000 + WM_NOTIFY) { + NMHDR *pnmh = (NMHDR*)lParam; + if (pnmh->code == TCN_SELCHANGE) { + ALF_Notebook_InternalHandleTabChange(GetParent(hwnd), hwnd); + + return TRUE; + } + } + if (uMsg == WM_DESTROY) { + ALF_Compat_RemoveWindowSubclass(hwnd, ALF_Notebook_TabCtrlSubclassProc, 0); + } + + return ALF_Compat_DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +static LRESULT CALLBACK +ALF__NotebookWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (ALF_ShouldMessageBubble(hwnd, uMsg, wParam, lParam)) + return SendMessage(GetParent(hwnd), uMsg, wParam, lParam); + + HWND hwndTabCtrl = (HWND)GetWindowLongPtr(hwnd, 0); + + if (uMsg == WM_CREATE) { + hwndTabCtrl = CreateWindowEx(0, + WC_TABCONTROL, + TEXT(""), + WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS, + 0, 0, 100, 100, + hwnd, + NULL, + ALF_HINSTANCE, + NULL); + + ALF_Compat_SetWindowSubclass(hwndTabCtrl, ALF_Notebook_TabCtrlSubclassProc, 0, 0); + + SetWindowLongPtr(hwnd, 0, (LONG_PTR)hwndTabCtrl); + } else if (uMsg == ALF_WM_APPLYFONTS) { + int n = ALF_Notebook_InternalTabCount(hwnd, hwndTabCtrl); + for (int i = 0; i < n; ++i) { + HWND p = ALF_Notebook_InternalTabPanel(hwnd, hwndTabCtrl, i); + SendMessage(p, ALF_WM_APPLYFONTS, wParam, lParam); + } + + return TRUE; + } else if (uMsg == WM_SETFONT) { + SendMessage(hwndTabCtrl, WM_SETFONT, wParam, lParam); + } else if (uMsg == ALF_WM_QUERYSIZE) { + int n = ALF_Notebook_InternalTabCount(hwnd, hwndTabCtrl); + RECT r = { 0, 0, 0, 0 }; + for (int i = 0; i < n; ++i) { + HWND p = ALF_Notebook_InternalTabPanel(hwnd, hwndTabCtrl, i); + SIZE s = { 0, 0 }; + SendMessage(p, ALF_WM_QUERYSIZE, 0, (LPARAM)&s); + if (s.cx > r.right) + r.right = s.cx; + if (s.cy > r.bottom) + r.bottom = s.cy; + } + + if (!r.right) + r.right = 100; // FIXME! + if (!r.bottom) + r.bottom = 100; // FIXME! + + TabCtrl_AdjustRect(hwndTabCtrl, TRUE, &r); + + SIZE *ps = (SIZE*)lParam; + if (!ps->cx) { + ps->cx = r.right - r.left; + } + + if (!ps->cy) { + ps->cy = r.bottom - r.top; + } + + return 0; + } else if (uMsg == WM_WINDOWPOSCHANGED) { + WINDOWPOS *pos = (WINDOWPOS *)lParam; + if (!(pos->flags & SWP_NOSIZE)) { + RECT r; + GetClientRect(hwnd, &r); + MoveWindow(hwndTabCtrl, 0, 0, r.right - r.left, r.bottom - r.top, FALSE); + + GetClientRect(hwndTabCtrl, &r); + TabCtrl_AdjustRect(hwndTabCtrl, FALSE, &r); + MapWindowRect(hwndTabCtrl, hwnd, &r); + + int n = ALF_Notebook_InternalTabCount(hwnd, hwndTabCtrl); + for (int i = 0; i < n; ++i) { + HWND p = ALF_Notebook_InternalTabPanel(hwnd, hwndTabCtrl, i); + + MoveWindow(p, r.left, r.top, r.right - r.left, r.bottom - r.top, FALSE); + } + + InvalidateRect(hwnd, NULL, TRUE); + } + } else if (uMsg == ALF_NB_ADDTAB) { + return (LRESULT)ALF_Notebook_InternalAddTab(hwnd, hwndTabCtrl, (TCHAR *)lParam); + } else if (uMsg == ALF_NB_TABCOUNT) { + return (LRESULT)ALF_Notebook_InternalTabCount(hwnd, hwndTabCtrl); + } else if (uMsg == ALF_NB_GETPANEL) { + return (LRESULT)ALF_Notebook_InternalTabPanel(hwnd, hwndTabCtrl, (int)lParam); + } else if (uMsg == ALF_NB_GETSELINDEX) { + return (LRESULT)ALF_Notebook_InternalSelectedIndex(hwnd, hwndTabCtrl); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +void +ALF_RegisterNotebookClass(void) +{ + WNDCLASS cls; + ZeroMemory(&cls, sizeof(cls)); + + TCHAR classNameBuf[256]; + ALF_BuildUniqueName(classNameBuf, TEXT("ALFNotebook."), (ULONG_PTR)&_alf_notebookClass); + + 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(HWND); + cls.lpfnWndProc = ALF__NotebookWindowProc; + + ATOM classatom = RegisterClass(&cls); + if (!classatom) + MessageBox(NULL, TEXT("FATAL: Could not register notebook class"), NULL, MB_OK); + + _alf_notebookClass = MAKEINTATOM(classatom); +} + +// tab control +HWND +ALF_AddNotebook(HWND parent, WORD id, UINT x, UINT y) +{ + HWND hwndNtbk = CreateWindowEx(WS_EX_CONTROLPARENT, + _alf_notebookClass, + TEXT(""), + WS_CHILD | WS_VISIBLE, + 0, 0, 100, 100, + parent, + (HMENU)(int)id, + ALF_HINSTANCE, + NULL); + + ALFWidgetLayoutParams p; + ZeroMemory(&p, sizeof(p)); + p.hwnd = hwndNtbk; + p.x = x; + p.y = y; + p.width = 0; + p.height = 0; + p.flags = ALF_QUERYSIZE | ALF_MESSAGEFONT | ALF_SENDAPPLYFONTS; + + ALF_AddWidgetEx(parent, &p); + + return hwndNtbk; +} + +HWND +ALF_NotebookAddTab(HWND notebook, const TCHAR *title) +{ + return (HWND)SendMessage(notebook, ALF_NB_ADDTAB, 0, (LPARAM)title); +} + +int +ALF_NotebookTabCount(HWND notebook) +{ + return (int)SendMessage(notebook, ALF_NB_TABCOUNT, 0, 0); +} + +int +ALF_NotebookTabIndex(HWND notebook, HWND tabPanel); + +HWND +ALF_NotebookTabPanel(HWND notebook, int index) +{ + return (HWND)SendMessage(notebook, ALF_NB_GETPANEL, 0, (WPARAM)index); +} + +int +ALF_NotebookSelectedIndex(HWND notebook) +{ + return (int)SendMessage(notebook, ALF_NB_GETSELINDEX, 0, 0); +} + +HWND +ALF_NotebookSelectedPanel(HWND notebook) +{ + int i = ALF_NotebookSelectedIndex(notebook); + if (i >= 0) { + return ALF_NotebookTabPanel(notebook, i); + } else { + return NULL; + } +} diff --git a/alf/alfpanel.cpp b/alf/alfpanel.cpp index 5a18976..8583d2e 100644 --- a/alf/alfpanel.cpp +++ b/alf/alfpanel.cpp @@ -37,6 +37,16 @@ ALF__PanelWindowProc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) SetWindowLongPtr(window, 0, 0); } + if (msg == WM_ERASEBKGND) { + HDC hdc = (HDC)wparam; + + RECT r = { 0, 0, 0, 0 }; + GetClientRect(window, &r); + ALF_Compat_DrawThemeParentBackground(window, hdc, &r); + + return TRUE; + } + if (ALF_ShouldMessageBubble(window, msg, wparam, lparam)) return SendMessage(GetParent(window), msg, wparam, lparam); @@ -74,23 +84,29 @@ ALF_RegisterPanelClass(void) ATOM classatom = RegisterClass(&cls); if (!classatom) - MessageBox(NULL, TEXT("FATAL: Could not register Combo class"), NULL, MB_OK); + MessageBox(NULL, TEXT("FATAL: Could not register panel class"), NULL, MB_OK); _alf_panelClass = MAKEINTATOM(classatom); } +HWND +ALF_CreatePanelWindow(HWND parent, WORD id) +{ + return CreateWindowEx(WS_EX_CONTROLPARENT, + _alf_panelClass, + TEXT(""), + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, + 0, 0, 0, 0, + parent, + (HMENU)(int)id, + ALF_HINSTANCE, + NULL); +} + HWND ALF_AddPanel(HWND parent, WORD id, UINT x, UINT y) { - HWND hwndPanel = CreateWindowEx(WS_EX_CONTROLPARENT, - _alf_panelClass, - TEXT(""), - WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, - 0, 0, 0, 0, - parent, - (HMENU)(int)id, - ALF_HINSTANCE, - NULL); + HWND hwndPanel = ALF_CreatePanelWindow(parent, id); ALFWidgetLayoutParams p; ZeroMemory(&p, sizeof(p)); diff --git a/alf/alfpriv.h b/alf/alfpriv.h index 3d0f092..4bccebc 100644 --- a/alf/alfpriv.h +++ b/alf/alfpriv.h @@ -31,6 +31,7 @@ extern TCHAR *_alf_comboClass; extern TCHAR *_alf_panelClass; extern TCHAR *_alf_spacerClass; extern TCHAR *_alf_labelClass; +extern TCHAR *_alf_notebookClass; int ALF_CentipointsToPxPriv(ALFWindowPriv *priv, int cptValue); @@ -56,6 +57,12 @@ ALF_RegisterSpacerClass(void); void ALF_RegisterLabelClass(void); +void +ALF_RegisterNotebookClass(void); + +HWND +ALF_CreatePanelWindow(HWND parent, WORD id); + void ALF_BuildUniqueName(TCHAR *buf, const TCHAR *prefix, ULONG_PTR uniquifier); -- cgit v1.2.3