2021-09-14 00:00:21 -04:00
/*
* Copyright ( C ) 2021 Paul Davis < paul @ linuxaudiosystems . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2021-09-14 20:29:06 -04:00
# include "pbd/debug.h"
2021-09-14 18:08:33 -04:00
# include "pbd/error.h"
# include "pbd/i18n.h"
2021-09-14 20:29:06 -04:00
# include "pbd/unwind.h"
2021-09-14 18:08:33 -04:00
2021-09-14 20:29:06 -04:00
# include "canvas/debug.h"
2021-09-14 00:00:21 -04:00
# include "canvas/table.h"
using namespace ArdourCanvas ;
using namespace PBD ;
using std : : cerr ;
using std : : endl ;
Table : : Table ( Canvas * canvas )
: Rectangle ( canvas )
2021-10-01 20:38:18 -04:00
, padding ( { 0 } )
, margin ( { 0 } )
2021-09-14 18:08:33 -04:00
, collapse_on_hide ( false )
2021-10-02 18:19:40 -04:00
, row_homogenous ( true )
, col_homogenous ( true )
2021-09-14 18:08:33 -04:00
, draw_hgrid ( false )
, draw_vgrid ( false )
2021-09-14 00:00:21 -04:00
{
2021-09-14 18:08:33 -04:00
set_layout_sensitive ( true ) ;
2021-09-14 00:00:21 -04:00
}
Table : : Table ( Item * item )
: Rectangle ( item )
2021-10-01 20:38:18 -04:00
, padding ( { 0 } )
, margin ( { 0 } )
2021-09-14 18:08:33 -04:00
, collapse_on_hide ( false )
2021-10-02 18:19:40 -04:00
, row_homogenous ( true )
, col_homogenous ( true )
2021-09-14 18:08:33 -04:00
, draw_hgrid ( false )
, draw_vgrid ( false )
2021-09-14 00:00:21 -04:00
{
2021-09-14 18:08:33 -04:00
set_layout_sensitive ( true ) ;
2021-09-14 00:00:21 -04:00
}
void
2021-10-02 17:16:39 -04:00
Table : : attach ( Item * item , uint32_t ulx , uint32_t uly , PackOptions row_options , PackOptions col_options , FourDimensions pad )
{
attach ( item , ulx , uly , ulx + 1 , uly + 1 , row_options , col_options , pad ) ;
}
void
Table : : attach_with_span ( Item * item , uint32_t ulx , uint32_t uly , uint32_t w , uint32_t h , PackOptions row_options , PackOptions col_options , FourDimensions pad )
{
attach ( item , ulx , uly , ulx + w , uly + h , row_options , col_options , pad ) ;
}
void
Table : : attach ( Item * item , uint32_t ulx , uint32_t uly , uint32_t lrx , uint32_t lry , PackOptions row_options , PackOptions col_options , FourDimensions pad )
2021-09-14 00:00:21 -04:00
{
2021-09-14 18:08:33 -04:00
/* XXX maybe use z-axis to stack elements if the insert fails? Would
* involve making Index 3 D and using an actual hash function
*/
2021-09-17 14:34:07 -04:00
std : : pair < Cells : : iterator , bool > res = cells . insert ( { Index ( ulx , uly ) , CellInfo ( item , row_options , col_options , Index ( ulx , uly ) , Index ( lrx , lry ) , pad ) } ) ;
if ( ! res . second ) {
2021-09-14 23:18:16 -04:00
cerr < < " Failed to attach at " < < ulx < < " , " < < uly < < " " < < lrx < < " , " < < lry < < endl ;
2021-09-14 18:08:33 -04:00
}
2021-09-17 14:34:07 -04:00
_add ( item ) ;
item - > size_request ( res . first - > second . natural_size . x , res . first - > second . natural_size . y ) ;
2021-09-17 14:51:26 -04:00
if ( lrx > col_info . size ( ) ) {
col_info . resize ( lrx ) ;
2021-09-17 14:34:07 -04:00
}
2021-09-17 14:51:26 -04:00
if ( lry > row_info . size ( ) ) {
row_info . resize ( lry ) ;
2021-09-17 14:34:07 -04:00
}
2021-09-14 00:00:21 -04:00
}
void
Table : : child_changed ( bool bbox_changed )
{
if ( ignore_child_changes ) {
return ;
}
Item : : child_changed ( bbox_changed ) ;
size_allocate_children ( _allocation ) ;
}
void
Table : : compute_bounding_box ( ) const
{
if ( cells . empty ( ) ) {
2021-10-03 18:46:25 -04:00
_bounding_box = Rect ( ) ;
2022-04-27 00:02:22 -04:00
set_bbox_clean ( ) ;
2021-09-14 00:00:21 -04:00
return ;
}
2021-09-17 14:34:07 -04:00
if ( ( * cells . begin ( ) ) . second . natural_size = = Duple ( ) ) {
/* force basic computation of natural size */
Duple ns = const_cast < Table * > ( this ) - > compute ( Rect ( ) ) ;
_bounding_box = Rect ( 0 , 0 , ns . x , ns . y ) ;
} else {
2021-10-02 18:11:58 -04:00
/* bounding box was computed in compute() */
2021-09-14 00:00:21 -04:00
}
2021-09-14 20:29:06 -04:00
DEBUG_TRACE ( DEBUG : : CanvasTable , string_compose ( " bounding box computed as %1 \n " , _bounding_box ) ) ;
2022-04-27 00:02:22 -04:00
set_bbox_clean ( ) ;
2021-09-14 00:00:21 -04:00
}
2021-09-14 18:08:33 -04:00
void
Table : : set_row_size ( uint32_t row , Distance size )
{
if ( row_info . size ( ) < = row ) {
row_info . resize ( row + 1 ) ;
}
row_info [ row ] . user_size = size ;
}
void
Table : : set_col_size ( uint32_t col , Distance size )
{
if ( col_info . size ( ) < = col ) {
col_info . resize ( col + 1 ) ;
}
col_info [ col ] . user_size = size ;
}
2021-09-14 00:00:21 -04:00
void
Table : : size_request ( Distance & w , Distance & h ) const
{
2021-09-17 14:51:26 -04:00
Duple d = const_cast < Table * > ( this ) - > compute ( Rect ( ) ) ;
2021-09-14 00:00:21 -04:00
2021-09-17 14:51:26 -04:00
w = d . x ;
h = d . y ;
2021-09-14 00:00:21 -04:00
}
void
Table : : layout ( )
{
2021-10-01 20:38:18 -04:00
( void ) compute ( _allocation ) ;
2021-09-14 00:00:21 -04:00
}
void
Table : : size_allocate_children ( Rect const & within )
2021-09-14 18:08:33 -04:00
{
( void ) compute ( within ) ;
}
Duple
Table : : compute ( Rect const & within )
2021-09-14 00:00:21 -04:00
{
2021-09-14 20:29:06 -04:00
DEBUG_TRACE ( DEBUG : : CanvasTable , string_compose ( " \n \n Compute table within rect: %1 \n " , within ) ) ;
2021-09-17 14:53:16 -04:00
if ( cells . empty ( ) ) {
return Duple ( 0 , 0 ) ;
}
2021-09-17 14:51:26 -04:00
uint32_t rows = row_info . size ( ) ;
uint32_t cols = col_info . size ( ) ;
2021-09-17 14:34:07 -04:00
for ( auto & ai : row_info ) {
ai . reset ( ) ;
}
2021-09-14 20:29:06 -04:00
2021-09-17 14:34:07 -04:00
for ( auto & ai : col_info ) {
ai . reset ( ) ;
2021-09-14 00:00:21 -04:00
}
2021-09-15 00:39:59 -04:00
DEBUG_TRACE ( DEBUG : : CanvasTable , string_compose ( " cell coordinates indicate rows %1 cols %2 from %3 cells \n " , rows , cols , cells . size ( ) ) ) ;
2021-09-14 18:08:33 -04:00
2021-09-15 00:39:59 -04:00
for ( auto & ci : cells ) {
2021-09-14 00:00:21 -04:00
2021-09-15 00:39:59 -04:00
CellInfo c ( ci . second ) ;
2021-09-14 00:00:21 -04:00
2021-09-23 13:47:01 -04:00
const float hspan = c . lower_right . x - c . upper_left . x ;
const float vspan = c . lower_right . y - c . upper_left . y ;
2021-10-01 20:38:18 -04:00
uint32_t covered_c_spacings = hspan - 1 ;
uint32_t covered_r_spacings = vspan - 1 ;
DEBUG_TRACE ( DEBUG : : CanvasTable , string_compose ( " for cell %8 %1,%2 - %3,%4, contents natural size = %5 hspan %6 vspan %7 \n " ,
2021-09-17 14:34:07 -04:00
c . upper_left . x ,
c . upper_left . y ,
c . lower_right . x ,
c . lower_right . y ,
2021-09-23 13:47:01 -04:00
c . natural_size ,
2021-10-01 20:38:18 -04:00
hspan , vspan ,
c . content - > whoami ( ) ) ) ;
2021-09-14 00:00:21 -04:00
2021-09-17 14:34:07 -04:00
/* for every col that this cell occupies, count the number of
* expanding / shrinking items , and compute the largest width
* for the column ( cells )
*/
for ( uint32_t col = c . upper_left . x ; col ! = c . lower_right . x ; + + col ) {
if ( c . col_options & PackExpand ) {
col_info [ col ] . expanders + + ;
}
if ( c . col_options & PackShrink ) {
col_info [ col ] . shrinkers + + ;
}
2021-09-23 13:47:01 -04:00
/* columns have a natural width
*
* The natural width of the item is divided across
* hspan cols , and then we add the padding and spacing
*/
2021-09-17 14:34:07 -04:00
2021-10-01 20:38:18 -04:00
const Distance total_cell_width = ( c . natural_size . x / hspan ) + c . padding . left + c . padding . right + col_info [ col ] . spacing + ( covered_c_spacings * col_spacing ) ;
/* the col's natural size (width) is the maximum
* width of any of the cells within it .
2021-09-23 13:47:01 -04:00
*/
2021-09-17 14:34:07 -04:00
2021-09-17 16:36:09 -04:00
col_info [ col ] . natural_size = std : : max ( col_info [ col ] . natural_size , total_cell_width ) ;
2021-09-17 14:34:07 -04:00
col_info [ col ] . occupied = true ;
}
/* for every row that this cell occupies, count the number of
* expanding / shrinking items , and compute the largest height
* for the row ( cells )
*/
for ( uint32_t row = c . upper_left . y ; row ! = c . lower_right . y ; + + row ) {
2021-09-14 00:00:21 -04:00
if ( c . row_options & PackExpand ) {
2021-09-14 18:08:33 -04:00
row_info [ row ] . expanders + + ;
2021-09-14 00:00:21 -04:00
}
2021-09-14 18:08:33 -04:00
2021-09-14 00:00:21 -04:00
if ( c . row_options & PackShrink ) {
2021-09-14 18:08:33 -04:00
row_info [ row ] . shrinkers + + ;
2021-09-14 00:00:21 -04:00
}
2021-09-23 13:47:01 -04:00
/* rows have a natural height.
*
* The natural height of the item is divided across
* vspan rows , and then we add the padding and spacing
*/
2021-10-01 20:38:18 -04:00
const Distance total_cell_height = ( c . natural_size . y / vspan ) + c . padding . up + c . padding . down + row_info [ row ] . spacing * ( covered_r_spacings * row_spacing ) ;
/* the row's natural size (height) is the maximum
* height of any of the cells within it .
*/
2021-09-23 13:47:01 -04:00
row_info [ row ] . natural_size = std : : max ( row_info [ row ] . natural_size , total_cell_height ) ;
row_info [ row ] . occupied = true ;
}
2021-09-17 14:34:07 -04:00
}
2021-09-14 00:00:21 -04:00
2021-09-17 14:34:07 -04:00
/* rows with nothing in them are still counted as existing. This is a
* design decision , not a logic inevitability .
*/
2021-09-14 00:00:21 -04:00
2021-09-23 13:47:01 -04:00
/* Find the widest column and tallest row. This will give us our
2021-09-17 14:34:07 -04:00
* " natural size "
*/
2021-09-14 00:00:21 -04:00
2021-10-01 20:38:18 -04:00
Distance widest_column_width = 0. ;
Distance highest_row_height = 0. ;
2021-09-23 13:47:01 -04:00
Distance inelastic_width = 0 ;
Distance inelastic_height = 0 ;
uint32_t inelastic_rows = 0 ;
uint32_t inelastic_cols = 0 ;
2021-10-01 20:38:18 -04:00
Distance total_natural_width = 0 ;
Distance total_natural_height = 0 ;
2021-09-14 18:08:33 -04:00
2021-10-02 19:09:01 -04:00
for ( auto & row : row_info ) {
2021-09-17 14:34:07 -04:00
2021-10-02 19:09:01 -04:00
if ( row . user_size ) {
highest_row_height = std : : max ( highest_row_height , row . user_size ) ;
inelastic_height + = row . user_size ;
2021-09-23 13:47:01 -04:00
inelastic_cols + + ;
2021-10-02 18:19:40 -04:00
if ( ! row_homogenous ) {
2021-10-02 19:09:01 -04:00
total_natural_height + = row . user_size ;
2021-10-01 20:38:18 -04:00
}
2021-09-17 14:34:07 -04:00
} else {
2021-10-02 19:09:01 -04:00
if ( row . expanders = = 0 & & row . shrinkers = = 0 ) {
2021-09-23 13:47:01 -04:00
inelastic_rows + + ;
2021-10-02 19:09:01 -04:00
inelastic_height + = row . natural_size ;
2021-09-23 13:47:01 -04:00
}
2021-10-02 19:09:01 -04:00
highest_row_height = std : : max ( highest_row_height , row . natural_size ) ;
2021-10-01 20:38:18 -04:00
2021-10-02 18:19:40 -04:00
if ( ! row_homogenous ) {
2021-10-02 19:09:01 -04:00
total_natural_height + = row . natural_size ;
2021-10-01 20:38:18 -04:00
}
2021-09-14 00:00:21 -04:00
}
2021-10-01 20:38:18 -04:00
2021-09-17 14:34:07 -04:00
}
2021-09-14 00:00:21 -04:00
2021-10-02 19:09:01 -04:00
for ( auto & col : col_info ) {
2021-09-17 14:34:07 -04:00
2021-10-02 19:09:01 -04:00
if ( col . user_size ) {
widest_column_width = std : : max ( widest_column_width , col . user_size ) ;
inelastic_width + = col . user_size ;
2021-09-23 13:47:01 -04:00
inelastic_cols + + ;
2021-10-02 18:19:40 -04:00
if ( ! col_homogenous ) {
2021-10-02 19:09:01 -04:00
total_natural_width + = col . user_size ;
2021-10-01 20:38:18 -04:00
}
2021-09-17 14:34:07 -04:00
} else {
2021-10-02 19:09:01 -04:00
if ( col . expanders = = 0 & & col . shrinkers = = 0 ) {
2021-09-23 13:47:01 -04:00
inelastic_cols + + ;
2021-10-02 19:09:01 -04:00
inelastic_width + = col . natural_size ;
2021-09-23 13:47:01 -04:00
}
2021-10-02 19:09:01 -04:00
widest_column_width = std : : max ( widest_column_width , col . natural_size ) ;
2021-10-01 20:38:18 -04:00
2021-10-02 18:19:40 -04:00
if ( ! col_homogenous ) {
2021-10-02 19:09:01 -04:00
total_natural_width + = col . natural_size ;
2021-10-01 20:38:18 -04:00
}
2021-09-17 14:34:07 -04:00
}
2021-10-01 20:38:18 -04:00
}
2021-09-23 13:47:01 -04:00
2021-10-02 18:19:40 -04:00
if ( col_homogenous ) {
2021-10-02 18:24:04 -04:00
/* reset total width using the widest, multiplied by the number
of cols , since they wll all be the same height . the values
before we do this are cumulative , and do not ( necessarily )
reflect homogeneity
2021-10-01 20:38:18 -04:00
*/
total_natural_width = widest_column_width * cols ;
2021-10-02 18:19:40 -04:00
}
if ( row_homogenous ) {
2021-10-02 18:24:04 -04:00
/* reset total height using the heighest, multiplied by the
number of rows , since they wll all be the same height . the
values before we do this are cumulative , and do not
( necessarily ) reflect homogeneity
*/
2021-10-01 20:38:18 -04:00
total_natural_height = highest_row_height * rows ;
2021-09-14 00:00:21 -04:00
}
2021-09-14 20:29:06 -04:00
# ifndef NDEBUG
if ( DEBUG_ENABLED ( DEBUG : : CanvasTable ) ) {
DEBUG_STR_DECL ( a ) ;
int n = 0 ;
2021-10-02 19:09:01 -04:00
for ( auto const & row : row_info ) {
DEBUG_STR_APPEND ( a , string_compose ( " row %1: height %2 \n " , n + 1 , row . natural_size ) ) ;
2021-09-14 20:29:06 -04:00
+ + n ;
}
DEBUG_TRACE ( DEBUG : : CanvasTable , DEBUG_STR ( a ) . str ( ) ) ;
DEBUG_STR_DECL ( b ) ;
n = 0 ;
2021-10-02 19:09:01 -04:00
for ( auto const & col : col_info ) {
2021-09-14 20:29:06 -04:00
2021-10-02 19:09:01 -04:00
DEBUG_STR_APPEND ( b , string_compose ( " col %1: width %2 \n " , n , col . natural_size ) ) ;
2021-09-14 20:29:06 -04:00
+ + n ;
}
DEBUG_TRACE ( DEBUG : : CanvasTable , DEBUG_STR ( b ) . str ( ) ) ;
}
# endif
2021-10-01 20:38:18 -04:00
DEBUG_TRACE ( DEBUG : : CanvasTable , string_compose ( " widest col width x highest row height = %1 x %2, inelastic: %3 x %4 ir x ic %5 x %6 \n " , widest_column_width , highest_row_height , inelastic_width , inelastic_height ,
2021-09-23 13:47:01 -04:00
inelastic_rows , inelastic_cols ) ) ;
2021-09-14 20:29:06 -04:00
2021-09-14 18:08:33 -04:00
if ( ! within ) {
/* within is empty, so this is just for a size request */
2021-10-01 20:38:18 -04:00
DEBUG_TRACE ( DEBUG : : CanvasTable , string_compose ( " total natural width x height = %1 x %2 + %3 , %4 \n " , total_natural_width , total_natural_height ,
( ( cols - 1 ) * col_spacing ) + padding . left + padding . right ,
( ( rows - 1 ) * col_spacing ) + padding . up + padding . down ) ) ;
return Duple ( total_natural_width + ( ( cols - 1 ) * col_spacing ) + padding . left + padding . right ,
total_natural_height + ( ( rows - 1 ) * col_spacing ) + padding . up + padding . down ) ;
2021-09-14 18:08:33 -04:00
}
2021-09-14 20:29:06 -04:00
/* actually doing allocation, so prevent endless loop between here and
* : : child_changed ( )
*/
PBD : : Unwinder < bool > uw ( ignore_child_changes , true ) ;
2021-09-14 00:00:21 -04:00
/* step two: compare the natural size to the size we've been given
*
* If the natural size is less than the allocated size , then find the
* difference , divide it by the number of expanding items per
* ( row | col ) . Divide the total size by the number of ( rows | cols ) , then
* iterate . Allocate expanders the per - cell size plus the extra for
* expansion . Allocate shrinkers / default just the per - cell size .
*
* If the natural size if greated than the allocated size , find the
* difference , divide it by the number of shrinking items per
* ( row | col ) . Divide the total size by the number of ( rows | cols ) , then
* iterate . Allocate shrinkers the per - cell size minus the excess for
* shrinking . Allocate expanders / default just the per - cell size .
*
*/
2021-10-01 20:38:18 -04:00
const uint32_t elastic_rows = rows - inelastic_rows ;
const uint32_t elastic_cols = cols - inelastic_cols ;
Distance elastic_col_width = 0 ;
Distance elastic_row_height = 0 ;
2021-09-14 00:00:21 -04:00
2021-10-01 20:38:18 -04:00
DEBUG_TRACE ( DEBUG : : CanvasTable , string_compose ( " vr,vc %1 x %2 \n " , elastic_rows , elastic_cols ) ) ;
2021-09-14 00:00:21 -04:00
2021-10-02 18:19:40 -04:00
if ( row_homogenous ) {
2021-09-23 13:47:01 -04:00
2021-10-01 20:38:18 -04:00
/* all columns must have the same width and height */
elastic_row_height = ( within . height ( ) - ( ( rows - 1 ) * row_spacing ) - padding . up - padding . down ) / rows ;
} else {
2021-10-02 18:19:40 -04:00
if ( elastic_rows ) {
const Distance elastic_non_spacing_non_padding_height = within . height ( ) - inelastic_height - ( ( rows - 1 ) * row_spacing ) - padding . up - padding . down ;
elastic_row_height = elastic_non_spacing_non_padding_height / elastic_rows ;
}
}
2021-10-01 20:38:18 -04:00
2021-10-02 18:19:40 -04:00
if ( col_homogenous ) {
elastic_col_width = ( within . width ( ) - ( ( cols - 1 ) * col_spacing ) - padding . left - padding . right ) / cols ;
} else {
2021-10-01 20:38:18 -04:00
if ( elastic_cols ) {
const Distance elastic_non_spacing_non_padding_width = within . width ( ) - inelastic_width - ( ( cols - 1 ) * col_spacing ) - padding . left - padding . right ;
elastic_col_width = elastic_non_spacing_non_padding_width / elastic_cols ;
}
2021-09-17 14:34:07 -04:00
}
2021-09-14 18:08:33 -04:00
2021-09-17 14:34:07 -04:00
for ( auto & ci : cells ) {
2021-09-14 00:00:21 -04:00
2021-09-17 14:34:07 -04:00
CellInfo & c ( ci . second ) ;
2021-09-14 18:08:33 -04:00
2021-09-17 14:34:07 -04:00
const float hspan = c . lower_right . x - c . upper_left . x ;
const float vspan = c . lower_right . y - c . upper_left . y ;
2021-09-14 18:08:33 -04:00
2021-10-01 20:38:18 -04:00
AxisInfo & col ( col_info [ c . upper_left . x ] ) ;
AxisInfo & row ( row_info [ c . upper_left . y ] ) ;
2021-09-14 18:08:33 -04:00
2021-09-17 14:34:07 -04:00
Distance w ;
Distance h ;
2021-09-14 20:29:06 -04:00
2021-09-17 14:34:07 -04:00
if ( col . user_size ) {
w = col . user_size ;
} else if ( c . row_options & PackExpand ) {
2021-10-01 20:38:18 -04:00
w = hspan * elastic_col_width + ( ( hspan - 1 ) * col_spacing ) ;
2021-09-17 14:34:07 -04:00
} else if ( c . row_options & PackShrink ) {
2021-10-01 20:38:18 -04:00
w = hspan * elastic_col_width + ( ( hspan - 1 ) * col_spacing ) ;
2021-09-17 14:34:07 -04:00
} else {
/* normal col, not expanding or shrinking */
w = c . natural_size . x ;
}
2021-09-14 18:08:33 -04:00
2021-09-17 14:34:07 -04:00
if ( row . user_size ) {
h = col . user_size ;
} else if ( c . row_options & PackExpand ) {
2021-10-01 20:38:18 -04:00
h = vspan * elastic_row_height + ( ( vspan - 1 ) * row_spacing ) ;
2021-09-17 14:34:07 -04:00
} else if ( c . row_options & PackShrink ) {
2021-10-01 20:38:18 -04:00
h = vspan * elastic_row_height + ( ( vspan - 1 ) * row_spacing ) ;
2021-09-17 14:34:07 -04:00
} else {
/* normal row, not expanding or shrinking */
h = c . natural_size . y ;
2021-09-14 00:00:21 -04:00
}
2021-10-01 20:38:18 -04:00
/* Reduce the allocate width x height to account for cell
* padding and individual column / row spacing . Do not adjust for
* global padding or global column / row spacing , since that was
* already accounted for when we computed
* elastic_ { row_height , col_width }
*/
2021-09-17 14:34:07 -04:00
w - = c . padding . left + c . padding . right ;
w - = col . spacing ;
2021-09-14 18:08:33 -04:00
2021-09-17 14:34:07 -04:00
h - = c . padding . up + c . padding . down ;
h - = row . spacing ;
2021-09-14 18:08:33 -04:00
2021-10-01 20:38:18 -04:00
if ( w < 0 | | w > within . width ( ) ) {
/* can't do anything */
return Duple ( within . width ( ) , within . height ( ) ) ;
}
if ( h < 0 | | h > within . height ( ) ) {
/* can't do anything */
return Duple ( within . width ( ) , within . height ( ) ) ;
}
DEBUG_TRACE ( DEBUG : : CanvasTable , string_compose ( " Cell %9 @ %1,%2 - %3,%4 (hspan %7 vspan %8) allocated %5 x %6 \n " ,
ci . first . x , ci . first . y , ci . second . lower_right . x , ci . second . lower_right . y , w , h , hspan , vspan , ci . second . content - > whoami ( ) ) ) ;
2021-09-14 00:00:21 -04:00
2021-09-17 14:34:07 -04:00
c . allocate_size = Duple ( w , h ) ;
}
2021-09-14 18:08:33 -04:00
/* final pass: actually allocate position for each cell. Do this in a
* row , col order so that we can set up position based on all cells
* above and left of whichever one we are working on .
*/
2021-09-14 00:00:21 -04:00
2021-10-01 20:38:18 -04:00
Distance vpos = padding . up ;
Distance hpos ;
2021-09-14 00:00:21 -04:00
for ( uint32_t r = 0 ; r < rows ; + + r ) {
2021-10-01 20:38:18 -04:00
hpos = padding . left ;
2021-09-14 18:08:33 -04:00
Distance vshift = 0 ;
2021-09-14 00:00:21 -04:00
for ( uint32_t c = 0 ; c < cols ; + + c ) {
2021-09-14 20:29:06 -04:00
Index idx ( c , r ) ;
2021-09-14 00:00:21 -04:00
Cells : : iterator ci = cells . find ( idx ) ;
if ( ci ! = cells . end ( ) ) {
2021-10-01 20:38:18 -04:00
Rect rect = Rect ( hpos + ci - > second . padding . left , /* x0 */
vpos + ci - > second . padding . up , /* y0 */
hpos + ci - > second . padding . left + ci - > second . allocate_size . x , /* x1 */
vpos + ci - > second . padding . up + ci - > second . allocate_size . y ) ; /* y1 */
2021-09-14 18:08:33 -04:00
2021-10-01 20:38:18 -04:00
DEBUG_TRACE ( DEBUG : : CanvasTable , string_compose ( " Item %7 @ %1,%2 - %3,%4 size-allocate %5 vs %6 \n " ,
2021-09-14 20:29:06 -04:00
ci - > second . upper_left . x ,
ci - > second . upper_left . y ,
ci - > second . lower_right . x ,
ci - > second . lower_right . y ,
2021-10-01 20:38:18 -04:00
rect , ci - > second . allocate_size ,
ci - > second . content - > whoami ( ) ) ) ;
2021-09-23 13:47:01 -04:00
2021-09-14 20:29:06 -04:00
2021-09-14 00:00:21 -04:00
ci - > second . content - > size_allocate ( rect ) ;
2021-09-14 23:39:24 -04:00
ci - > second . full_size = rect ;
2021-09-14 18:08:33 -04:00
2021-10-02 18:19:40 -04:00
if ( col_homogenous | | ( ci - > second . col_options & PackOptions ( PackExpand | PackShrink ) ) ) {
2021-10-01 20:38:18 -04:00
/* homogenous forces all col widths to
the same value , and / or the cell
is allowed to expand / shrink to the
allotted variable column width .
*/
hpos = padding . left + ( elastic_col_width * ( c + 1 ) ) ;
2021-09-23 13:47:01 -04:00
} else {
2021-10-01 20:38:18 -04:00
/* not homogeneous, and no
expand / shrink being applied to
contents . We need to skip over to
the start of the next column here .
But . . . we can ' t just use the
allocation rect , since that is
probably too small / too large .
So . . . where is the start of the next
2021-10-02 19:45:43 -04:00
column . Well , it ' s at the greater of
( a ) right edge of this cell ' s
natural box OR ( b ) wherever the nth
elastic column would be .
2021-10-01 20:38:18 -04:00
*/
2021-10-02 19:45:43 -04:00
2021-10-01 20:38:18 -04:00
/* rect already includes padding.left */
hpos = std : : max ( rect . x1 + ci - > second . padding . right , padding . left + ( elastic_col_width * ( c + 1 ) ) ) ;
2021-09-23 13:47:01 -04:00
}
2021-10-02 18:19:40 -04:00
if ( row_homogenous | | ( ci - > second . row_options & PackOptions ( PackExpand | PackShrink ) ) ) {
2021-10-01 20:38:18 -04:00
/* homogenous forces all row heights to
the same value , and / or the cell
is allowed to expand / shrink to the
allotted variable row height .
*/
vshift = std : : max ( vshift , elastic_row_height ) ;
2021-09-23 13:47:01 -04:00
} else {
/* rect already includes padding.up */
2021-10-01 20:38:18 -04:00
vshift = std : : max ( vshift , rect . height ( ) + ci - > second . padding . down ) ;
2021-09-23 13:47:01 -04:00
}
2021-09-14 18:08:33 -04:00
2021-10-01 20:38:18 -04:00
/* when this row is done, we'll shift down by
the largest cell height so far for this row .
*/
2021-09-14 18:08:33 -04:00
2021-09-14 00:00:21 -04:00
} else {
2021-10-01 20:38:18 -04:00
2021-09-29 13:20:12 -04:00
/* cell is empty, just adjust horizontal &
vertical shift values to get to the next
cell
2021-10-01 20:38:18 -04:00
2021-09-29 13:20:12 -04:00
*/
2021-10-02 18:19:40 -04:00
if ( col_homogenous ) {
2021-10-01 20:38:18 -04:00
hpos = elastic_col_width * ( c + 1 ) ;
} else {
hpos + = col_info [ c ] . natural_size ;
2021-10-02 18:19:40 -04:00
}
if ( row_homogenous ) {
vshift = std : : max ( vshift , elastic_row_height ) ;
} else {
2021-10-01 20:38:18 -04:00
vshift = std : : max ( vshift , row_info [ r ] . natural_size ) ;
}
2021-09-14 00:00:21 -04:00
}
2021-09-14 18:08:33 -04:00
2021-10-01 20:38:18 -04:00
if ( c < ( cols - 1 ) ) {
hpos + = col_info [ c ] . spacing ;
hpos + = col_spacing ;
}
} /* end of a row */
2021-10-02 17:16:39 -04:00
/* add per-row and global row-spacing to the vertical
2021-10-01 20:38:18 -04:00
shift when we reach the end of the row .
*/
2021-09-14 18:08:33 -04:00
vshift + = row_info [ r ] . spacing ;
2021-10-01 20:38:18 -04:00
vshift + = row_spacing ;
vpos + = vshift ;
2021-09-14 18:08:33 -04:00
}
2021-10-02 17:16:39 -04:00
/* We never take padding.right into account for layout, and hpos is reset to zero as we start a
* new row , but we want this set correctly as we exit the loop
*/
hpos + = padding . right ;
2021-10-02 18:11:58 -04:00
/* set bounding box so that we don't have to do it again in ::compute_bounding_box() */
_bounding_box = Rect ( 0 , 0 , hpos , vpos ) ;
2021-10-03 18:46:25 -04:00
DEBUG_TRACE ( DEBUG : : CanvasTable , string_compose ( " table bbox in compute() %1 \n " , _bounding_box ) ) ;
2021-10-02 18:11:58 -04:00
/* return our size */
2021-10-01 20:38:18 -04:00
return Duple ( hpos , vpos ) ;
2021-09-14 18:08:33 -04:00
}
void
Table : : add ( Item * )
{
fatal < < _ ( " programming error: add() cannot be used with Canvas::Table; use attach() instead " ) < < endmsg ;
}
void
Table : : add_front ( Item * )
{
fatal < < _ ( " programming error: add_front() cannot be used with Canvas::Table; use attach() instead " ) < < endmsg ;
}
void
Table : : remove ( Item * )
{
fatal < < _ ( " programming error: remove() cannot be used with Canvas::Table; use detach() instead " ) < < endmsg ;
}
void
Table : : _add ( Item * i )
{
if ( ! i ) {
return ;
}
Item : : add ( i ) ;
queue_resize ( ) ;
}
void
Table : : _add_front ( Item * i )
{
if ( ! i ) {
return ;
}
Item : : add_front ( i ) ;
queue_resize ( ) ;
}
void
Table : : _remove ( Item * i )
{
if ( ! i ) {
return ;
2021-09-14 00:00:21 -04:00
}
2021-09-14 18:08:33 -04:00
Item : : remove ( i ) ;
queue_resize ( ) ;
2021-09-14 00:00:21 -04:00
}
2021-10-01 20:38:18 -04:00
void
Table : : set_row_spacing ( Distance d )
{
row_spacing = d ;
queue_resize ( ) ;
}
void
Table : : set_col_spacing ( Distance d )
{
col_spacing = d ;
queue_resize ( ) ;
}
void
Table : : set_homogenous ( bool yn )
{
2021-10-02 18:19:40 -04:00
row_homogenous = yn ;
col_homogenous = yn ;
queue_resize ( ) ;
}
void
Table : : set_row_homogenous ( bool yn )
{
row_homogenous = yn ;
queue_resize ( ) ;
}
void
Table : : set_col_homogenous ( bool yn )
{
col_homogenous = yn ;
2021-10-01 20:38:18 -04:00
queue_resize ( ) ;
}
void
Table : : set_padding ( FourDimensions const & p )
{
padding = p ;
queue_resize ( ) ;
}