#!/usr/bin/perl
use
POSIX
qw( ceil floor round )
;
sub
_ncols(
$windows
) {
return
0
if
$windows
<= 0;
return
2
if
$windows
== 5;
ceil(
sqrt
(
$windows
));
}
sub
_nrows(
$windows
) {
return
0
if
$windows
<= 0;
ceil(
$windows
/ _ncols(
$windows
));
}
sub
_new_layout(
$windows
) {
croak
"Cannot create a layout for imaginary windows"
if
$windows
<= 0;
my
$nrows
= _nrows(
$windows
);
my
$ncols
= _ncols(
$windows
);
my
$layout
= {
nrows
=>
$nrows
,
ncols
=>
$ncols
,
rows
=> [
map
{ 1 /
$nrows
} 1..
$nrows
],
cols
=> [
map
{ 1 /
$ncols
} 1..
$ncols
],
};
my
$grid
= [
map
{ [
$_
, @{
$layout
->{rows} } ] } @{
$layout
->{cols} } ];
return
$grid
if
$ncols
== 1;
my
$extra
=
$nrows
*
$ncols
-
$windows
;
pop
@{
$grid
->[0] }
for
1..
$extra
;
push
@{
$grid
->[0] },
pop
@{
$grid
->[1] }
if
@{
$grid
->[1] } - @{
$grid
->[0] } > 1;
for
my
$arr
(@{
$grid
}[0, 1]) {
@{
$arr
} = (
shift
@{
$arr
},
map
{ 1 /
@$arr
} 1..@{
$arr
});
}
return
$grid
;
}
sub
arrange_windows(
$self
,
$windows
,
$dpy_width
,
$dpy_height
,
$x_offset
=0,
$y_offset
=0) {
croak
"Cannot arrange non-windows"
unless
ref
$windows
eq
"ARRAY"
;
return
if
@{
$windows
} < 1;
croak
"Trying to use non-initialized layout"
unless
defined
$self
->{grid};
my
$nwindows
= @{
$windows
};
my
(
$dpy_width_orig
,
$dpy_height_orig
) = (
$dpy_width
,
$dpy_height
);
my
$grid
= dclone(
$self
->{grid}->[
$nwindows
- 1] //= _new_layout(
$nwindows
));
my
@cols
=
reverse
@{
$grid
};
my
@windows
=
reverse
@{
$windows
};
my
$hide_border
= (1 ==
@windows
and 1 ==
@screens
);
my
(
$i
,
$j
) = 0 +
@cols
;
for
my
$col
(
@cols
) {
$i
--;
$j
= @{
$col
} - 1;
my
$col_w
=
shift
@{
$col
};
my
$width
= floor(
$dpy_width_orig
*
$col_w
);
my
$x
=
$dpy_width
-
$width
;
$x
--,
$width
++
if
$x
== 1;
for
my
$row_w
(
reverse
@{
$col
}) {
$j
--;
my
$height
= floor(
$dpy_height_orig
*
$row_w
);
my
$y
=
$dpy_height
-
$height
;
$y
--,
$height
++
if
$y
== 1;
my
$win
=
shift
@windows
;
croak
"Window cannot be undef"
unless
defined
$win
;
$win
->resize_and_move(
$x
+
$x_offset
,
$y
+
$y_offset
,
$width
,
$height
,
$hide_border
? 0 : ());
$win
->{real_i} =
$i
;
$win
->{real_j} =
$j
;
$dpy_height
=
$y
;
}
$dpy_height
=
$dpy_height_orig
;
$dpy_width
=
$x
;
}
$X
->flush();
}
sub
resize(
$self
,
$nwindows
,
$i
,
$j
,
$delta_x
,
$delta_y
) {
return
if
$i
< 0 or
$j
< 0 or
$nwindows
< 0;
my
$grid
=
$self
->{grid}->[
$nwindows
- 1];
return
unless
defined
$grid
and @{
$grid
} >
$i
+ (
$delta_x
? 1 : 0);
my
$col
=
$grid
->[
$i
];
return
unless
defined
$col
and @{
$col
} >
$j
+ (
$delta_y
? 2 : 1);
if
(
$delta_x
) {
next
unless
(
$delta_x
> 0 ?
$grid
->[
$i
+ 1] :
$grid
->[
$i
])->[0] >= 0.2;
$grid
->[
$i
]->[0] +=
$delta_x
;
$grid
->[
$i
+ 1]->[0] -=
$delta_x
;
}
if
(
$delta_y
) {
my
$col_size
= @{
$col
};
for
my
$col
(
grep
{
$col_size
== @{
$_
} } @{
$grid
}) {
next
unless
(
$delta_y
> 0 ?
$col
->[
$j
+ 2] :
$col
->[
$j
+ 1]) >= 0.2;
$col
->[
$j
+ 1] +=
$delta_y
;
$col
->[
$j
+ 2] -=
$delta_y
;
}
}
}
sub
new(
$self
) {
bless
{
grid
=> [] },
$self
;
}
1;