2015-05-30 11:28:52 -05:00
|
|
|
// 30 may 2015
|
2015-05-30 11:34:39 -05:00
|
|
|
#include "uipriv_windows.h"
|
2015-05-30 11:28:52 -05:00
|
|
|
|
|
|
|
// This is a special internal control type that handles tab pages.
|
|
|
|
// This doesn't use the container class, but rather a subclassed WC_DIALOG, as that supports tab textures properly.
|
2015-06-01 18:12:54 -05:00
|
|
|
// The standard property sheet control does the same thing.
|
2015-05-30 14:03:04 -05:00
|
|
|
|
2015-05-30 11:28:52 -05:00
|
|
|
struct tabPage {
|
|
|
|
uiControl c;
|
|
|
|
HWND hwnd;
|
2015-06-01 16:37:43 -05:00
|
|
|
uiControl *child;
|
2015-05-30 11:28:52 -05:00
|
|
|
int margined;
|
2015-05-30 12:15:43 -05:00
|
|
|
void (*baseResize)(uiControl *, intmax_t, intmax_t, intmax_t, intmax_t, uiSizing *);
|
2015-05-30 11:28:52 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
uiDefineControlType(tabPage, tabPageType, struct tabPage)
|
|
|
|
|
2015-06-01 16:21:21 -05:00
|
|
|
// don't override CommitDestroy(); we destroy the child with a separate function
|
2015-05-30 11:28:52 -05:00
|
|
|
|
|
|
|
static uintptr_t tabPageHandle(uiControl *c)
|
|
|
|
{
|
|
|
|
struct tabPage *t = (struct tabPage *) c;
|
|
|
|
|
|
|
|
return (uintptr_t) (t->hwnd);
|
|
|
|
}
|
|
|
|
|
2015-05-30 12:15:43 -05:00
|
|
|
// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx
|
|
|
|
#define tabMargin 7
|
|
|
|
|
2015-06-01 18:07:00 -05:00
|
|
|
static void tabPagePreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height)
|
|
|
|
{
|
|
|
|
struct tabPage *t = (struct tabPage *) c;
|
|
|
|
|
|
|
|
*width = 0;
|
|
|
|
*height = 0;
|
|
|
|
if (t->child != NULL)
|
|
|
|
uiControlPreferredSize(t->child, d, width, height);
|
|
|
|
if (t->margined) {
|
|
|
|
*width += 2 * uiWindowsDlgUnitsToX(tabMargin, d->Sys->BaseX);
|
|
|
|
*height += 2 * uiWindowsDlgUnitsToY(tabMargin, d->Sys->BaseY);
|
|
|
|
}
|
|
|
|
}
|
2015-06-01 16:21:21 -05:00
|
|
|
|
2015-05-30 12:15:43 -05:00
|
|
|
static void tabPageResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d)
|
|
|
|
{
|
|
|
|
struct tabPage *t = (struct tabPage *) c;
|
|
|
|
RECT r;
|
|
|
|
uiSizing *dchild;
|
|
|
|
|
|
|
|
(*(t->baseResize))(uiControl(t), x, y, width, height, d);
|
|
|
|
|
2015-06-01 19:12:55 -05:00
|
|
|
if (t->child == NULL)
|
|
|
|
return;
|
|
|
|
|
2015-05-30 12:32:59 -05:00
|
|
|
dchild = uiControlSizing(uiControl(t));
|
|
|
|
|
2015-05-30 12:15:43 -05:00
|
|
|
if (GetClientRect(t->hwnd, &r) == 0)
|
|
|
|
logLastError("error getting tab page client rect in tabPageResize()");
|
|
|
|
if (t->margined) {
|
|
|
|
r.left += uiWindowsDlgUnitsToX(tabMargin, d->Sys->BaseX);
|
|
|
|
r.top += uiWindowsDlgUnitsToY(tabMargin, d->Sys->BaseY);
|
|
|
|
r.right -= uiWindowsDlgUnitsToX(tabMargin, d->Sys->BaseX);
|
|
|
|
r.bottom -= uiWindowsDlgUnitsToY(tabMargin, d->Sys->BaseY);
|
|
|
|
}
|
2015-05-30 12:32:59 -05:00
|
|
|
// this rect is in client coordinates; we need toplevel window coordinates
|
|
|
|
mapWindowRect(t->hwnd, dchild->Sys->CoordFrom, &r);
|
|
|
|
|
2015-06-01 16:37:43 -05:00
|
|
|
uiControlResize(t->child, r.left, r.top, r.right - r.left, r.bottom - r.top, dchild);
|
2015-05-30 12:15:43 -05:00
|
|
|
|
|
|
|
uiFreeSizing(dchild);
|
|
|
|
}
|
|
|
|
|
2015-06-01 18:07:00 -05:00
|
|
|
static void tabPageContainerUpdateState(uiControl *c)
|
|
|
|
{
|
|
|
|
struct tabPage *t = (struct tabPage *) c;
|
|
|
|
|
|
|
|
if (t->child != NULL)
|
|
|
|
uiControlUpdateState(t->child);
|
|
|
|
}
|
2015-06-01 16:21:21 -05:00
|
|
|
|
2015-06-01 18:27:28 -05:00
|
|
|
// dummy dialog procedure; see below for details
|
|
|
|
// let's handle parent messages here to avoid needing to subclass
|
2015-06-01 18:07:00 -05:00
|
|
|
static INT_PTR CALLBACK dlgproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
2015-05-30 14:01:21 -05:00
|
|
|
{
|
2015-06-01 18:27:28 -05:00
|
|
|
LRESULT lResult;
|
|
|
|
|
|
|
|
if (handleParentMessages(hwnd, uMsg, wParam, lParam, &lResult) != FALSE) {
|
|
|
|
SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (LONG_PTR) lResult);
|
|
|
|
return TRUE;
|
|
|
|
}
|
2015-06-07 19:36:03 -05:00
|
|
|
// unthemed dialogs don't respond to WM_PRINTCLIENT
|
|
|
|
// fortunately they don't have any special painting
|
|
|
|
if (uMsg == WM_PRINTCLIENT) {
|
2015-06-07 21:06:41 -05:00
|
|
|
// don't worry about the return value; hopefully DefWindowProcW() caught it (if not the dialog procedure itself)
|
|
|
|
// we COULD paint the dialog background brush ourselves but meh, it works
|
2015-06-07 19:36:03 -05:00
|
|
|
SendMessageW(hwnd, WM_ERASEBKGND, wParam, lParam);
|
|
|
|
// and pretend we did nothing just so the themed dialog can still paint its content
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-05-30 14:01:21 -05:00
|
|
|
if (uMsg == WM_INITDIALOG)
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2015-06-01 19:12:55 -05:00
|
|
|
uiControl *newTabPage(void)
|
2015-05-30 11:28:52 -05:00
|
|
|
{
|
|
|
|
struct tabPage *t;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
t = (struct tabPage *) uiWindowsNewSingleHWNDControl(tabPageType());
|
|
|
|
|
2015-05-30 14:01:21 -05:00
|
|
|
// unfortunately this needs to be a proper dialog for EnableThemeDialogTexture() to work; CreateWindowExW() won't suffice
|
|
|
|
t->hwnd = CreateDialogW(hInstance, MAKEINTRESOURCE(rcTabPageDialog),
|
|
|
|
utilWindow, dlgproc);
|
|
|
|
if (t->hwnd == NULL)
|
|
|
|
logLastError("error creating tab page in newTabPage()");
|
2015-05-30 11:28:52 -05:00
|
|
|
|
|
|
|
hr = EnableThemeDialogTexture(t->hwnd, ETDT_ENABLE | ETDT_USETABTEXTURE | ETDT_ENABLETAB);
|
|
|
|
if (hr != S_OK)
|
|
|
|
logHRESULT("error setting tab page background in newTabPage()", hr);
|
|
|
|
|
2015-05-30 11:34:39 -05:00
|
|
|
uiControl(t)->Handle = tabPageHandle;
|
2015-06-01 18:07:00 -05:00
|
|
|
uiControl(t)->PreferredSize = tabPagePreferredSize;
|
2015-05-30 12:15:43 -05:00
|
|
|
t->baseResize = uiControl(t)->Resize;
|
|
|
|
uiControl(t)->Resize = tabPageResize;
|
2015-06-01 18:07:00 -05:00
|
|
|
uiControl(t)->ContainerUpdateState = tabPageContainerUpdateState;
|
2015-05-30 12:15:43 -05:00
|
|
|
|
2015-05-30 11:28:52 -05:00
|
|
|
return uiControl(t);
|
|
|
|
}
|
2015-05-31 09:53:20 -05:00
|
|
|
|
|
|
|
int tabPageMargined(uiControl *c)
|
|
|
|
{
|
|
|
|
struct tabPage *t = (struct tabPage *) c;
|
|
|
|
|
|
|
|
return t->margined;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tabPageSetMargined(uiControl *c, int margined)
|
|
|
|
{
|
|
|
|
struct tabPage *t = (struct tabPage *) c;
|
|
|
|
|
|
|
|
t->margined = margined;
|
|
|
|
}
|
2015-06-01 16:37:43 -05:00
|
|
|
|
|
|
|
void tabPageDestroyChild(uiControl *c)
|
|
|
|
{
|
|
|
|
struct tabPage *t = (struct tabPage *) c;
|
|
|
|
|
|
|
|
uiControlSetParent(t->child, NULL);
|
|
|
|
uiControlDestroy(t->child);
|
2015-06-01 18:09:13 -05:00
|
|
|
t->child = NULL;
|
2015-06-01 16:37:43 -05:00
|
|
|
}
|
2015-06-01 19:12:55 -05:00
|
|
|
|
2015-06-01 20:14:30 -05:00
|
|
|
void tabPagePreserveChild(uiControl *c)
|
|
|
|
{
|
|
|
|
struct tabPage *t = (struct tabPage *) c;
|
|
|
|
|
|
|
|
uiControlSetParent(t->child, NULL);
|
|
|
|
t->child = NULL;
|
|
|
|
}
|
|
|
|
|
2015-06-01 19:12:55 -05:00
|
|
|
void tabPageSetChild(uiControl *c, uiControl *child)
|
|
|
|
{
|
|
|
|
struct tabPage *t = (struct tabPage *) c;
|
|
|
|
|
|
|
|
t->child = child;
|
|
|
|
t->child = child;
|
|
|
|
uiControlSetParent(t->child, uiControl(t));
|
|
|
|
}
|