1#  You may distribute under the terms of either the GNU General Public License
2#  or the Artistic License (the same terms as Perl itself)
3#
4#  (C) Paul Evans, 2013-2021 -- leonerd@leonerd.org.uk
5
6use Object::Pad 0.57;
7
8package Tickit::Widget::VSplit 0.34;
9class Tickit::Widget::VSplit
10   :isa(Tickit::Widget::LinearSplit);
11
12use Tickit::Style;
13use Tickit::RenderBuffer qw( LINE_SINGLE CAP_BOTH );
14
15use Carp;
16
17use List::Util qw( sum max );
18
19=head1 NAME
20
21C<Tickit::Widget::VSplit> - an adjustable vertical split between two widgets
22
23=head1 SYNOPSIS
24
25   use Tickit;
26   use Tickit::Widget::VSplit;
27   use Tickit::Widget::Static;
28
29   my $vsplit = Tickit::Widget::VSplit->new
30      ->set_left_child ( Tickit::Widget::Static->new( text => "Text above" ) ),
31      ->set_right_child( Tickit::Widget::Static->new( text => "Text below" ) );
32
33   Tickit->new( root => $vsplit )->run;
34
35=head1 DESCRIPTION
36
37This container widget holds two child widgets, displayed side by side. The two
38widgets are displayed with a vertical split bar between them, which reacts to
39mouse click-drag events, allowing the user to adjust the proportion of space
40given to the two widgets.
41
42=head1 STYLE
43
44The default style pen is used as the widget pen. The following style pen
45prefixes are also used:
46
47=over 4
48
49=item split => PEN
50
51The pen used to render the vertical split area
52
53=back
54
55The following style keys are used:
56
57=over 4
58
59=item spacing => INT
60
61The number of columns of spacing between the left and right child widgets
62
63=back
64
65The following style tags are used:
66
67=over 4
68
69=item :active
70
71Set when a mouse drag resize operation is occurring
72
73=back
74
75=cut
76
77style_definition base =>
78   split_fg => "white",
79   split_bg => "blue",
80   spacing => 1;
81
82style_definition ':active' =>
83   split_fg => "hi-white",
84   split_b => 1;
85
86style_reshape_keys qw( spacing );
87
88use constant WIDGET_PEN_FROM_STYLE => 1;
89
90use constant VALUE_METHOD => "cols";
91
92=head1 CONSTRUCTOR
93
94=head2 new
95
96   $vsplit = Tickit::Widget::VSplit->new( %args )
97
98Constructs a new C<Tickit::Widget::VSplit> object.
99
100=cut
101
102ADJUSTPARAMS
103{
104   my ( $params ) = @_;
105
106   croak "The 'left_child' constructor argument to ${\ref $self} is no longer recognised; use ->set_left_child instead"
107      if delete $params->{left_child};
108
109   croak "The 'right_child' constructor argument to ${\ref $self} is no longer recognised; use ->set_right_child instead"
110      if delete $params->{right_child};
111}
112
113method lines
114{
115   return max(
116      $self->left_child  ? $self->left_child->requested_lines  : 1,
117      $self->right_child ? $self->right_child->requested_lines : 1,
118   );
119}
120
121method cols
122{
123   my $spacing = $self->get_style_values( "spacing" );
124   return sum(
125      $self->left_child  ? $self->left_child->requested_cols  : 1,
126      $spacing,
127      $self->right_child ? $self->right_child->requested_cols : 1,
128   );
129}
130
131=head1 ACCESSORS
132
133=cut
134
135=head2 left_child
136
137=head2 set_left_child
138
139   $child = $hsplit->left_child
140
141   $vsplit->set_left_child( $child )
142
143Accessor for the child widget used in the left half of the display.
144
145=cut
146
147*left_child     = __PACKAGE__->can( "A_child" );
148*set_left_child = __PACKAGE__->can( "set_A_child" );
149
150=head2 right_child
151
152=head2 set_right_child
153
154   $child = $hsplit->right_child
155
156   $vsplit->set_right_child( $child )
157
158Accessor for the child widget used in the right half of the display.
159
160These mutators returning the container widget itself making them suitable to
161use as chaining mutators; e.g.
162
163   my $container = Tickit::Widget::VSplit->new( ... )
164      ->set_left_child ( Tickit::Widget::Box->new ... )
165      ->set_right_child( Tickit::Widget::Box->new ... );
166
167=cut
168
169*right_child     = __PACKAGE__->can( "B_child" );
170*set_right_child = __PACKAGE__->can( "set_B_child" );
171
172method _make_child_geom
173{
174   my ( $start, $len ) = @_;
175   return ( 0, $start, $self->window->lines, $len );
176}
177
178method render_to_rb
179{
180   my ( $rb, $rect ) = @_;
181
182   my $split_len = $self->_split_len;
183   my $split_at  = $self->_split_at;
184
185   my $lines = $self->window->lines;
186
187   $rb->setpen( $self->get_style_pen( "split" ) );
188
189   $rb->vline_at( 0, $lines-1, $split_at, LINE_SINGLE, undef, CAP_BOTH );
190
191   if( $split_len > 2 ) {
192      foreach my $line ( $rect->linerange ) {
193         $rb->erase_at( $line, $split_at + 1, $split_len - 2 );
194      }
195   }
196   if( $split_len > 1 ) {
197      $rb->vline_at( 0, $lines-1, $split_at + $split_len - 1, LINE_SINGLE, undef, CAP_BOTH );
198   }
199}
200
201method on_mouse
202{
203   my ( $args ) = @_;
204
205   if( $args->type ne "wheel" and $args->button == 1 ) {
206      return $self->_on_mouse( $args->type, $args->col );
207   }
208   return;
209}
210
211=head1 AUTHOR
212
213Paul Evans <leonerd@leonerd.org.uk>
214
215=cut
216
2170x55AA;
218