File Coverage

blib/lib/Circle/FE/Term/Ribbon.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             # You may distribute under the terms of the GNU General Public License
2             #
3             # (C) Paul Evans, 2012-2013 -- leonerd@leonerd.org.uk
4              
5             package Circle::FE::Term::Ribbon;
6              
7 1     1   3469 use strict;
  1         3  
  1         24  
8 1     1   4 use warnings;
  1         2  
  1         24  
9              
10 1     1   5 use base qw( Tickit::Widget::Tabbed::Ribbon );
  1         1  
  1         340  
11              
12             package Circle::FE::Term::Ribbon::horizontal;
13             use base qw( Circle::FE::Term::Ribbon );
14              
15             use feature qw( switch );
16             no if $] >= 5.017011, warnings => 'experimental::smartmatch';
17              
18             use Tickit::Utils qw( textwidth );
19             use List::Util qw( max first );
20             Tickit::Widget->VERSION( '0.35' ); # ->render_to_rb
21              
22             use Tickit::Style;
23              
24             style_definition base =>
25             activity_fg => "cyan";
26              
27             use constant orientation => "horizontal";
28              
29             sub lines { 1 }
30             sub cols { 1 }
31              
32             sub render_to_rb
33             {
34             my $self = shift;
35             my ( $rb, $rect ) = @_;
36              
37             my $win = $self->window or return;
38              
39             my @tabs = $self->tabs;
40             my $active = $self->active_tab;
41              
42             $rb->goto( 0, 0 );
43              
44             my $col = 0;
45             my $printed;
46              
47             if( $active ) {
48             $rb->text( $printed = sprintf( "%d", $active->index + 1 ), $active->pen );
49             $col += textwidth $printed;
50              
51             $rb->text( $printed = sprintf( ":%s | ", $active->label ) );
52             $col += textwidth $printed;
53             }
54              
55             my $rhs = sprintf " | total: %d", scalar @tabs;
56             my $rhswidth = textwidth $rhs;
57              
58             $self->{tabpos} = \my @tabpos;
59              
60             if( grep { $_ != $active and $_->level > 0 } @tabs ) {
61             my @used;
62             # Output formats: [0] = full text
63             # [1] = initialise level<2 names
64             # [2] = initialise level<3 names
65             # [3] = initialise all names
66             # [4] = hide level<2 names, initialise others
67             # [5] = hide all names
68              
69             foreach my $idx ( 0 .. $#tabs ) {
70             my $tab = $tabs[$idx];
71             next if $tab == $active;
72              
73             next unless my $level = $tab->level;
74              
75             my $width_full = textwidth sprintf "%d:%s", $idx + 1, $tab->label;
76             my $width_short = textwidth sprintf "%d:%s", $idx + 1, $tab->label_short;
77             my $width_hide = textwidth sprintf "%d", $idx + 1;
78              
79             $used[0] += 1 + $width_full;
80             $used[1] += 1 + $level < 2 ? $width_short : $width_full;
81             $used[2] += 1 + $level < 3 ? $width_short : $width_full;
82             $used[3] += 1 + $width_short;
83             $used[4] += 1 + $level < 2 ? $width_hide : $width_short;
84             $used[5] += 1 + $width_hide;
85             }
86              
87             my $space = $win->cols - $col - $rhswidth;
88              
89             my $format;
90             given( Circle::FE::Term->get_theme_var( "label_format" ) ) {
91             when( "name_and_number" ) { $format = 0 }
92             when( "initial" ) { $format = 3 }
93             when( "number" ) { $format = 5 }
94             default { die "Unrecognised label_format $_"; $format = 0 }
95             }
96              
97             $format++ while $format < $#used and $used[$format] > $space;
98              
99             my $first = 1;
100              
101             TAB: foreach my $idx ( 0 .. $#tabs ) {
102             my $tab = $tabs[$idx];
103             next if $tab == $active;
104              
105             next unless my $level = $tab->level;
106              
107             my $label;
108              
109             for( $format ) {
110             $label = sprintf "%d:%s", $idx + 1, $tab->label;
111             when( 0 ) { ; }
112             when( 1 ) { $label = sprintf "%d:%s", $idx + 1, $tab->label_short if $level < 2 }
113             when( 2 ) { $label = sprintf "%d:%s", $idx + 1, $tab->label_short if $level < 3 }
114             $label = sprintf "%d:%s", $idx + 1, $tab->label_short;
115             when( 3 ) { ; }
116             when( 4 ) { $label = sprintf "%d", $idx + 1 if $level < 2 }
117             when( 5 ) { $label = sprintf "%d", $idx + 1 }
118             }
119              
120             {
121             $rb->savepen;
122              
123             if( !$first ) {
124             $rb->setpen( $self->get_style_pen( "activity" ) );
125             $rb->text( "," );
126             $col++;
127             }
128              
129             $rb->setpen( $tab->pen );
130             $rb->text( $label );
131             my $width = textwidth $label;
132              
133             push @tabpos, [ $idx, $col, $width ];
134              
135             $col += $width;
136              
137             $rb->restore;
138             }
139              
140             $first = 0;
141             }
142             }
143              
144             $rb->erase_to( $win->cols - $rhswidth );
145              
146             $rb->text( $rhs );
147             }
148              
149             sub scroll_to_visible { }
150              
151             sub activate_next
152             {
153             my $self = shift;
154              
155             my @tabs = $self->tabs;
156             @tabs = ( @tabs[$self->active_tab_index + 1 .. $#tabs], @tabs[0 .. $self->active_tab_index - 1] );
157              
158             my $max_level = max map { $_->level } @tabs;
159             return unless $max_level > 0;
160              
161             my $next_tab = first { $_->level == $max_level } @tabs;
162              
163             $next_tab->activate if $next_tab;
164             }
165              
166             my $tab_shortcuts = "1234567890" .
167             "qwertyuiop" .
168             "sdfghjkl;'" .
169             "zxcvbnm,./";
170              
171             sub on_key
172             {
173             my $self = shift;
174             my ( $ev ) = @_;
175              
176             if( $ev->type eq "key" and $ev->str eq "M-a" ) {
177             $self->activate_next;
178             return 1;
179             }
180             elsif( $ev->type eq "key" and $ev->str =~ m/^M-(.)$/ and
181             ( my $idx = index $tab_shortcuts, $1 ) > -1 ) {
182             eval { $self->activate_tab( $idx ) }; # ignore croak on invalid index
183             return 1;
184             }
185              
186             return 0;
187             }
188              
189             sub on_mouse
190             {
191             my $self = shift;
192             my ( $ev ) = @_;
193              
194             return 0 unless $ev->line == 0;
195              
196             if( $ev->type eq "press" and $ev->button == 1 ) {
197             foreach my $pos ( @{ $self->{tabpos} } ) {
198             $self->activate_tab( $pos->[0] ), return 1 if $ev->col >= $pos->[1] and $ev->col < $pos->[1] + $pos->[2];
199             }
200             }
201             elsif( $ev->type eq "wheel" ) {
202             $self->prev_tab if $ev->button eq "up";
203             $self->next_tab if $ev->button eq "down";
204             return 1;
205             }
206             }
207              
208             0x55AA;