2016-06-10 18:34:48 -05:00
// 10 june 2016
# include "uipriv_windows.hpp"
// TODO compare with GTK+:
// - what happens if you call InsertAt() twice?
// - what happens if you call Append() twice?
// TODOs
2016-06-14 22:03:40 -05:00
// - the Assorted page has clipping and repositioning issues
2016-06-10 18:34:48 -05:00
struct gridChild {
uiControl * c ;
2016-06-13 20:20:20 -05:00
int left ;
int top ;
int xspan ;
int yspan ;
2016-06-10 18:34:48 -05:00
int hexpand ;
uiAlign halign ;
int vexpand ;
uiAlign valign ;
// have these here so they don't need to be reallocated each relayout
2016-06-13 20:20:20 -05:00
int finalx , finaly ;
int finalwidth , finalheight ;
int minwidth , minheight ;
2016-06-10 18:34:48 -05:00
} ;
struct uiGrid {
uiWindowsControl c ;
HWND hwnd ;
std : : vector < struct gridChild * > * children ;
std : : map < uiControl * , size_t > * indexof ;
int padded ;
2016-06-13 20:20:20 -05:00
int xmin , ymin ;
int xmax , ymax ;
2016-06-10 18:34:48 -05:00
} ;
2016-06-14 20:55:14 -05:00
static bool gridRecomputeMinMax ( uiGrid * g )
{
bool first = true ;
for ( struct gridChild * gc : * ( g - > children ) ) {
// this is important; we want g->xmin/g->ymin to satisfy gridLayoutData::visibleRow()/visibleColumn()
if ( ! uiControlVisible ( gc - > c ) )
continue ;
if ( first ) {
g - > xmin = gc - > left ;
g - > ymin = gc - > top ;
g - > xmax = gc - > left + gc - > xspan ;
g - > ymax = gc - > top + gc - > yspan ;
first = false ;
continue ;
}
if ( g - > xmin > gc - > left )
g - > xmin = gc - > left ;
if ( g - > ymin > gc - > top )
g - > ymin = gc - > top ;
if ( g - > xmax < ( gc - > left + gc - > xspan ) )
g - > xmax = gc - > left + gc - > xspan ;
if ( g - > ymax < ( gc - > top + gc - > yspan ) )
g - > ymax = gc - > top + gc - > yspan ;
}
return first ! = false ;
}
2016-06-10 18:34:48 -05:00
# define xcount(g) ((g)->xmax - (g)->xmin)
# define ycount(g) ((g)->ymax - (g)->ymin)
# define toxindex(g, x) ((x) - (g)->xmin)
# define toyindex(g, y) ((y) - (g)->ymin)
class gridLayoutData {
2016-06-14 19:57:21 -05:00
int ycount ;
2016-06-10 18:34:48 -05:00
public :
2016-06-13 20:20:20 -05:00
int * * gg ; // topological map gg[y][x] = control index
int * colwidths ;
int * rowheights ;
2016-06-10 18:34:48 -05:00
bool * hexpand ;
bool * vexpand ;
2016-06-14 19:57:21 -05:00
int nVisibleRows ;
int nVisibleColumns ;
2016-06-10 18:34:48 -05:00
2016-06-14 20:55:14 -05:00
bool noVisible ;
2016-06-10 18:34:48 -05:00
gridLayoutData ( uiGrid * g )
{
size_t i ;
2016-06-13 20:20:20 -05:00
int x , y ;
2016-06-10 18:34:48 -05:00
2016-06-14 20:55:14 -05:00
this - > noVisible = gridRecomputeMinMax ( g ) ;
2016-06-13 20:20:20 -05:00
this - > gg = new int * [ ycount ( g ) ] ;
2016-06-10 18:34:48 -05:00
for ( y = 0 ; y < ycount ( g ) ; y + + ) {
2016-06-13 20:20:20 -05:00
this - > gg [ y ] = new int [ xcount ( g ) ] ;
2016-06-10 18:34:48 -05:00
for ( x = 0 ; x < xcount ( g ) ; x + + )
this - > gg [ y ] [ x ] = - 1 ;
}
for ( i = 0 ; i < g - > children - > size ( ) ; i + + ) {
struct gridChild * gc ;
gc = ( * ( g - > children ) ) [ i ] ;
2016-06-14 18:44:28 -05:00
if ( ! uiControlVisible ( gc - > c ) )
continue ;
2016-06-10 18:34:48 -05:00
for ( y = gc - > top ; y < gc - > top + gc - > yspan ; y + + )
for ( x = gc - > left ; x < gc - > left + gc - > xspan ; x + + )
this - > gg [ toyindex ( g , y ) ] [ toxindex ( g , x ) ] = i ;
}
2016-06-13 20:20:20 -05:00
this - > colwidths = new int [ xcount ( g ) ] ;
ZeroMemory ( this - > colwidths , xcount ( g ) * sizeof ( int ) ) ;
this - > rowheights = new int [ ycount ( g ) ] ;
ZeroMemory ( this - > rowheights , ycount ( g ) * sizeof ( int ) ) ;
2016-06-10 18:34:48 -05:00
this - > hexpand = new bool [ xcount ( g ) ] ;
ZeroMemory ( this - > hexpand , xcount ( g ) * sizeof ( bool ) ) ;
this - > vexpand = new bool [ ycount ( g ) ] ;
ZeroMemory ( this - > vexpand , ycount ( g ) * sizeof ( bool ) ) ;
this - > ycount = ycount ( g ) ;
2016-06-14 19:57:21 -05:00
// if a row or column only contains emptys and spanning cells of a opposite-direction spannings, it is invisible and should not be considered for padding amount calculations
2016-06-14 22:00:30 -05:00
// note that the first row and column will always be visible because gridRecomputeMinMax() computed a smallest fitting rectangle
2016-06-14 20:55:14 -05:00
if ( this - > noVisible )
return ;
2016-06-14 19:57:21 -05:00
this - > nVisibleRows = 0 ;
for ( y = 0 ; y < this - > ycount ; y + + )
if ( this - > visibleRow ( g , y ) )
this - > nVisibleRows + + ;
this - > nVisibleColumns = 0 ;
for ( x = 0 ; x < xcount ( g ) ; x + + )
if ( this - > visibleColumn ( g , x ) )
this - > nVisibleColumns + + ;
2016-06-10 18:34:48 -05:00
}
~ gridLayoutData ( )
{
size_t y ;
delete [ ] this - > hexpand ;
delete [ ] this - > vexpand ;
delete [ ] this - > colwidths ;
delete [ ] this - > rowheights ;
for ( y = 0 ; y < this - > ycount ; y + + )
delete [ ] this - > gg [ y ] ;
delete [ ] this - > gg ;
}
2016-06-14 19:57:21 -05:00
bool visibleRow ( uiGrid * g , int y )
{
int x ;
struct gridChild * gc ;
for ( x = 0 ; x < xcount ( g ) ; x + + )
if ( this - > gg [ y ] [ x ] ! = - 1 ) {
gc = ( * ( g - > children ) ) [ this - > gg [ y ] [ x ] ] ;
if ( gc - > yspan = = 1 | | gc - > top - g - > ymin = = y )
return true ;
}
return false ;
}
bool visibleColumn ( uiGrid * g , int x )
{
int y ;
struct gridChild * gc ;
for ( y = 0 ; y < this - > ycount ; y + + )
if ( this - > gg [ y ] [ x ] ! = - 1 ) {
gc = ( * ( g - > children ) ) [ this - > gg [ y ] [ x ] ] ;
if ( gc - > xspan = = 1 | | gc - > left - g - > xmin = = x )
return true ;
}
return false ;
}
2016-06-10 18:34:48 -05:00
} ;
static void gridPadding ( uiGrid * g , int * xpadding , int * ypadding )
{
uiWindowsSizing sizing ;
* xpadding = 0 ;
* ypadding = 0 ;
if ( g - > padded ) {
uiWindowsGetSizing ( g - > hwnd , & sizing ) ;
uiWindowsSizingStandardPadding ( & sizing , xpadding , ypadding ) ;
}
}
static void gridRelayout ( uiGrid * g )
{
RECT r ;
2016-06-13 20:20:20 -05:00
int x , y , width , height ;
2016-06-10 18:34:48 -05:00
gridLayoutData * ld ;
int xpadding , ypadding ;
2016-06-13 20:20:20 -05:00
int ix , iy ;
int iwidth , iheight ;
2016-06-10 18:34:48 -05:00
int i ;
struct gridChild * gc ;
2016-06-13 20:20:20 -05:00
int nhexpand , nvexpand ;
2016-06-10 18:34:48 -05:00
if ( g - > children - > size ( ) = = 0 )
return ; // nothing to do
uiWindowsEnsureGetClientRect ( g - > hwnd , & r ) ;
x = r . left ;
y = r . top ;
width = r . right - r . left ;
height = r . bottom - r . top ;
gridPadding ( g , & xpadding , & ypadding ) ;
ld = new gridLayoutData ( g ) ;
2016-06-14 22:03:40 -05:00
if ( ld - > noVisible ) { // nothing to do
delete ld ;
2016-06-14 20:55:14 -05:00
return ;
2016-06-14 22:03:40 -05:00
}
2016-06-10 18:34:48 -05:00
// 0) discount padding from width/height
2016-06-14 19:57:21 -05:00
width - = ( ld - > nVisibleColumns - 1 ) * xpadding ;
height - = ( ld - > nVisibleRows - 1 ) * ypadding ;
2016-06-10 18:34:48 -05:00
// 1) compute colwidths and rowheights before handling expansion
// we only count non-spanning controls to avoid weirdness
for ( iy = 0 ; iy < ycount ( g ) ; iy + + )
for ( ix = 0 ; ix < xcount ( g ) ; ix + + ) {
i = ld - > gg [ iy ] [ ix ] ;
if ( i = = - 1 )
continue ;
gc = ( * ( g - > children ) ) [ i ] ;
uiWindowsControlMinimumSize ( uiWindowsControl ( gc - > c ) , & iwidth , & iheight ) ;
if ( gc - > xspan = = 1 )
if ( ld - > colwidths [ ix ] < iwidth )
ld - > colwidths [ ix ] = iwidth ;
if ( gc - > yspan = = 1 )
if ( ld - > rowheights [ iy ] < iheight )
ld - > rowheights [ iy ] = iheight ;
// save these for step 6
gc - > minwidth = iwidth ;
gc - > minheight = iheight ;
}
// 2) figure out which rows/columns expand but not span
// we need to know which expanding rows/columns don't span before we can handle the ones that do
for ( i = 0 ; i < g - > children - > size ( ) ; i + + ) {
gc = ( * ( g - > children ) ) [ i ] ;
2016-06-14 18:44:28 -05:00
if ( ! uiControlVisible ( gc - > c ) )
continue ;
2016-06-10 18:34:48 -05:00
if ( gc - > hexpand & & gc - > xspan = = 1 )
2016-06-10 20:24:30 -05:00
ld - > hexpand [ toxindex ( g , gc - > left ) ] = true ;
2016-06-10 18:34:48 -05:00
if ( gc - > vexpand & & gc - > yspan = = 1 )
2016-06-10 20:24:30 -05:00
ld - > vexpand [ toyindex ( g , gc - > top ) ] = true ;
2016-06-10 18:34:48 -05:00
}
// 3) figure out which rows/columns expand that do span
// the way we handle this is simple: if none of the spanned rows/columns expand, make all rows/columns expand
for ( i = 0 ; i < g - > children - > size ( ) ; i + + ) {
gc = ( * ( g - > children ) ) [ i ] ;
2016-06-14 18:44:28 -05:00
if ( ! uiControlVisible ( gc - > c ) )
continue ;
2016-06-10 18:34:48 -05:00
if ( gc - > hexpand & & gc - > xspan ! = 1 ) {
bool doit = true ;
for ( ix = gc - > left ; ix < gc - > left + gc - > xspan ; ix + + )
2016-06-10 20:24:30 -05:00
if ( ld - > hexpand [ toxindex ( g , ix ) ] ) {
2016-06-10 18:34:48 -05:00
doit = false ;
break ;
}
if ( doit )
for ( ix = gc - > left ; ix < gc - > left + gc - > xspan ; ix + + )
2016-06-10 20:24:30 -05:00
ld - > hexpand [ toxindex ( g , ix ) ] = true ;
2016-06-10 18:34:48 -05:00
}
if ( gc - > vexpand & & gc - > yspan ! = 1 ) {
bool doit = true ;
for ( iy = gc - > top ; iy < gc - > top + gc - > yspan ; iy + + )
2016-06-10 20:24:30 -05:00
if ( ld - > vexpand [ toyindex ( g , iy ) ] ) {
2016-06-10 18:34:48 -05:00
doit = false ;
break ;
}
if ( doit )
for ( iy = gc - > top ; iy < gc - > top + gc - > yspan ; iy + + )
2016-06-10 20:24:30 -05:00
ld - > vexpand [ toyindex ( g , iy ) ] = true ;
2016-06-10 18:34:48 -05:00
}
}
// 4) compute and assign expanded widths/heights
nhexpand = 0 ;
nvexpand = 0 ;
for ( i = 0 ; i < xcount ( g ) ; i + + )
if ( ld - > hexpand [ i ] )
nhexpand + + ;
else
width - = ld - > colwidths [ i ] ;
for ( i = 0 ; i < ycount ( g ) ; i + + )
if ( ld - > vexpand [ i ] )
nvexpand + + ;
else
height - = ld - > rowheights [ i ] ;
for ( i = 0 ; i < xcount ( g ) ; i + + )
if ( ld - > hexpand [ i ] )
ld - > colwidths [ i ] = width / nhexpand ;
for ( i = 0 ; i < ycount ( g ) ; i + + )
if ( ld - > vexpand [ i ] )
ld - > rowheights [ i ] = height / nvexpand ;
// 5) reset the final coordinates for the next step
for ( i = 0 ; i < g - > children - > size ( ) ; i + + ) {
gc = ( * ( g - > children ) ) [ i ] ;
2016-06-14 18:44:28 -05:00
if ( ! uiControlVisible ( gc - > c ) )
continue ;
2016-06-10 18:34:48 -05:00
gc - > finalx = 0 ;
gc - > finaly = 0 ;
gc - > finalwidth = 0 ;
gc - > finalheight = 0 ;
}
// 6) compute cell positions and sizes
2016-06-10 20:24:30 -05:00
for ( iy = 0 ; iy < ycount ( g ) ; iy + + ) {
2016-06-13 20:20:20 -05:00
int curx ;
2016-06-10 18:34:48 -05:00
int prev ;
curx = 0 ;
prev = - 1 ;
for ( ix = 0 ; ix < xcount ( g ) ; ix + + ) {
2016-06-14 22:00:30 -05:00
if ( ! ld - > visibleColumn ( g , ix ) )
continue ;
2016-06-10 18:34:48 -05:00
i = ld - > gg [ iy ] [ ix ] ;
if ( i ! = - 1 ) {
gc = ( * ( g - > children ) ) [ i ] ;
2016-06-10 20:24:30 -05:00
if ( iy = = toyindex ( g , gc - > top ) ) { // don't repeat this step if the control spans vertically
2016-06-10 18:34:48 -05:00
if ( i ! = prev )
gc - > finalx = curx ;
else
gc - > finalwidth + = xpadding ;
gc - > finalwidth + = ld - > colwidths [ ix ] ;
}
}
curx + = ld - > colwidths [ ix ] + xpadding ;
prev = i ;
}
}
for ( ix = 0 ; ix < xcount ( g ) ; ix + + ) {
2016-06-13 20:20:20 -05:00
int cury ;
2016-06-10 18:34:48 -05:00
int prev ;
cury = 0 ;
prev = - 1 ;
for ( iy = 0 ; iy < ycount ( g ) ; iy + + ) {
2016-06-14 22:00:30 -05:00
if ( ! ld - > visibleRow ( g , iy ) )
continue ;
2016-06-10 18:34:48 -05:00
i = ld - > gg [ iy ] [ ix ] ;
if ( i ! = - 1 ) {
gc = ( * ( g - > children ) ) [ i ] ;
2016-06-10 20:24:30 -05:00
if ( ix = = toxindex ( g , gc - > left ) ) { // don't repeat this step if the control spans horizontally
2016-06-10 18:34:48 -05:00
if ( i ! = prev )
gc - > finaly = cury ;
else
gc - > finalheight + = ypadding ;
gc - > finalheight + = ld - > rowheights [ iy ] ;
}
}
cury + = ld - > rowheights [ iy ] + ypadding ;
prev = i ;
}
}
// 7) everything as it stands now is set for xalign == Fill yalign == Fill; set the correct alignments
// this is why we saved minwidth/minheight above
for ( i = 0 ; i < g - > children - > size ( ) ; i + + ) {
gc = ( * ( g - > children ) ) [ i ] ;
2016-06-14 18:44:28 -05:00
if ( ! uiControlVisible ( gc - > c ) )
continue ;
2016-06-10 18:34:48 -05:00
if ( gc - > halign ! = uiAlignFill ) {
switch ( gc - > halign ) {
case uiAlignEnd :
gc - > finalx + = gc - > finalwidth - gc - > minwidth ;
break ;
case uiAlignCenter :
gc - > finalx + = ( gc - > finalwidth - gc - > minwidth ) / 2 ;
break ;
}
gc - > finalwidth = gc - > minwidth ; // for all three
}
if ( gc - > valign ! = uiAlignFill ) {
switch ( gc - > valign ) {
case uiAlignEnd :
gc - > finaly + = gc - > finalheight - gc - > minheight ;
break ;
case uiAlignCenter :
gc - > finaly + = ( gc - > finalheight - gc - > minheight ) / 2 ;
break ;
}
gc - > finalheight = gc - > minheight ; // for all three
}
}
// 8) and FINALLY we resize
for ( iy = 0 ; iy < ycount ( g ) ; iy + + )
for ( ix = 0 ; ix < xcount ( g ) ; ix + + ) {
i = ld - > gg [ iy ] [ ix ] ;
if ( i ! = - 1 ) { // treat empty cells like spaces
gc = ( * ( g - > children ) ) [ i ] ;
uiWindowsEnsureMoveWindowDuringResize (
( HWND ) uiControlHandle ( gc - > c ) ,
gc - > finalx , //TODO + x,
gc - > finaly , //TODO + y,
gc - > finalwidth ,
gc - > finalheight ) ;
}
}
delete ld ;
}
static void uiGridDestroy ( uiControl * c )
{
uiGrid * g = uiGrid ( c ) ;
for ( struct gridChild * gc : * ( g - > children ) ) {
uiControlSetParent ( gc - > c , NULL ) ;
uiControlDestroy ( gc - > c ) ;
uiFree ( gc ) ;
}
delete g - > indexof ;
delete g - > children ;
uiWindowsEnsureDestroyWindow ( g - > hwnd ) ;
uiFreeControl ( uiControl ( g ) ) ;
}
uiWindowsControlDefaultHandle ( uiGrid )
uiWindowsControlDefaultParent ( uiGrid )
uiWindowsControlDefaultSetParent ( uiGrid )
uiWindowsControlDefaultToplevel ( uiGrid )
uiWindowsControlDefaultVisible ( uiGrid )
uiWindowsControlDefaultShow ( uiGrid )
uiWindowsControlDefaultHide ( uiGrid )
uiWindowsControlDefaultEnabled ( uiGrid )
uiWindowsControlDefaultEnable ( uiGrid )
uiWindowsControlDefaultDisable ( uiGrid )
static void uiGridSyncEnableState ( uiWindowsControl * c , int enabled )
{
uiGrid * g = uiGrid ( c ) ;
if ( uiWindowsShouldStopSyncEnableState ( uiWindowsControl ( g ) , enabled ) )
return ;
for ( const struct gridChild * gc : * ( g - > children ) )
uiWindowsControlSyncEnableState ( uiWindowsControl ( gc - > c ) , enabled ) ;
}
uiWindowsControlDefaultSetParentHWND ( uiGrid )
2016-06-13 20:20:20 -05:00
static void uiGridMinimumSize ( uiWindowsControl * c , int * width , int * height )
2016-06-10 18:34:48 -05:00
{
uiGrid * g = uiGrid ( c ) ;
int xpadding , ypadding ;
gridLayoutData * ld ;
2016-06-13 20:20:20 -05:00
int x , y ;
2016-06-10 18:34:48 -05:00
int i ;
struct gridChild * gc ;
2016-06-13 20:20:20 -05:00
int minwid , minht ;
int colwidth , rowheight ;
2016-06-10 18:34:48 -05:00
* width = 0 ;
* height = 0 ;
if ( g - > children - > size ( ) = = 0 )
return ; // nothing to do
gridPadding ( g , & xpadding , & ypadding ) ;
ld = new gridLayoutData ( g ) ;
2016-06-14 22:03:40 -05:00
if ( ld - > noVisible ) { // nothing to do; return 0x0
delete ld ;
2016-06-14 20:55:14 -05:00
return ;
2016-06-14 22:03:40 -05:00
}
2016-06-10 18:34:48 -05:00
// 1) compute colwidths and rowheights before handling expansion
// TODO put this in its own function (but careful about the spanning calculation in gridRelayout())
for ( y = 0 ; y < ycount ( g ) ; y + + )
for ( x = 0 ; x < xcount ( g ) ; x + + ) {
i = ld - > gg [ y ] [ x ] ;
if ( i = = - 1 )
continue ;
gc = ( * ( g - > children ) ) [ i ] ;
uiWindowsControlMinimumSize ( uiWindowsControl ( gc - > c ) , & minwid , & minht ) ;
// allot equal space in the presence of spanning to keep things sane
if ( ld - > colwidths [ x ] < minwid / gc - > xspan )
ld - > colwidths [ x ] = minwid / gc - > xspan ;
if ( ld - > rowheights [ y ] < minht / gc - > yspan )
ld - > rowheights [ y ] = minht / gc - > yspan ;
// save these for step 6
gc - > minwidth = minwid ;
gc - > minheight = minht ;
}
// 2) compute total column width/row height
colwidth = 0 ;
rowheight = 0 ;
for ( x = 0 ; x < xcount ( g ) ; x + + )
colwidth + = ld - > colwidths [ x ] ;
for ( y = 0 ; y < ycount ( g ) ; y + + )
rowheight + = ld - > rowheights [ y ] ;
// and that's it; just account for padding
2016-06-14 19:57:21 -05:00
* width = colwidth + ( ld - > nVisibleColumns - 1 ) * xpadding ;
* height = rowheight + ( ld - > nVisibleRows - 1 ) * ypadding ;
2016-06-10 18:34:48 -05:00
}
static void uiGridMinimumSizeChanged ( uiWindowsControl * c )
{
uiGrid * g = uiGrid ( c ) ;
if ( uiWindowsControlTooSmall ( uiWindowsControl ( g ) ) ) {
uiWindowsControlContinueMinimumSizeChanged ( uiWindowsControl ( g ) ) ;
return ;
}
gridRelayout ( g ) ;
}
uiWindowsControlDefaultLayoutRect ( uiGrid )
uiWindowsControlDefaultAssignControlIDZOrder ( uiGrid )
2016-06-14 14:55:24 -05:00
static void uiGridChildVisibilityChanged ( uiWindowsControl * c )
{
// TODO eliminate the redundancy
uiWindowsControlMinimumSizeChanged ( c ) ;
}
2016-06-10 18:34:48 -05:00
// must have called gridRecomputeMinMax() first
static void gridArrangeChildren ( uiGrid * g )
{
LONG_PTR controlID ;
HWND insertAfter ;
gridLayoutData * ld ;
bool * visited ;
2016-06-13 20:20:20 -05:00
int x , y ;
2016-06-10 18:34:48 -05:00
int i ;
struct gridChild * gc ;
if ( g - > children - > size ( ) = = 0 )
return ; // nothing to do
ld = new gridLayoutData ( g ) ;
controlID = 100 ;
insertAfter = NULL ;
visited = new bool [ g - > children - > size ( ) ] ;
ZeroMemory ( visited , g - > children - > size ( ) * sizeof ( bool ) ) ;
for ( y = 0 ; y < ycount ( g ) ; y + + )
for ( x = 0 ; x < xcount ( g ) ; x + + ) {
i = ld - > gg [ y ] [ x ] ;
if ( i = = - 1 )
continue ;
if ( visited [ i ] )
continue ;
visited [ i ] = true ;
gc = ( * ( g - > children ) ) [ i ] ;
uiWindowsControlAssignControlIDZOrder ( uiWindowsControl ( gc - > c ) , & controlID , & insertAfter ) ;
}
delete [ ] visited ;
delete ld ;
}
2016-06-13 20:20:20 -05:00
static struct gridChild * toChild ( uiControl * c , int xspan , int yspan , int hexpand , uiAlign halign , int vexpand , uiAlign valign )
2016-06-10 18:34:48 -05:00
{
struct gridChild * gc ;
if ( xspan < 0 )
userbug ( " You cannot have a negative xspan in a uiGrid cell. " ) ;
if ( yspan < 0 )
userbug ( " You cannot have a negative yspan in a uiGrid cell. " ) ;
gc = uiNew ( struct gridChild ) ;
gc - > c = c ;
gc - > xspan = xspan ;
gc - > yspan = yspan ;
gc - > hexpand = hexpand ;
gc - > halign = halign ;
gc - > vexpand = vexpand ;
gc - > valign = valign ;
return gc ;
}
static void add ( uiGrid * g , struct gridChild * gc )
{
uiControlSetParent ( gc - > c , uiControl ( g ) ) ;
uiWindowsControlSetParentHWND ( uiWindowsControl ( gc - > c ) , g - > hwnd ) ;
g - > children - > push_back ( gc ) ;
( * ( g - > indexof ) ) [ gc - > c ] = g - > children - > size ( ) - 1 ;
gridRecomputeMinMax ( g ) ;
gridArrangeChildren ( g ) ;
uiWindowsControlMinimumSizeChanged ( uiWindowsControl ( g ) ) ;
}
2016-06-13 20:20:20 -05:00
void uiGridAppend ( uiGrid * g , uiControl * c , int left , int top , int xspan , int yspan , int hexpand , uiAlign halign , int vexpand , uiAlign valign )
2016-06-10 18:34:48 -05:00
{
struct gridChild * gc ;
gc = toChild ( c , xspan , yspan , hexpand , halign , vexpand , valign ) ;
gc - > left = left ;
gc - > top = top ;
add ( g , gc ) ;
}
// TODO decide what happens if existing is NULL
2016-06-13 20:20:20 -05:00
void uiGridInsertAt ( uiGrid * g , uiControl * c , uiControl * existing , uiAt at , int xspan , int yspan , int hexpand , uiAlign halign , int vexpand , uiAlign valign )
2016-06-10 18:34:48 -05:00
{
struct gridChild * gc ;
struct gridChild * other ;
gc = toChild ( c , xspan , yspan , hexpand , halign , vexpand , valign ) ;
other = ( * ( g - > children ) ) [ ( * ( g - > indexof ) ) [ existing ] ] ;
switch ( at ) {
case uiAtLeading :
gc - > left = other - > left - gc - > xspan ;
gc - > top = other - > top ;
break ;
case uiAtTop :
gc - > left = other - > left ;
gc - > top = other - > top - gc - > yspan ;
break ;
case uiAtTrailing :
gc - > left = other - > left + other - > xspan ;
gc - > top = other - > top ;
break ;
case uiAtBottom :
gc - > left = other - > left ;
gc - > top = other - > top + other - > yspan ;
break ;
// TODO add error checks to ALL enums
}
add ( g , gc ) ;
}
int uiGridPadded ( uiGrid * g )
{
return g - > padded ;
}
void uiGridSetPadded ( uiGrid * g , int padded )
{
g - > padded = padded ;
uiWindowsControlMinimumSizeChanged ( uiWindowsControl ( g ) ) ;
}
static void onResize ( uiWindowsControl * c )
{
gridRelayout ( uiGrid ( c ) ) ;
}
uiGrid * uiNewGrid ( void )
{
uiGrid * g ;
uiWindowsNewControl ( uiGrid , g ) ;
g - > hwnd = uiWindowsMakeContainer ( uiWindowsControl ( g ) , onResize ) ;
g - > children = new std : : vector < struct gridChild * > ;
g - > indexof = new std : : map < uiControl * , size_t > ;
return g ;
}