2015-08-30 17:38:22 -05:00
// 16 may 2015
2016-04-22 21:20:02 -05:00
# include "uipriv_windows.hpp"
2015-08-30 17:38:22 -05:00
struct uiGroup {
uiWindowsControl c ;
HWND hwnd ;
2016-04-28 21:33:32 -05:00
struct uiControl * child ;
2015-08-30 17:38:22 -05:00
int margined ;
} ;
// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
# define groupXMargin 6
2016-04-28 21:33:32 -05:00
# define groupYMarginTop 11 /* note this value /includes/ the groupbox label */
2015-08-30 17:38:22 -05:00
# define groupYMarginBottom 7
// unfortunately because the client area of a groupbox includes the frame and caption text, we have to apply some margins ourselves, even if we don't want "any"
// these were deduced by hand based on the standard DLU conversions; the X and Y top margins are the width and height, respectively, of one character cell
// they can be fine-tuned later
# define groupUnmarginedXMargin 4
# define groupUnmarginedYMarginTop 8
# define groupUnmarginedYMarginBottom 3
2016-04-28 21:33:32 -05:00
static void groupMargins ( uiGroup * g , int * mx , int * mtop , int * mbottom )
2015-08-30 17:38:22 -05:00
{
2016-04-28 21:33:32 -05:00
uiWindowsSizing sizing ;
int dummy ;
2015-08-30 17:38:22 -05:00
2016-04-28 21:33:32 -05:00
* mx = groupUnmarginedXMargin ;
* mtop = groupUnmarginedYMarginTop ;
* mbottom = groupUnmarginedYMarginBottom ;
dummy = 1 ; // for the bottom conversion
2015-08-30 17:38:22 -05:00
if ( g - > margined ) {
2016-04-28 21:33:32 -05:00
* mx = groupXMargin ;
* mtop = groupYMarginTop ;
* mbottom = groupYMarginBottom ;
2015-08-30 17:38:22 -05:00
}
2016-04-28 21:33:32 -05:00
uiWindowsControlGetSizing ( uiWindowsControl ( g ) , & sizing ) ;
uiWindowsSizingDlgUnitsToPixels ( & sizing , mx , mtop ) ;
uiWindowsSizingDlgUnitsToPixels ( & sizing , & dummy , mbottom ) ;
2015-08-30 17:38:22 -05:00
}
2016-04-28 21:33:32 -05:00
static void groupRelayout ( uiGroup * g )
2015-08-30 17:38:22 -05:00
{
2015-08-31 16:50:23 -05:00
uiGroup * g = uiGroup ( c ) ;
uiWindowsSizing * d ;
2015-08-30 17:38:22 -05:00
2016-04-23 21:23:07 -05:00
uiWindowsEnsureMoveWindowDuringResize ( g - > hwnd , x , y , width , height ) ;
2015-08-30 17:38:22 -05:00
if ( g - > child = = NULL )
return ;
2015-09-01 06:21:18 -05:00
d = uiWindowsNewSizing ( g - > hwnd ) ;
2015-09-02 20:29:16 -05:00
x = 0 ; // make relative to the top-left corner of the groupbox
y = 0 ;
2015-08-30 17:38:22 -05:00
if ( g - > margined ) {
x + = uiWindowsDlgUnitsToX ( groupXMargin , d - > BaseX ) ;
y + = uiWindowsDlgUnitsToY ( groupYMarginTop , d - > BaseY ) ;
width - = 2 * uiWindowsDlgUnitsToX ( groupXMargin , d - > BaseX ) ;
height - = uiWindowsDlgUnitsToY ( groupYMarginTop , d - > BaseY ) + uiWindowsDlgUnitsToY ( groupYMarginBottom , d - > BaseY ) ;
} else {
x + = uiWindowsDlgUnitsToX ( groupUnmarginedXMargin , d - > BaseX ) ;
y + = uiWindowsDlgUnitsToY ( groupUnmarginedYMarginTop , d - > BaseY ) ;
width - = 2 * uiWindowsDlgUnitsToX ( groupUnmarginedXMargin , d - > BaseX ) ;
height - = uiWindowsDlgUnitsToY ( groupUnmarginedYMarginTop , d - > BaseY ) + uiWindowsDlgUnitsToY ( groupUnmarginedYMarginBottom , d - > BaseY ) ;
}
uiWindowsFreeSizing ( d ) ;
childRelayout ( g - > child , x , y , width , height ) ;
}
2016-04-28 21:33:32 -05:00
static void uiGroupDestroy ( uiControl * c )
2015-08-30 17:38:22 -05:00
{
uiGroup * g = uiGroup ( c ) ;
2016-04-28 21:33:32 -05:00
if ( g - > child ! = NULL ) {
uiControlSetParent ( g - > child , NULL ) ;
uiControlDestroy ( g - > child ) ;
}
uiWindowsEnsureDestroyWindow ( g - > hwnd ) ;
uiFreeControl ( uiControl ( g ) ) ;
}
uiWindowsControlDefaultHandle ( uiGroup )
uiWindowsControlDefaultParent ( uiGroup )
uiWindowsControlDefaultSetParent ( uiGroup )
uiWindowsControlDefaultToplevel ( uiGroup )
uiWindowsControlDefaultVisible ( uiGroup )
uiWindowsControlDefaultShow ( uiGroup )
uiWindowsControlDefaultHide ( uiGroup )
uiWindowsControlDefaultEnabled ( uiGroup )
uiWindowsControlDefaultEnable ( uiGroup )
uiWindowsControlDefaultDisable ( uiGroup )
static void uiGroupSyncEnableState ( uiWindowsControl * c , int enabled )
{
uiGroup * g = uiGroup ( c ) ;
if ( uiWindowsShouldStopSyncEnableState ( uiWindowsControl ( g ) , enabled ) )
return ;
EnableWindow ( g - > hwnd , enabled ) ;
2015-08-30 17:38:22 -05:00
if ( g - > child ! = NULL )
2016-04-28 21:33:32 -05:00
uiWindowsControlSyncEnableState ( uiWindowsControl ( g - > child ) , enabled ) ;
2015-08-30 17:38:22 -05:00
}
2016-04-28 21:33:32 -05:00
uiWindowsControlDefaultSetParentHWND ( uiGroup )
static void uiGroupMinimumSize ( uiWindowsControl * c , intmax_t * width , intmax_t * height )
{
uiGroup * g = uiGroup ( c ) ;
int mx , mtop , mbottom ;
* width = 0 ;
* height = 0 ;
if ( g - > child ! = NULL )
uiWindowsControlMinimumSize ( uiWindowsControl ( g - > child ) , width , height ) ;
groupMargins ( g , & mx , & mtop , & mbottom ) ;
* width + = 2 * mx ;
* height + = mtop + mbottom ;
// TODO label width? and when?
}
static void uiGroupMinimumSizeChanged ( uiWindowsControl * c )
{
uiGroup * g = uiGroup ( c ) ;
if ( uiWindowsControlTooSmall ( uiWindowsControl ( g ) ) ) {
uiWindowsControlContinueMinimumSizeChanged ( uiWindowsControl ( g ) ) ;
return ;
}
groupRelayout ( g ) ;
}
uiWindowsControlDefaultLayoutRect ( uiGroup )
uiWindowsControlDefaultAssignControlIDZorder ( uiGroup )
2015-09-02 11:59:57 -05:00
static void groupArrangeChildrenControlIDsZOrder ( uiWindowsControl * c )
{
uiGroup * g = uiGroup ( c ) ;
if ( g - > child ! = NULL )
childSetSoleControlID ( g - > child ) ;
}
2015-08-30 17:38:22 -05:00
char * uiGroupTitle ( uiGroup * g )
{
2016-04-22 19:04:30 -05:00
return uiWindowsWindowText ( g - > hwnd ) ;
2015-08-30 17:38:22 -05:00
}
void uiGroupSetTitle ( uiGroup * g , const char * text )
{
2016-04-22 19:04:30 -05:00
uiWindowsSetWindowText ( g - > hwnd , text ) ;
2015-08-30 17:38:22 -05:00
// changing the text might necessitate a change in the groupbox's size
2016-04-29 11:20:41 -05:00
uiWindowsControlMinimumSizeChanged ( uiWindowsControl ( g ) ) ;
2015-08-30 17:38:22 -05:00
}
void uiGroupSetChild ( uiGroup * g , uiControl * child )
{
2015-09-02 08:18:49 -05:00
if ( g - > child ! = NULL ) {
2016-04-28 21:33:32 -05:00
uiControlSetParent ( g - > child , NULL ) ;
uiWindowsControlSetParentHWND ( uiWindowsControl ( g - > child ) , NULL ) ;
}
g - > child = child ;
if ( g - > child ! = NULL ) {
uiControlSetParent ( g - > child , uiControl ( g ) ) ;
uiWindowsControlSetParentHWND ( uiWindowsControl ( g - > child ) , g - > hwnd ) ;
uiWindowsControlAssignSoleControlIDZOrder ( uiWindowsControl ( g - > child ) ) ;
uiWindowsControlChildMinimumSizeChanged ( uiWindowsControl ( g ) ) ;
2015-09-02 08:18:49 -05:00
}
2015-08-30 17:38:22 -05:00
}
int uiGroupMargined ( uiGroup * g )
{
return g - > margined ;
}
void uiGroupSetMargined ( uiGroup * g , int margined )
{
g - > margined = margined ;
2016-04-28 21:33:32 -05:00
uiWindowsControlChildMinimumSizeChanged ( uiWindowsControl ( g ) ) ;
2015-08-30 17:38:22 -05:00
}
2015-09-01 15:10:29 -05:00
static LRESULT CALLBACK groupSubProc ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam , UINT_PTR uIdSubclass , DWORD_PTR dwRefData )
{
2016-04-28 21:33:32 -05:00
uiGroup * g = uiGroup ( dwRefData ) ;
2015-09-01 15:10:29 -05:00
LRESULT lResult ;
if ( handleParentMessages ( hwnd , uMsg , wParam , lParam , & lResult ) ! = FALSE )
return lResult ;
switch ( uMsg ) {
2016-04-28 21:33:32 -05:00
case WM_WINDOWPOSCHANGED :
// TODO check
// TODO add check in container.c
groupRelayout ( g ) ;
// TODO is this right?
break ;
// TODO WM_GETMINMAXINFO
2015-09-01 15:10:29 -05:00
case WM_NCDESTROY :
if ( RemoveWindowSubclass ( hwnd , groupSubProc , uIdSubclass ) = = FALSE )
2016-04-22 21:20:02 -05:00
logLastError ( L " error removing groupbox subclass " ) ;
2015-09-01 15:10:29 -05:00
break ;
}
return DefSubclassProc ( hwnd , uMsg , wParam , lParam ) ;
}
2015-08-30 17:38:22 -05:00
uiGroup * uiNewGroup ( const char * text )
{
uiGroup * g ;
WCHAR * wtext ;
2016-04-28 21:33:32 -05:00
uiWindowsNewControl ( uiGroup , g ) ;
2015-08-30 17:38:22 -05:00
wtext = toUTF16 ( text ) ;
2015-08-31 11:33:44 -05:00
g - > hwnd = uiWindowsEnsureCreateControlHWND ( WS_EX_CONTROLPARENT ,
2015-08-30 17:38:22 -05:00
L " button " , wtext ,
BS_GROUPBOX ,
hInstance , NULL ,
TRUE ) ;
uiFree ( wtext ) ;
2015-09-01 15:10:29 -05:00
if ( SetWindowSubclass ( g - > hwnd , groupSubProc , 0 , ( DWORD_PTR ) g ) = = FALSE )
2016-04-22 21:20:02 -05:00
logLastError ( L " error subclassing groupbox to handle parent messages " ) ;
2015-08-30 17:38:22 -05:00
return g ;
}