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 ;
2015-08-30 17:38:22 -05:00
2016-04-28 21:33:32 -05:00
* mx = groupUnmarginedXMargin ;
* mtop = groupUnmarginedYMarginTop ;
* mbottom = groupUnmarginedYMarginBottom ;
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-29 16:08:31 -05:00
uiWindowsGetSizing ( g - > hwnd , & sizing ) ;
2016-04-28 21:33:32 -05:00
uiWindowsSizingDlgUnitsToPixels ( & sizing , mx , mtop ) ;
2016-04-29 16:08:31 -05:00
uiWindowsSizingDlgUnitsToPixels ( & sizing , NULL , 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
{
2016-04-29 16:08:31 -05:00
RECT r ;
int mx , mtop , mbottom ;
2015-08-30 17:38:22 -05:00
if ( g - > child = = NULL )
return ;
2016-04-29 16:08:31 -05:00
uiWindowsEnsureGetClientRect ( g - > hwnd , & r ) ;
groupMargins ( g , & mx , & mtop , & mbottom ) ;
r . left + = mx ;
r . top + = mtop ;
r . right - = mx ;
r . bottom - = mbottom ;
uiWindowsEnsureMoveWindowDuringResize ( ( HWND ) uiControlHandle ( g - > child ) , r . left , r . top , r . right - r . left , r . bottom - r . top ) ;
2015-08-30 17:38:22 -05:00
}
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 ;
2016-05-29 18:55:53 -05:00
intmax_t labelWidth ;
2016-04-28 21:33:32 -05:00
* width = 0 ;
* height = 0 ;
if ( g - > child ! = NULL )
uiWindowsControlMinimumSize ( uiWindowsControl ( g - > child ) , width , height ) ;
2016-05-29 18:55:53 -05:00
labelWidth = uiWindowsWindowTextWidth ( g - > hwnd ) ;
if ( * width < labelWidth ) // don't clip the label; it doesn't ellipsize
* width = labelWidth ;
2016-04-28 21:33:32 -05:00
groupMargins ( g , & mx , & mtop , & mbottom ) ;
* width + = 2 * mx ;
* height + = mtop + mbottom ;
}
static void uiGroupMinimumSizeChanged ( uiWindowsControl * c )
{
uiGroup * g = uiGroup ( c ) ;
if ( uiWindowsControlTooSmall ( uiWindowsControl ( g ) ) ) {
uiWindowsControlContinueMinimumSizeChanged ( uiWindowsControl ( g ) ) ;
return ;
}
groupRelayout ( g ) ;
}
uiWindowsControlDefaultLayoutRect ( uiGroup )
2016-04-29 16:08:31 -05:00
uiWindowsControlDefaultAssignControlIDZOrder ( uiGroup )
2015-09-02 11:59:57 -05:00
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 ) ) ;
2016-04-29 16:08:31 -05:00
uiWindowsControlMinimumSizeChanged ( 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-29 16:08:31 -05:00
uiWindowsControlMinimumSizeChanged ( 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 ) ;
2016-05-29 18:55:53 -05:00
WINDOWPOS * wp = ( WINDOWPOS * ) lParam ;
MINMAXINFO * mmi = ( MINMAXINFO * ) lParam ;
intmax_t minwid , minht ;
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 :
2016-05-29 18:55:53 -05:00
if ( ( wp - > flags & SWP_NOSIZE ) ! = 0 )
break ;
2016-04-28 21:33:32 -05:00
groupRelayout ( g ) ;
2016-05-29 18:55:53 -05:00
return 0 ;
case WM_GETMINMAXINFO :
lResult = DefWindowProcW ( hwnd , uMsg , wParam , lParam ) ;
uiWindowsControlMinimumSize ( uiWindowsControl ( g ) , & minwid , & minht ) ;
mmi - > ptMinTrackSize . x = minwid ;
mmi - > ptMinTrackSize . y = minht ;
return lResult ;
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 ;
}