2016-09-25 15:46:07 -04:00
/*
2019-08-02 22:40:09 -04:00
* Copyright ( C ) 2012 Carl Hetherington < carl @ carlh . net >
* Copyright ( C ) 2016 - 2017 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 .
*/
2016-09-25 15:46:07 -04:00
# include <algorithm>
2021-09-10 15:02:01 -04:00
# include "pbd/compose.h"
2018-11-19 11:31:09 -05:00
# include "pbd/unwind.h"
2021-08-01 23:18:35 -04:00
# include "pbd/stacktrace.h"
2018-11-19 11:31:09 -05:00
2016-09-25 15:46:07 -04:00
# include "canvas/box.h"
2021-09-10 15:02:01 -04:00
# include "canvas/debug.h"
2016-09-25 15:46:07 -04:00
# include "canvas/rectangle.h"
using namespace ArdourCanvas ;
2021-09-10 15:02:01 -04:00
using namespace PBD ;
2016-09-25 15:46:07 -04:00
2021-08-30 19:40:06 -04:00
using std : : cerr ;
using std : : endl ;
2016-09-25 15:46:07 -04:00
Box : : Box ( Canvas * canvas , Orientation o )
2018-11-19 11:31:09 -05:00
: Rectangle ( canvas )
2016-09-25 15:46:07 -04:00
, orientation ( o )
, spacing ( 0 )
, top_padding ( 0 ) , right_padding ( 0 ) , bottom_padding ( 0 ) , left_padding ( 0 )
, top_margin ( 0 ) , right_margin ( 0 ) , bottom_margin ( 0 ) , left_margin ( 0 )
, homogenous ( false )
2018-11-19 11:31:09 -05:00
, ignore_child_changes ( false )
2016-09-25 15:46:07 -04:00
{
2021-08-01 23:18:35 -04:00
set_layout_sensitive ( true ) ;
2016-09-25 15:46:07 -04:00
}
Box : : Box ( Item * parent , Orientation o )
2018-11-19 11:31:09 -05:00
: Rectangle ( parent )
2016-09-25 15:46:07 -04:00
, orientation ( o )
, spacing ( 0 )
, top_padding ( 0 ) , right_padding ( 0 ) , bottom_padding ( 0 ) , left_padding ( 0 )
, top_margin ( 0 ) , right_margin ( 0 ) , bottom_margin ( 0 ) , left_margin ( 0 )
2016-09-25 17:44:03 -04:00
, homogenous ( false )
2018-11-19 11:31:09 -05:00
, ignore_child_changes ( false )
2016-09-25 15:46:07 -04:00
{
2021-08-01 23:18:35 -04:00
set_layout_sensitive ( true ) ;
2016-09-25 15:46:07 -04:00
}
Box : : Box ( Item * parent , Duple const & p , Orientation o )
2018-11-19 11:31:09 -05:00
: Rectangle ( parent )
2016-09-25 15:46:07 -04:00
, orientation ( o )
, spacing ( 0 )
, top_padding ( 0 ) , right_padding ( 0 ) , bottom_padding ( 0 ) , left_padding ( 0 )
, top_margin ( 0 ) , right_margin ( 0 ) , bottom_margin ( 0 ) , left_margin ( 0 )
2016-09-25 17:44:03 -04:00
, homogenous ( false )
2018-11-19 11:31:09 -05:00
, ignore_child_changes ( false )
2016-09-25 15:46:07 -04:00
{
2021-08-01 23:18:35 -04:00
set_layout_sensitive ( true ) ;
2018-11-19 11:31:09 -05:00
set_position ( p ) ;
2021-07-27 19:07:42 -04:00
set_outline_width ( 3 ) ;
2016-09-25 15:46:07 -04:00
}
void
Box : : compute_bounding_box ( ) const
{
2017-01-19 14:54:24 -05:00
_bounding_box = Rect ( ) ;
2016-09-25 15:46:07 -04:00
if ( _items . empty ( ) ) {
2021-07-27 15:13:14 -04:00
bb_clean ( ) ;
2016-09-25 15:46:07 -04:00
return ;
}
add_child_bounding_boxes ( ! collapse_on_hide ) ;
if ( _bounding_box ) {
2017-01-19 14:54:24 -05:00
Rect r = _bounding_box ;
2016-09-25 15:46:07 -04:00
2021-08-31 15:21:12 -04:00
_bounding_box = r . expand ( top_padding + outline_width ( ) + top_margin ,
2016-09-25 15:46:07 -04:00
right_padding + outline_width ( ) + right_margin ,
bottom_padding + outline_width ( ) + bottom_margin ,
2021-08-31 15:21:12 -04:00
left_padding + outline_width ( ) + left_margin ) ;
2016-09-25 15:46:07 -04:00
}
2021-07-27 15:13:14 -04:00
bb_clean ( ) ;
2016-09-25 15:46:07 -04:00
}
void
Box : : set_spacing ( double s )
{
spacing = s ;
}
void
Box : : set_padding ( double t , double r , double b , double l )
{
double last = t ;
top_padding = t ;
if ( r > = 0 ) {
last = r ;
}
right_padding = last ;
if ( b > = 0 ) {
last = b ;
}
bottom_padding = last ;
if ( l > = 0 ) {
last = l ;
}
left_padding = last ;
}
void
Box : : set_margin ( double t , double r , double b , double l )
{
double last = t ;
top_margin = t ;
if ( r > = 0 ) {
last = r ;
}
right_margin = last ;
if ( b > = 0 ) {
last = b ;
}
bottom_margin = last ;
if ( l > = 0 ) {
last = l ;
}
left_margin = last ;
}
2021-07-21 19:22:35 -04:00
void
Box : : set_homogenous ( bool yn )
{
homogenous = yn ;
}
2016-09-25 15:46:07 -04:00
void
2021-08-04 01:21:55 -04:00
Box : : _size_allocate ( Rect const & alloc )
2021-08-01 23:18:35 -04:00
{
2021-08-04 01:21:55 -04:00
Rect old_alloc ( _allocation ) ;
Rectangle : : _size_allocate ( alloc ) ;
2021-08-01 23:18:35 -04:00
2021-08-04 01:21:55 -04:00
bool width_shrinking = ( old_alloc . width ( ) > alloc . width ( ) ) ;
bool height_shrinking = ( old_alloc . height ( ) > alloc . height ( ) ) ;
reposition_children ( alloc . width ( ) , alloc . height ( ) , width_shrinking , height_shrinking ) ;
}
void
Box : : size_allocate_children ( Rect const & )
{
/* do nothing here */
2021-08-01 23:18:35 -04:00
}
void
Box : : size_request ( Distance & w , Distance & h ) const
2016-09-25 15:46:07 -04:00
{
2018-11-19 11:31:09 -05:00
Duple previous_edge = Duple ( left_margin + left_padding , top_margin + top_padding ) ;
2016-09-25 15:46:07 -04:00
Distance largest_width = 0 ;
Distance largest_height = 0 ;
2017-01-30 08:46:14 -05:00
Rect uniform_size ;
2016-09-25 15:46:07 -04:00
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " size request for %1 \n " , this ) ) ;
2016-09-25 15:46:07 -04:00
if ( homogenous ) {
2021-08-01 23:18:35 -04:00
for ( std : : list < Item * > : : const_iterator i = _items . begin ( ) ; i ! = _items . end ( ) ; + + i ) {
2021-08-04 01:21:55 -04:00
Distance iw , ih ;
( * i ) - > size_request ( iw , ih ) ;
largest_height = std : : max ( largest_height , ih ) ;
largest_width = std : : max ( largest_width , iw ) ;
2016-09-25 15:46:07 -04:00
}
2017-01-30 08:46:14 -05:00
uniform_size = Rect ( 0 , 0 , largest_width , largest_height ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " homogenous box, uniform size computed as %1 \n " , uniform_size ) ) ;
2016-09-25 15:46:07 -04:00
}
2021-07-27 19:06:32 -04:00
Rect r ;
2018-11-19 11:31:09 -05:00
{
PBD : : Unwinder < bool > uw ( ignore_child_changes , true ) ;
2017-01-30 08:46:14 -05:00
2021-08-01 23:18:35 -04:00
for ( std : : list < Item * > : : const_iterator i = _items . begin ( ) ; i ! = _items . end ( ) ; + + i ) {
2016-09-25 15:46:07 -04:00
2021-08-01 23:18:35 -04:00
double width ;
double height ;
Rect isize ;
( * i ) - > size_request ( width , height ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1, desires %2 x %3 \n " , ( * i ) - > whoami ( ) , width , height ) ) ;
2016-09-25 15:46:07 -04:00
2018-11-19 11:31:09 -05:00
if ( homogenous ) {
2021-08-01 23:18:35 -04:00
if ( ( ( * i ) - > pack_options ( ) & PackOptions ( PackExpand | PackFill ) ) = = PackOptions ( PackExpand | PackFill ) ) {
if ( orientation = = Vertical ) {
/* use the item's own height and our computed width */
isize = Rect ( previous_edge . x , previous_edge . y , previous_edge . x + uniform_size . width ( ) , previous_edge . y + height ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1, use computed width to give %2 \n " , ( * i ) - > whoami ( ) , isize ) ) ;
2021-08-01 23:18:35 -04:00
} else {
/* use the item's own width and our computed height */
isize = Rect ( previous_edge . x , previous_edge . y , previous_edge . x + width , previous_edge . y + uniform_size . height ( ) ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1, use computed height to give %2 \n " , ( * i ) - > whoami ( ) , isize ) ) ;
2021-08-01 23:18:35 -04:00
}
} else {
isize = Rect ( previous_edge . x , previous_edge . y , previous_edge . x + width , previous_edge . y + height ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1, use item size to give %2 \n " , ( * i ) - > whoami ( ) , isize ) ) ;
2021-08-01 23:18:35 -04:00
}
} else {
isize = Rect ( previous_edge . x , previous_edge . y , previous_edge . x + width , previous_edge . y + height ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1, use item size (non-homogenous) to give %2 \n " , ( * i ) - > whoami ( ) , isize ) ) ;
2016-09-25 15:46:07 -04:00
}
2021-08-01 23:18:35 -04:00
width = isize . width ( ) ;
height = isize . height ( ) ;
2016-09-25 15:46:07 -04:00
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1, initial size %2 x %3 \n " , ( * i ) - > whoami ( ) , width , height ) ) ;
2021-07-27 19:06:32 -04:00
r = r . extend ( Rect ( previous_edge . x , previous_edge . y , previous_edge . x + width , previous_edge . y + height ) ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t cumulative rect is now %1 \n " , r ) ) ;
2018-11-19 11:31:09 -05:00
if ( orientation = = Vertical ) {
2016-09-25 15:46:07 -04:00
2018-11-19 11:31:09 -05:00
Distance shift = 0 ;
if ( ! ( * i ) - > visible ( ) ) {
/* invisible child */
if ( ! collapse_on_hide ) {
/* still add in its size */
shift + = height ;
2016-09-25 15:46:07 -04:00
}
2018-11-19 11:31:09 -05:00
} else {
shift + = height ;
2016-09-25 15:46:07 -04:00
}
2018-11-19 11:31:09 -05:00
previous_edge = previous_edge . translate ( Duple ( 0 , spacing + shift ) ) ;
2017-01-30 08:46:14 -05:00
} else {
2018-11-19 11:31:09 -05:00
Distance shift = 0 ;
if ( ! ( * i ) - > visible ( ) ) {
if ( ! collapse_on_hide ) {
shift + = width ;
}
} else {
shift + = width ;
2017-01-30 08:46:14 -05:00
}
2016-09-25 15:46:07 -04:00
2018-11-19 11:31:09 -05:00
previous_edge = previous_edge . translate ( Duple ( spacing + shift , 0 ) ) ;
}
2016-09-25 15:46:07 -04:00
}
}
2021-07-27 19:06:32 -04:00
/* left and top margins+padding already reflected in child bboxes */
r = r . expand ( 0 , right_margin + right_padding , bottom_margin + bottom_padding , 0 ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " add margin and padding, get %1 \n " , r ) ) ;
2021-08-01 23:18:35 -04:00
w = r . width ( ) ;
h = r . height ( ) ;
2016-09-25 15:46:07 -04:00
}
2021-07-28 00:40:14 -04:00
void
2021-08-04 01:21:55 -04:00
Box : : reposition_children ( Distance width , Distance height , bool shrink_width , bool shrink_height )
2021-07-28 00:40:14 -04:00
{
2021-08-01 23:18:35 -04:00
Duple previous_edge = Duple ( left_margin + left_padding , top_margin + top_padding ) ;
Distance largest_width = 0 ;
Distance largest_height = 0 ;
Rect uniform_size ;
2021-09-10 15:01:26 -04:00
if ( width = = 0 & & height = = 0 ) {
return ;
}
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " allocating children within %1 x %2, shrink/w %3 shrink/h %4 \n " , width , height , shrink_width , shrink_height ) ) ;
2021-08-01 23:18:35 -04:00
if ( homogenous ) {
for ( std : : list < Item * > : : const_iterator i = _items . begin ( ) ; i ! = _items . end ( ) ; + + i ) {
2021-08-04 01:21:55 -04:00
Distance iw , ih ;
( * i ) - > size_request ( iw , ih ) ;
if ( ! shrink_height ) {
largest_height = std : : max ( largest_height , ih ) ;
}
if ( ! shrink_width ) {
largest_width = std : : max ( largest_width , iw ) ;
2021-08-01 23:18:35 -04:00
}
}
2021-09-10 15:02:01 -04:00
/* these two represent the width and height available for
* contents ( i . e . after we ' ve taken " borders " " owned " by this
* box into account )
*/
2021-08-01 23:18:35 -04:00
const Distance contents_width = width - ( left_margin + left_padding + right_margin + right_padding ) ;
const Distance contents_height = height - ( top_margin + top_padding + bottom_margin + bottom_padding ) ;
2021-08-30 19:40:06 -04:00
Distance item_width ;
Distance item_height ;
2021-08-01 23:18:35 -04:00
2021-08-04 01:21:55 -04:00
if ( orientation = = Vertical ) {
2021-08-30 19:40:06 -04:00
item_width = contents_width ;
item_height = ( contents_height - ( ( _items . size ( ) - 1 ) * spacing ) ) ; ;
} else {
item_width = ( contents_width - ( ( _items . size ( ) - 1 ) * spacing ) ) ;
item_height = contents_height ;
}
if ( orientation = = Vertical ) {
largest_width = std : : max ( largest_width , item_width ) ;
2021-08-01 23:18:35 -04:00
}
2021-08-04 01:21:55 -04:00
if ( orientation = = Horizontal ) {
2021-08-30 19:40:06 -04:00
largest_height = std : : max ( largest_height , item_height ) ;
2021-08-01 23:18:35 -04:00
}
uniform_size = Rect ( 0 , 0 , largest_width , largest_height ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " allocating for homogenous box, uniform size computed as %1 \n " , uniform_size ) ) ;
2021-08-01 23:18:35 -04:00
}
{
PBD : : Unwinder < bool > uw ( ignore_child_changes , true ) ;
for ( std : : list < Item * > : : const_iterator i = _items . begin ( ) ; i ! = _items . end ( ) ; + + i ) {
double width ;
double height ;
Rect isize ;
( * i ) - > size_request ( width , height ) ;
if ( homogenous ) {
if ( ( ( * i ) - > pack_options ( ) & PackOptions ( PackExpand | PackFill ) ) = = PackOptions ( PackExpand | PackFill ) ) {
if ( orientation = = Vertical ) {
/* use the item's own height and our computed width */
isize = Rect ( previous_edge . x , previous_edge . y , previous_edge . x + uniform_size . width ( ) , previous_edge . y + height ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1, use computed width to give %2 \n " , ( * i ) - > whoami ( ) , isize ) ) ;
2021-08-01 23:18:35 -04:00
} else {
/* use the item's own width and our computed height */
isize = Rect ( previous_edge . x , previous_edge . y , previous_edge . x + width , previous_edge . y + uniform_size . height ( ) ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1, use computed height to give %2 \n " , ( * i ) - > whoami ( ) , isize ) ) ;
2021-08-01 23:18:35 -04:00
}
} else {
isize = Rect ( previous_edge . x , previous_edge . y , previous_edge . x + width , previous_edge . y + height ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1, use item size to give %2 \n " , ( * i ) - > whoami ( ) , isize ) ) ;
2021-08-01 23:18:35 -04:00
}
} else {
isize = Rect ( previous_edge . x , previous_edge . y , previous_edge . x + width , previous_edge . y + height ) ;
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1, use item size (non-homogenous) to give %2 \n " , ( * i ) - > whoami ( ) , isize ) ) ;
2021-08-01 23:18:35 -04:00
}
2021-09-10 15:02:01 -04:00
DEBUG_TRACE ( DEBUG : : CanvasBox | DEBUG : : CanvasSizeAllocate , string_compose ( " \t %1 allocating %2 \n " , ( * i ) - > whoami ( ) , isize ) ) ;
2021-08-01 23:18:35 -04:00
( * i ) - > size_allocate ( isize ) ;
width = isize . width ( ) ;
height = isize . height ( ) ;
if ( orientation = = Vertical ) {
Distance shift = 0 ;
if ( ! ( * i ) - > visible ( ) ) {
/* invisible child */
if ( ! collapse_on_hide ) {
/* still add in its size */
shift + = height ;
}
} else {
shift + = height ;
}
previous_edge = previous_edge . translate ( Duple ( 0 , spacing + shift ) ) ;
} else {
Distance shift = 0 ;
if ( ! ( * i ) - > visible ( ) ) {
if ( ! collapse_on_hide ) {
shift + = width ;
}
} else {
shift + = width ;
}
previous_edge = previous_edge . translate ( Duple ( spacing + shift , 0 ) ) ;
}
}
}
2021-07-28 00:40:14 -04:00
}
2016-09-25 15:46:07 -04:00
void
2018-11-19 11:31:09 -05:00
Box : : add ( Item * i )
2016-09-25 15:46:07 -04:00
{
if ( ! i ) {
return ;
}
2018-11-19 11:31:09 -05:00
Item : : add ( i ) ;
queue_resize ( ) ;
2016-09-25 15:46:07 -04:00
}
2018-11-19 11:31:09 -05:00
2016-09-25 15:46:07 -04:00
void
2018-11-19 11:31:09 -05:00
Box : : add_front ( Item * i )
2016-09-25 15:46:07 -04:00
{
if ( ! i ) {
return ;
}
2018-11-19 11:31:09 -05:00
Item : : add_front ( i ) ;
queue_resize ( ) ;
2016-09-25 15:46:07 -04:00
}
void
2018-11-19 11:31:09 -05:00
Box : : layout ( )
2016-09-25 15:46:07 -04:00
{
2018-11-19 11:31:09 -05:00
bool yes_do_it = _resize_queued ;
Item : : layout ( ) ;
if ( yes_do_it ) {
2021-08-04 01:21:55 -04:00
reposition_children ( _allocation . width ( ) , _allocation . height ( ) , false , false ) ;
2018-11-19 11:31:09 -05:00
}
2016-09-25 15:46:07 -04:00
}
void
2020-06-10 17:25:22 -04:00
Box : : child_changed ( bool bbox_changed )
2016-09-25 15:46:07 -04:00
{
/* catch visibility and size changes */
2018-11-19 11:31:09 -05:00
if ( ignore_child_changes ) {
return ;
}
2020-06-10 17:25:22 -04:00
Item : : child_changed ( bbox_changed ) ;
2018-11-19 11:31:09 -05:00
2021-08-04 01:21:55 -04:00
reposition_children ( _allocation . width ( ) , _allocation . height ( ) , false , false ) ;
2016-09-25 15:46:07 -04:00
}
void
Box : : set_collapse_on_hide ( bool yn )
{
if ( collapse_on_hide ! = yn ) {
collapse_on_hide = yn ;
2021-08-04 01:21:55 -04:00
reposition_children ( _allocation . width ( ) , _allocation . height ( ) , false , false ) ;
2016-09-25 15:46:07 -04:00
}
}
/*----*/
VBox : : VBox ( Canvas * c )
: Box ( c , Vertical )
{
}
VBox : : VBox ( Item * i )
: Box ( i , Vertical )
{
}
VBox : : VBox ( Item * i , Duple const & position )
: Box ( i , position , Vertical )
{
}
HBox : : HBox ( Canvas * c )
: Box ( c , Horizontal )
{
}
HBox : : HBox ( Item * i )
: Box ( i , Horizontal )
{
}
HBox : : HBox ( Item * i , Duple const & position )
: Box ( i , position , Horizontal )
{
}