2015-08-31 09:55:33 -05:00
// 30 may 2015
2016-04-22 21:20:02 -05:00
# include "uipriv_windows.hpp"
// TODO refine error handling
2015-08-31 09:55:33 -05:00
// from http://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx
# define tabMargin 7
2016-04-27 11:41:30 -05:00
static void tabPageMargins ( struct tabPage * tp , int * mx , int * my )
{
uiWindowsSizing sizing ;
* mx = 0 ;
* my = 0 ;
if ( ! tp - > margined )
return ;
uiWindowsGetSizing ( tp - > hwnd , & sizing ) ;
* mx = tabMargin ;
* my = tabMargin ;
uiWindowsSizingDlgUnitsToPixels ( & sizing , mx , my ) ;
}
2016-04-29 16:08:31 -05:00
static void tabPageRelayout ( struct tabPage * tp )
2015-08-31 09:55:33 -05:00
{
2016-04-27 11:41:30 -05:00
RECT r ;
int mx , my ;
HWND child ;
if ( tp - > child = = NULL )
return ;
2016-04-28 15:59:26 -05:00
uiWindowsEnsureGetClientRect ( tp - > hwnd , & r ) ;
2016-04-27 11:41:30 -05:00
tabPageMargins ( tp , & mx , & my ) ;
r . left + = mx ;
2016-04-29 16:35:48 -05:00
r . top + = my ;
2016-04-29 16:41:17 -05:00
r . right - = mx ;
r . bottom - = my ;
2016-04-27 11:41:30 -05:00
child = ( HWND ) uiControlHandle ( tp - > child ) ;
uiWindowsEnsureMoveWindowDuringResize ( child , r . left , r . top , r . right - r . left , r . bottom - r . top ) ;
2015-08-31 09:55:33 -05:00
}
// dummy dialog procedure; see below for details
// let's handle parent messages here to avoid needing to subclass
2015-12-05 19:37:29 -06:00
// TODO do we need to handle DM_GETDEFID/DM_SETDEFID here too because of the ES_WANTRETURN stuff at http://blogs.msdn.com/b/oldnewthing/archive/2007/08/20/4470527.aspx? what about multiple default buttons (TODO)?
2015-12-06 13:38:13 -06:00
// TODO we definitely need to do something about edit message handling; it does a fake close of our parent on pressing escape, causing uiWindow to stop responding to maximizes but still respond to events and then die horribly on destruction
2015-08-31 09:55:33 -05:00
static INT_PTR CALLBACK dlgproc ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
2016-04-27 11:41:30 -05:00
struct tabPage * tp ;
2015-08-31 09:55:33 -05:00
LRESULT lResult ;
2016-04-27 11:41:30 -05:00
if ( uMsg = = WM_INITDIALOG ) {
tp = ( struct tabPage * ) lParam ;
tp - > hwnd = hwnd ;
2016-04-29 16:08:31 -05:00
SetWindowLongPtrW ( hwnd , DWLP_USER , ( LONG_PTR ) tp ) ;
2016-04-27 11:41:30 -05:00
return TRUE ;
}
2015-08-31 09:55:33 -05:00
if ( handleParentMessages ( hwnd , uMsg , wParam , lParam , & lResult ) ! = FALSE ) {
SetWindowLongPtrW ( hwnd , DWLP_MSGRESULT , ( LONG_PTR ) lResult ) ;
return TRUE ;
}
2016-04-27 11:41:30 -05:00
if ( uMsg = = WM_WINDOWPOSCHANGED ) {
2016-04-29 16:08:31 -05:00
tp = ( struct tabPage * ) GetWindowLongPtrW ( hwnd , DWLP_USER ) ;
2016-04-27 11:41:30 -05:00
tabPageRelayout ( tp ) ;
// pretend the dialog hasn't handled this just in case it needs to do something special
return FALSE ;
}
2015-08-31 09:55:33 -05:00
// unthemed dialogs don't respond to WM_PRINTCLIENT
// fortunately they don't have any special painting
if ( uMsg = = WM_PRINTCLIENT ) {
// 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
SendMessageW ( hwnd , WM_ERASEBKGND , wParam , lParam ) ;
// and pretend we did nothing just so the themed dialog can still paint its content
2016-04-22 21:20:02 -05:00
// TODO see if w ecan avoid erasing the background in this case in the first place, or if we even need to
2015-08-31 09:55:33 -05:00
return FALSE ;
}
2016-04-27 11:41:30 -05:00
2015-08-31 09:55:33 -05:00
return FALSE ;
}
2016-04-27 11:41:30 -05:00
struct tabPage * newTabPage ( uiControl * child )
2015-08-31 09:55:33 -05:00
{
2016-04-27 11:41:30 -05:00
struct tabPage * tp ;
2015-08-31 09:55:33 -05:00
HRESULT hr ;
2016-04-27 11:41:30 -05:00
tp = uiNew ( struct tabPage ) ;
2015-08-31 09:55:33 -05:00
// unfortunately this needs to be a proper dialog for EnableThemeDialogTexture() to work; CreateWindowExW() won't suffice
2016-04-27 11:41:30 -05:00
if ( CreateDialogParamW ( hInstance , MAKEINTRESOURCE ( rcTabPageDialog ) ,
2016-04-29 16:08:31 -05:00
utilWindow , dlgproc , ( LPARAM ) tp ) = = NULL )
2016-04-22 21:20:02 -05:00
logLastError ( L " error creating tab page " ) ;
2015-08-31 09:55:33 -05:00
2016-04-27 11:41:30 -05:00
tp - > child = child ;
2016-05-06 15:06:55 -05:00
if ( tp - > child ! = NULL ) {
uiWindowsEnsureSetParentHWND ( ( HWND ) uiControlHandle ( tp - > child ) , tp - > hwnd ) ;
uiWindowsControlAssignSoleControlIDZOrder ( uiWindowsControl ( tp - > child ) ) ;
}
2016-04-27 11:41:30 -05:00
hr = EnableThemeDialogTexture ( tp - > hwnd , ETDT_ENABLE | ETDT_USETABTEXTURE | ETDT_ENABLETAB ) ;
2015-08-31 09:55:33 -05:00
if ( hr ! = S_OK )
2016-04-22 21:20:02 -05:00
logHRESULT ( L " error setting tab page background " , hr ) ;
2016-04-27 11:41:30 -05:00
// continue anyway; it'll look wrong but eh
2015-08-31 09:55:33 -05:00
2015-09-01 10:46:53 -05:00
// and start the tab page hidden
2016-04-27 11:41:30 -05:00
ShowWindow ( tp - > hwnd , SW_HIDE ) ;
return tp ;
}
void tabPageDestroy ( struct tabPage * tp )
{
2016-04-27 13:21:05 -05:00
// don't destroy the child with the page
if ( tp - > child ! = NULL )
uiWindowsControlSetParentHWND ( uiWindowsControl ( tp - > child ) , NULL ) ;
2016-05-06 15:06:55 -05:00
// don't call EndDialog(); that's for the DialogBox() family of functions instead of CreateDialog()
2016-04-27 11:41:30 -05:00
uiWindowsEnsureDestroyWindow ( tp - > hwnd ) ;
uiFree ( tp ) ;
}
void tabPageMinimumSize ( struct tabPage * tp , intmax_t * width , intmax_t * height )
{
int mx , my ;
2015-09-01 10:46:53 -05:00
2016-04-27 11:41:30 -05:00
* width = 0 ;
* height = 0 ;
if ( tp - > child ! = NULL )
uiWindowsControlMinimumSize ( uiWindowsControl ( tp - > child ) , width , height ) ;
tabPageMargins ( tp , & mx , & my ) ;
* width + = 2 * mx ;
* height + = 2 * my ;
2015-08-31 09:55:33 -05:00
}