class Tickit::Widget::GridBox 0.29
extends
Tickit::ContainerWidget;
style_definition
base
=>
row_spacing
=> 0,
col_spacing
=> 0;
style_reshape_keys
qw( row_spacing col_spacing )
;
use
constant
WIDGET_PEN_FROM_STYLE
=> 1;
sub
new
{
my
$class
=
shift
;
my
%args
=
@_
;
exists
$args
{
$_
} and
$args
{style}{
$_
} =
delete
$args
{
$_
}
for
qw( row_spacing col_spacing )
;
my
$self
=
$class
->SUPER::new(
%args
);
$self
->{grid} = [];
$self
->{max_col} = -1;
if
(
my
$children
=
$args
{children} ) {
foreach
my
$row
( 0 ..
$#$children
) {
foreach
my
$col
( 0 .. $
$self
->add(
$row
,
$col
,
$children
->[
$row
][
$col
] );
}
}
}
return
$self
;
}
sub
lines
{
my
$self
=
shift
;
my
$row_spacing
=
$self
->get_style_values(
"row_spacing"
);
my
$max_row
= $
my
$max_col
=
$self
->{max_col};
return
( sum(
map
{
my
$r
=
$_
;
max
map
{
my
$c
=
$_
;
my
$child
=
$self
->{grid}[
$r
][
$c
];
$child
?
$child
->requested_lines : 0;
} 0 ..
$max_col
} 0 ..
$max_row
) ) +
$row_spacing
*
$max_row
;
}
sub
cols
{
my
$self
=
shift
;
my
$col_spacing
=
$self
->get_style_values(
"col_spacing"
);
my
$max_row
= $
my
$max_col
=
$self
->{max_col};
return
( sum(
map
{
my
$c
=
$_
;
max
map
{
my
$r
=
$_
;
my
$child
=
$self
->{grid}[
$r
][
$c
];
$child
?
$child
->requested_cols : 0;
} 0 ..
$max_row
} 0 ..
$max_col
) ) +
$col_spacing
*
$max_col
;
}
sub
children
{
my
$self
=
shift
;
my
$grid
=
$self
->{grid};
map
{
my
$r
=
$_
;
map
{
$grid
->[
$r
][
$_
] ? (
$grid
->[
$r
][
$_
] ) : ()
} 0 ..
$self
->{max_col}
} 0..
$#$grid
;
}
sub
rowcount
{
my
$self
=
shift
;
return
scalar
@{
$self
->{grid} }
}
sub
colcount
{
my
$self
=
shift
;
return
$self
->{max_col} + 1;
}
sub
add
{
my
$self
=
shift
;
my
(
$row
,
$col
,
$child
,
%opts
) =
@_
;
if
(
my
$old_child
=
$self
->{grid}[
$row
][
$col
] ) {
$self
->SUPER::remove(
$old_child
);
}
$self
->{max_col} =
$col
if
$col
>
$self
->{max_col};
$self
->{grid}[
$row
][
$col
] =
$child
;
$self
->SUPER::add(
$child
,
col_expand
=>
$opts
{col_expand} || 0,
row_expand
=>
$opts
{row_expand} || 0,
);
}
sub
remove
{
my
$self
=
shift
;
my
(
$row
,
$col
) =
@_
;
my
$grid
=
$self
->{grid};
my
$child
=
$grid
->[
$row
][
$col
];
undef
$grid
->[
$row
][
$col
];
my
$max_col
= 0;
foreach
my
$col
(
reverse
0 .. $
next
if
!
defined
$grid
->[
$row
][
$col
];
$max_col
=
$col
+1;
last
;
}
splice
@{
$grid
->[
$row
] },
$max_col
;
my
$max_row
= 0;
foreach
my
$row
(
reverse
0 ..
$#$grid
) {
next
if
!
defined
$grid
->[
$row
] or !@{
$grid
->[
$row
] };
$max_row
=
$row
+1;
last
;
}
splice
@$grid
,
$max_row
;
$self
->{max_col} = max
map
{
$_
?
$#$_
: 0 }
@$grid
;
my
$childrect
=
$child
->window ?
$child
->window->rect :
undef
;
$self
->SUPER::remove(
$child
);
$self
->window->expose(
$childrect
)
if
$childrect
;
}
sub
get
{
my
$self
=
shift
;
my
(
$row
,
$col
) =
@_
;
return
undef
if
$row
>= @{
$self
->{grid} };
return
$self
->{grid}[
$row
][
$col
];
}
sub
get_row
{
my
$self
=
shift
;
my
(
$row
) =
@_
;
return
map
{
$self
->get(
$row
,
$_
) } 0 ..
$self
->colcount - 1;
}
sub
get_col
{
my
$self
=
shift
;
my
(
$col
) =
@_
;
return
map
{
$self
->get(
$_
,
$col
) } 0 ..
$self
->rowcount - 1;
}
sub
insert_row
{
my
$self
=
shift
;
my
(
$row
,
$children
) =
@_
;
splice
@{
$self
->{grid} },
$row
, 0, [];
foreach
my
$col
( 0 ..
$#$children
) {
next
unless
my
$child
=
$children
->[
$col
];
$self
->add(
$row
,
$col
,
$child
);
}
}
sub
insert_col
{
my
$self
=
shift
;
my
(
$col
,
$children
) =
@_
;
my
$grid
=
$self
->{grid};
$self
->{max_col}++;
foreach
my
$row
( 0 .. max(
$self
->rowcount,
scalar
@$children
) - 1 ) {
splice
@{
$grid
->[
$row
] //= [ (
undef
) x
$col
] },
$col
, 0, (
undef
);
next
unless
my
$child
=
$children
->[
$row
];
$self
->add(
$row
,
$col
,
$child
);
}
}
sub
append_row
{
my
$self
=
shift
;
$self
->insert_row(
$self
->rowcount,
@_
);
}
sub
append_col
{
my
$self
=
shift
;
$self
->insert_col(
$self
->colcount,
@_
);
}
sub
delete_row
{
my
$self
=
shift
;
my
(
$row
) =
@_
;
$self
->remove(
$row
,
$_
)
for
0 ..
$self
->colcount - 1;
splice
@{
$self
->{grid} },
$row
, 1, ();
$self
->children_changed;
}
sub
delete_col
{
my
$self
=
shift
;
my
(
$col
) =
@_
;
$self
->remove(
$_
,
$col
)
for
0 ..
$self
->rowcount - 1;
splice
@{
$self
->{grid}[
$_
] },
$col
, 1, ()
for
0 ..
$self
->rowcount - 1;
$self
->{max_col}--;
$self
->children_changed;
}
sub
reshape
{
my
$self
=
shift
;
my
$win
=
$self
->window or
return
;
my
@row_buckets
;
my
@col_buckets
;
my
$max_row
=
$self
->rowcount - 1;
my
$max_col
=
$self
->colcount - 1;
my
(
$row_spacing
,
$col_spacing
) =
$self
->get_style_values(
qw( row_spacing col_spacing )
);
foreach
my
$row
( 0 ..
$max_row
) {
push
@row_buckets
, {
fixed
=>
$row_spacing
}
if
@row_buckets
;
my
$base
= 0;
my
$expand
= 0;
foreach
my
$col
( 0 ..
$max_col
) {
my
$child
=
$self
->{grid}[
$row
][
$col
] or
next
;
$base
= max
$base
,
$child
->requested_lines;
$expand
= max
$expand
,
$self
->child_opts(
$child
)->{row_expand};
}
push
@row_buckets
, {
row
=>
$row
,
base
=>
$base
,
expand
=>
$expand
,
};
}
foreach
my
$col
( 0 ..
$max_col
) {
push
@col_buckets
, {
fixed
=>
$col_spacing
}
if
@col_buckets
;
my
$base
= 0;
my
$expand
= 0;
foreach
my
$row
( 0 ..
$max_row
) {
my
$child
=
$self
->{grid}[
$row
][
$col
] or
next
;
$base
= max
$base
,
$child
->requested_cols;
$expand
= max
$expand
,
$self
->child_opts(
$child
)->{col_expand};
}
push
@col_buckets
, {
col
=>
$col
,
base
=>
$base
,
expand
=>
$expand
,
};
}
distribute(
$win
->lines,
@row_buckets
);
distribute(
$win
->cols,
@col_buckets
);
my
@rows
;
foreach
(
@row_buckets
) {
$rows
[
$_
->{row}] = [
$_
->{start},
$_
->{value} ]
if
defined
$_
->{row};
}
my
@cols
;
foreach
(
@col_buckets
) {
$cols
[
$_
->{col}] = [
$_
->{start},
$_
->{value} ]
if
defined
$_
->{col};
}
foreach
my
$row
( 0 ..
$max_row
) {
foreach
my
$col
( 0 ..
$max_col
) {
my
$child
=
$self
->{grid}[
$row
][
$col
] or
next
;
next
unless
$rows
[
$row
][1] and
$cols
[
$col
][1];
my
@geom
= (
$rows
[
$row
][0],
$cols
[
$col
][0],
$rows
[
$row
][1],
$cols
[
$col
][1] );
if
(
my
$childwin
=
$child
->window ) {
$childwin
->change_geometry(
@geom
);
}
else
{
$childwin
=
$win
->make_sub(
@geom
);
$child
->set_window(
$childwin
);
}
}
}
}
sub
render_to_rb
{
my
$self
=
shift
;
my
(
$rb
,
$rect
) =
@_
;
$rb
->eraserect(
$rect
);
}
0x55AA;