2016-06-08 22:33:32 -05:00
// 8 june 2016
# include "uipriv_windows.hpp"
struct formChild {
uiControl * c ;
HWND label ;
int stretchy ;
2016-06-13 20:54:15 -05:00
int height ;
2016-06-08 22:33:32 -05:00
} ;
struct uiForm {
uiWindowsControl c ;
HWND hwnd ;
std : : vector < struct formChild > * controls ;
int padded ;
} ;
static void formPadding ( uiForm * f , int * xpadding , int * ypadding )
{
uiWindowsSizing sizing ;
* xpadding = 0 ;
* ypadding = 0 ;
if ( f - > padded ) {
uiWindowsGetSizing ( f - > hwnd , & sizing ) ;
uiWindowsSizingStandardPadding ( & sizing , xpadding , ypadding ) ;
}
}
// via http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing
# define labelHeight 8
# define labelYOffset 3
static void formRelayout ( uiForm * f )
{
RECT r ;
2016-06-13 20:54:15 -05:00
int x , y , width , height ;
2016-06-08 22:33:32 -05:00
int xpadding , ypadding ;
2016-06-13 20:54:15 -05:00
int nStretchy ;
int labelwid , stretchyht ;
int thiswid ;
int i ;
int minimumWidth , minimumHeight ;
2016-06-08 22:33:32 -05:00
uiWindowsSizing sizing ;
int labelht , labelyoff ;
2016-06-14 17:12:30 -05:00
int nVisible ;
2016-06-08 22:33:32 -05:00
if ( f - > controls - > size ( ) = = 0 )
return ;
uiWindowsEnsureGetClientRect ( f - > hwnd , & r ) ;
x = r . left ;
y = r . top ;
width = r . right - r . left ;
height = r . bottom - r . top ;
2016-06-14 17:12:30 -05:00
// 0) get this Form's padding
2016-06-08 22:33:32 -05:00
formPadding ( f , & xpadding , & ypadding ) ;
// 1) get width of labels and height of non-stretchy controls
// this will tell us how much space will be left for controls
labelwid = 0 ;
stretchyht = height ;
nStretchy = 0 ;
2016-06-14 17:12:30 -05:00
nVisible = 0 ;
2016-06-08 22:33:32 -05:00
for ( struct formChild & fc : * ( f - > controls ) ) {
2016-06-14 17:12:30 -05:00
if ( ! uiControlVisible ( fc . c ) ) {
ShowWindow ( fc . label , SW_HIDE ) ;
2016-06-08 22:33:32 -05:00
continue ;
2016-06-14 17:12:30 -05:00
}
ShowWindow ( fc . label , SW_SHOW ) ;
nVisible + + ;
2016-06-08 22:33:32 -05:00
thiswid = uiWindowsWindowTextWidth ( fc . label ) ;
if ( labelwid < thiswid )
labelwid = thiswid ;
if ( fc . stretchy ) {
nStretchy + + ;
continue ;
}
uiWindowsControlMinimumSize ( uiWindowsControl ( fc . c ) , & minimumWidth , & minimumHeight ) ;
fc . height = minimumHeight ;
stretchyht - = minimumHeight ;
}
2016-06-14 17:12:30 -05:00
if ( nVisible = = 0 ) // nothing to do
return ;
2016-06-08 22:33:32 -05:00
2016-06-14 17:12:30 -05:00
// 2) inset the available rect by the needed padding
width - = xpadding ;
height - = ( nVisible - 1 ) * ypadding ;
stretchyht - = ( nVisible - 1 ) * ypadding ;
// 3) now get the width of controls and the height of stretchy controls
2016-06-08 22:33:32 -05:00
width - = labelwid ;
if ( nStretchy ! = 0 ) {
stretchyht / = nStretchy ;
for ( struct formChild & fc : * ( f - > controls ) ) {
if ( ! uiControlVisible ( fc . c ) )
continue ;
if ( fc . stretchy )
fc . height = stretchyht ;
}
}
2016-06-14 17:12:30 -05:00
// 4) get the y offset
2016-06-08 22:33:32 -05:00
labelyoff = labelYOffset ;
uiWindowsGetSizing ( f - > hwnd , & sizing ) ;
uiWindowsSizingDlgUnitsToPixels ( & sizing , NULL , & labelyoff ) ;
2016-06-14 17:12:30 -05:00
// 5) now we can position controls
2016-06-08 22:33:32 -05:00
// first, make relative to the top-left corner of the container
// also prefer left alignment on Windows
x = labelwid + xpadding ;
y = 0 ;
for ( const struct formChild & fc : * ( f - > controls ) ) {
if ( ! uiControlVisible ( fc . c ) )
continue ;
labelht = labelHeight ;
uiWindowsGetSizing ( f - > hwnd , & sizing ) ;
uiWindowsSizingDlgUnitsToPixels ( & sizing , NULL , & labelht ) ;
uiWindowsEnsureMoveWindowDuringResize ( fc . label , 0 , y + labelyoff - sizing . InternalLeading , labelwid , labelht ) ;
uiWindowsEnsureMoveWindowDuringResize ( ( HWND ) uiControlHandle ( fc . c ) , x , y , width , fc . height ) ;
y + = fc . height + ypadding ;
}
}
static void uiFormDestroy ( uiControl * c )
{
uiForm * f = uiForm ( c ) ;
for ( const struct formChild & fc : * ( f - > controls ) ) {
uiControlSetParent ( fc . c , NULL ) ;
uiControlDestroy ( fc . c ) ;
uiWindowsEnsureDestroyWindow ( fc . label ) ;
}
delete f - > controls ;
uiWindowsEnsureDestroyWindow ( f - > hwnd ) ;
uiFreeControl ( uiControl ( f ) ) ;
}
uiWindowsControlDefaultHandle ( uiForm )
uiWindowsControlDefaultParent ( uiForm )
uiWindowsControlDefaultSetParent ( uiForm )
uiWindowsControlDefaultToplevel ( uiForm )
uiWindowsControlDefaultVisible ( uiForm )
uiWindowsControlDefaultShow ( uiForm )
uiWindowsControlDefaultHide ( uiForm )
uiWindowsControlDefaultEnabled ( uiForm )
uiWindowsControlDefaultEnable ( uiForm )
uiWindowsControlDefaultDisable ( uiForm )
static void uiFormSyncEnableState ( uiWindowsControl * c , int enabled )
{
uiForm * f = uiForm ( c ) ;
if ( uiWindowsShouldStopSyncEnableState ( uiWindowsControl ( f ) , enabled ) )
return ;
for ( const struct formChild & fc : * ( f - > controls ) )
uiWindowsControlSyncEnableState ( uiWindowsControl ( fc . c ) , enabled ) ;
}
uiWindowsControlDefaultSetParentHWND ( uiForm )
2016-06-13 20:54:15 -05:00
static void uiFormMinimumSize ( uiWindowsControl * c , int * width , int * height )
2016-06-08 22:33:32 -05:00
{
uiForm * f = uiForm ( c ) ;
int xpadding , ypadding ;
2016-06-13 20:54:15 -05:00
int nStretchy ;
2016-06-08 22:33:32 -05:00
// these two contain the largest minimum width and height of all stretchy controls in the form
// all stretchy controls will use this value to determine the final minimum size
2016-06-13 20:54:15 -05:00
int maxLabelWidth , maxControlWidth ;
int maxStretchyHeight ;
int labelwid ;
int i ;
int minimumWidth , minimumHeight ;
2016-06-14 17:12:30 -05:00
int nVisible ;
2016-06-08 22:33:32 -05:00
uiWindowsSizing sizing ;
* width = 0 ;
* height = 0 ;
if ( f - > controls - > size ( ) = = 0 )
return ;
// 0) get this Form's padding
formPadding ( f , & xpadding , & ypadding ) ;
2016-06-14 17:12:30 -05:00
// 1) determine the longest width of all controls and labels; add in the height of non-stretchy controls and get (but not add in) the largest heights of stretchy controls
2016-06-08 22:33:32 -05:00
// we still add in like direction of stretchy controls
nStretchy = 0 ;
maxLabelWidth = 0 ;
maxControlWidth = 0 ;
maxStretchyHeight = 0 ;
2016-06-14 17:12:30 -05:00
nVisible = 0 ;
2016-06-08 22:33:32 -05:00
for ( const struct formChild & fc : * ( f - > controls ) ) {
if ( ! uiControlVisible ( fc . c ) )
continue ;
2016-06-14 17:12:30 -05:00
nVisible + + ;
2016-06-08 22:33:32 -05:00
labelwid = uiWindowsWindowTextWidth ( fc . label ) ;
if ( maxLabelWidth < labelwid )
maxLabelWidth = labelwid ;
uiWindowsControlMinimumSize ( uiWindowsControl ( fc . c ) , & minimumWidth , & minimumHeight ) ;
if ( fc . stretchy ) {
nStretchy + + ;
if ( maxStretchyHeight < minimumHeight )
maxStretchyHeight = minimumHeight ;
}
if ( maxControlWidth < minimumWidth )
maxControlWidth = minimumWidth ;
if ( ! fc . stretchy )
* height + = minimumHeight ;
}
2016-06-14 17:12:30 -05:00
if ( nVisible = = 0 ) // nothing to show; return 0x0
return ;
2016-06-08 22:33:32 -05:00
* width + = maxLabelWidth + maxControlWidth ;
2016-06-14 17:12:30 -05:00
// 2) outset the desired rect with the needed padding
* width + = xpadding ;
* height + = ( nVisible - 1 ) * ypadding ;
2016-06-08 22:33:32 -05:00
// 3) and now we can add in stretchy controls
* height + = nStretchy * maxStretchyHeight ;
}
static void uiFormMinimumSizeChanged ( uiWindowsControl * c )
{
uiForm * f = uiForm ( c ) ;
if ( uiWindowsControlTooSmall ( uiWindowsControl ( f ) ) ) {
uiWindowsControlContinueMinimumSizeChanged ( uiWindowsControl ( f ) ) ;
return ;
}
formRelayout ( f ) ;
}
uiWindowsControlDefaultLayoutRect ( uiForm )
uiWindowsControlDefaultAssignControlIDZOrder ( uiForm )
2016-06-14 14:55:24 -05:00
static void uiFormChildVisibilityChanged ( uiWindowsControl * c )
{
// TODO eliminate the redundancy
uiWindowsControlMinimumSizeChanged ( c ) ;
}
2016-06-08 22:33:32 -05:00
static void formArrangeChildren ( uiForm * f )
{
LONG_PTR controlID ;
HWND insertAfter ;
2016-06-13 20:54:15 -05:00
int i ;
2016-06-08 22:33:32 -05:00
controlID = 100 ;
insertAfter = NULL ;
for ( const struct formChild & fc : * ( f - > controls ) ) {
// TODO assign label ID and z-order
uiWindowsControlAssignControlIDZOrder ( uiWindowsControl ( fc . c ) , & controlID , & insertAfter ) ;
}
}
void uiFormAppend ( uiForm * f , const char * label , uiControl * c , int stretchy )
{
struct formChild fc ;
WCHAR * wlabel ;
fc . c = c ;
wlabel = toUTF16 ( label ) ;
fc . label = uiWindowsEnsureCreateControlHWND ( 0 ,
L " STATIC " , wlabel ,
SS_LEFT | SS_NOPREFIX ,
hInstance , NULL ,
TRUE ) ;
2016-06-10 21:29:20 -05:00
uiFree ( wlabel ) ;
2016-06-08 22:33:32 -05:00
uiWindowsEnsureSetParentHWND ( fc . label , f - > hwnd ) ;
fc . stretchy = stretchy ;
uiControlSetParent ( fc . c , uiControl ( f ) ) ;
uiWindowsControlSetParentHWND ( uiWindowsControl ( fc . c ) , f - > hwnd ) ;
f - > controls - > push_back ( fc ) ;
formArrangeChildren ( f ) ;
uiWindowsControlMinimumSizeChanged ( uiWindowsControl ( f ) ) ;
}
int uiFormPadded ( uiForm * f )
{
return f - > padded ;
}
void uiFormSetPadded ( uiForm * f , int padded )
{
f - > padded = padded ;
uiWindowsControlMinimumSizeChanged ( uiWindowsControl ( f ) ) ;
}
static void onResize ( uiWindowsControl * c )
{
formRelayout ( uiForm ( c ) ) ;
}
uiForm * uiNewForm ( void )
{
uiForm * f ;
uiWindowsNewControl ( uiForm , f ) ;
f - > hwnd = uiWindowsMakeContainer ( uiWindowsControl ( f ) , onResize ) ;
f - > controls = new std : : vector < struct formChild > ;
return f ;
}