File Coverage

lib/Kephra/App/StatusBar.pm
Criterion Covered Total %
statement 6 174 3.4
branch 0 86 0.0
condition 0 44 0.0
subroutine 2 36 5.5
pod 0 21 0.0
total 8 361 2.2


line stmt bran cond sub pod time code
1             package Kephra::App::StatusBar;
2             our $VERSION = '0.09';
3 1     1   1056 use strict;
  1         3  
  1         34  
4 1     1   5 use warnings;
  1         3  
  1         3234  
5            
6             my (@fields, @abs_border_x, %index, %width);
7             my $bar;
8 0 0   0     sub _ref { $bar = ref $_[0] eq 'Wx::StatusBar' ? $_[0] : $bar }
9 0     0     sub _config { Kephra::API::settings()->{app}{statusbar} }
10 0     0     sub _item { $fields[$_[0]] }
11 0     0     sub _l18n { Kephra::Config::Localisation::strings()->{app}{status} }
12             sub _none_string {
13 0     0     Kephra::Config::Localisation::strings()->{dialog}{general}{none};
14             }
15             sub _set_text {
16 0     0     my ($msg, $nr) = @_;
17 0           my $win = Kephra::App::Window::_ref();
18 0 0 0       return if not defined $nr or $nr < 0 or $nr > @fields or not $win or not defined $msg;
      0        
      0        
      0        
19 0           $win->SetStatusText($msg, $nr);
20             }
21             sub _index_from_mouse_pos {
22 0     0     my $x_pos = shift;
23 0           for (0 .. $#abs_border_x) {
24 0 0         return $_ if $width{ $fields[$_] } == -1;
25 0 0         return $_ if $x_pos <= $abs_border_x[$_];
26             }
27             }
28             #
29             # external API
30             #
31             sub create {
32 0     0 0   my $win = Kephra::App::Window::_ref();
33 0           $win->CreateStatusBar(1);
34 0           my $bar = $win->GetStatusBar;
35            
36 0           my $statusbar_def = Kephra::Config::File::load_from_node_data( _config() );
37 0 0         unless ($statusbar_def) {
38 0           $statusbar_def = Kephra::Config::Default::toolbars()->{statusbar};
39             }
40            
41 0           for my $nr (0 .. $#$statusbar_def) {
42 0           my @item = split / /, $statusbar_def->[$nr];
43 0 0 0       if ($item[0] eq 'textpanel' and defined $item[1]) {
44 0           $index{$item[1]} = $nr;
45 0 0         $width{$item[1]} = defined $item[2] ? $item[2] : 50;
46             }
47             }
48 0           $fields[ $index{$_} ] = $_ for keys %index;
49 0           $abs_border_x[0] = $width{ $fields[0] };
50             $abs_border_x[$_] = $abs_border_x[$_-1] + $width{ $fields[$_] } + 2
51 0           for 1 .. $#fields;
52            
53 0           my $length = scalar keys %index;
54 0           $bar->SetFieldsCount( $length );
55 0           my @field_width;
56 0           $field_width[$_] = $width{ $fields[$_] } for 0 .. $length - 1;
57 0           $bar->SetStatusWidths( @field_width );
58 0           $win->SetStatusBarPane( $index{message} );
59            
60             Wx::Event::EVT_LEFT_DOWN ( $bar, sub {
61 0 0   0     return unless get_interactive();
62 0           my ( $bar, $event ) = @_;
63 0           my $field = _item( _index_from_mouse_pos( $event->GetX ) );
64 0 0         if ($field eq 'syntaxmode') {Kephra::Document::SyntaxMode::switch_auto()}
  0 0          
  0 0          
    0          
65             #elsif ($field eq 'codepage') {Kephra::Document::Property::switch_codepage()}
66 0           elsif ($field eq 'tab') {Kephra::Document::Property::switch_tab_mode()}
67 0           elsif ($field eq 'EOL') {Kephra::App::EditPanel::Indicator::switch_EOL_visibility()}
68             elsif ($field eq 'message') {next_file_info(); }
69 0           } );
70             Wx::Event::EVT_RIGHT_DOWN ( $bar, sub {
71 0 0   0     return unless get_contextmenu_visibility();
72 0           my ( $bar, $event ) = @_;
73 0           my $x = $event->GetX;
74 0           my $index = _index_from_mouse_pos( $x );
75 0           my $cell_start = $bar->GetFieldRect($index)->GetTopLeft;
76 0 0         $x = $cell_start->x unless $width{ _item($index) } == -1;
77 0           my $y = $cell_start->y;
78 0           my $field = _item( $index );
79 0           my $menu = \&Kephra::App::ContextMenu::get;
80 0 0         if ($field eq 'syntaxmode'){$bar->PopupMenu( &$menu('status_syntaxmode'),$x,$y)}
  0 0          
  0 0          
    0          
    0          
81 0           elsif ($field eq 'codepage') {$bar->PopupMenu( &$menu('status_encoding'), $x,$y)}
82 0           elsif ($field eq 'tab') {$bar->PopupMenu( &$menu('status_tab'), $x,$y)}
83 0           elsif ($field eq 'EOL') {$bar->PopupMenu( &$menu('status_eol'), $x,$y)}
84             elsif ($field eq 'message') {$bar->PopupMenu( &$menu('status_info'), $x,$y)}
85 0           });
86 0           my $help_index = -1;
87             Wx::Event::EVT_MOTION ( $bar, sub {
88 0     0     my $index = _index_from_mouse_pos( $_[1]->GetX );
89 0 0         return if $index == $help_index;
90 0           $help_index = $index;
91 0           info_msg( _l18n()->{help}{ _item( $index ) } );
92 0           });
93 0     0     Wx::Event::EVT_LEAVE_WINDOW( $bar, sub { info_msg(''); $help_index = -1 });
  0            
  0            
94            
95            
96 0           Kephra::EventTable::add_call
97             ('caret.move', 'caret_status', \&caret_pos_info, __PACKAGE__);
98 0           Kephra::EventTable::add_call
99             ('document.text.change', 'info_msg', \&refresh_info_msg, __PACKAGE__);
100 0           Kephra::EventTable::add_call
101             ('editpanel.focus', 'info_msg', \&refresh_info_msg, __PACKAGE__);
102            
103 0           show();
104             }
105 0     0 0   sub get_visibility { _config()->{'visible'} }
106             sub switch_visibility {
107 0     0 0   _config()->{'visible'} ^= 1;
108 0           show();
109 0           Kephra::App::Window::_ref()->Layout();
110             }
111 0     0 0   sub show { Kephra::App::Window::_ref()->GetStatusBar->Show( get_visibility() ) }
112 0     0 0   sub get_interactive { _config()->{interactive} }
113 0     0 0   sub get_contextmenu_visibility { _config()->{contextmenu_visible} }
114 0     0 0   sub switch_contextmenu_visibility { _config()->{contextmenu_visible} ^= 1 }
115             #
116             # update cell content
117             #
118             sub refresh_cursor {
119 0     0 0   caret_pos_info();
120 0           refresh_info_msg();
121             }
122            
123             sub refresh_all_cells {
124 0     0 0   refresh_cursor();
125 0           style_info();
126 0           codepage_info();
127 0           tab_info();
128 0           EOL_info();
129 0           info_msg();
130             }
131            
132             sub caret_pos_info {
133 0     0 0   my $ep = Kephra::App::EditPanel::_ref();
134 0           my $pos = $ep->GetCurrentPos;
135 0           my $line = $ep->LineFromPosition($pos) + 1;
136 0           my $lpos = $ep->GetColumn($pos) + 1;
137 0           my $value;
138            
139             # caret pos display
140 0 0 0       if ( $line > 9999 or $lpos > 9999 )
141 0           { _set_text(" $line : $lpos", $index{cursor} ) }
142 0           else { _set_text(" $line : $lpos", $index{cursor} ) }
143            
144             # selection or pos % display
145 0           my ( $sel_beg, $sel_end ) = $ep->GetSelection;
146 0 0         unless ( Kephra::Document::Data::attr('text_selected') ) {
147 0           my $chars = $ep->GetLength;
148 0 0         if ($chars) {
149 0           my $value = int 100 * $pos / $chars + .5;
150 0 0         $value = ' ' . $value if $value < 10;
151 0 0         $value = ' ' . $value . ' ' if $value < 100;
152 0           _set_text( " $value%", $index{selection} );
153 0           } else { _set_text( " 100%", $index{selection} ) }
154             } else {
155 0 0         if ( $ep->SelectionIsRectangle ) {
156 0           my $x = abs int $ep->GetColumn($sel_beg) - $ep->GetColumn($sel_end);
157 0           my $lines = 1 + abs int $ep->LineFromPosition($sel_beg)
158             - $ep->LineFromPosition($sel_end);
159 0           my $chars = $x * $lines;
160 0 0         $lines = ' ' . $lines if $lines < 100;
161 0 0         if ($lines < 10000) { $value = "$lines : $chars" }
  0            
162 0           else { $value = "$lines:$chars" }
163 0           _set_text( $value, $index{selection} );
164             } else {
165 0           my $lines = 1 + $ep->LineFromPosition($sel_end)
166             - $ep->LineFromPosition($sel_beg);
167 0           my $chars = $sel_end - $sel_beg -
168             ($lines - 1) * Kephra::Document::Data::get_attribute('EOL_length');
169 0 0         $lines = ' ' . $lines if $lines < 100;
170 0 0         if ($lines < 10000) { $value = "$lines : $chars" }
  0            
171 0           else { $value = "$lines:$chars" }
172 0           _set_text( $value, $index{selection});
173             }
174             }
175             }
176            
177             sub style_info {
178 0   0 0 0   my $style = shift
179             || Kephra::Document::Data::attr('syntaxmode')
180             || _none_string();
181 0           _set_text( '' . $style, $index{syntaxmode} );
182             }
183             sub codepage_info {
184 0   0 0 0   my $codepage = shift || Kephra::Document::Data::attr('codepage');
185 0 0         my $msg = defined $codepage
186             ? Kephra::CommandList::get_cmd_property
187             ( 'document-encoding-'.$codepage, 'label' )
188             : _none_string();
189 0           _set_text( '' . $codepage, $index{codepage} );
190             }
191             sub tab_info {
192 0   0 0 0   my $mode = Kephra::App::EditPanel::_ref()->GetUseTabs || 0;
193 0 0         my $msg = $mode ? ' HT' : ' ST';
194 0           _set_text( $msg, $index{'tab'} );
195             }
196            
197             sub EOL_info {
198 0   0 0 0   my $mode = shift || Kephra::Document::Data::get_attribute('EOL') || _none_string() || 'no';
199 0           my $msg;
200 0 0 0       if ( $mode eq 'none' or $mode eq 'no' ) { $msg = _none_string() || 'no' }
  0 0 0        
    0 0        
    0 0        
      0        
201 0           elsif ( $mode eq 'cr' or $mode eq 'mac' ) { $msg = " Mac" }
202 0           elsif ( $mode eq 'lf' or $mode eq 'lin' ) { $msg = "Linux" }
203 0           elsif ( $mode eq 'cr+lf' or $mode eq 'win' ) { $msg = " Win" }
204 0           _set_text( $msg, $index{EOL} );
205             }
206             #
207             # info messages, last cell
208             #
209 0     0 0   sub status_msg { info_msg(@_) }
210             sub info_msg {
211 0     0 0   my $msg;
212 0           $msg .= $_ for @_;
213 0           _set_text( $msg, $index{message} );
214             }
215 0     0 0   sub refresh_info_msg { refresh_file_info() }
216            
217             sub info_msg_nr {
218 0     0 0   my $nr = shift;
219 0 0         if (defined $nr) { _config()->{msg_nr} = $nr}
  0            
220 0           else { _config()->{msg_nr} }
221             }
222            
223             sub next_file_info {
224 0     0 0   my $info_nr = _config()->{msg_nr};
225 0 0         $info_nr = $info_nr >= 2 ? 0 : $info_nr + 1;
226 0           set_info_msg_nr($info_nr);
227             }
228            
229             sub set_info_msg_nr {
230 0   0 0 0   my $info_nr = shift || 0;
231 0           info_msg_nr($info_nr);
232 0           refresh_file_info();
233             }
234            
235             sub refresh_file_info {
236 0 0   0 0   my $msg = info_msg_nr() ? _get_file_info( _config()->{msg_nr} ) : '';
237 0           _set_text( $msg, $index{message} );
238             }
239            
240             sub _get_file_info {
241 0     0     my $selector = shift;
242 0 0         return '' unless $selector;
243 0           my $l18n = _l18n()->{label};
244            
245             # show how big file is
246 0 0         if ( $selector == 1 ) {
    0          
247 0           my $ep = Kephra::App::EditPanel::_ref();
248            
249 0           return sprintf ' %s: %s %s: %s',
250             $l18n->{chars}, _dotted_number( $ep->GetLength ),
251             $l18n->{lines}, _dotted_number( $ep->GetLineCount );
252            
253             # show how old file is
254             } elsif ( $selector == 2 ) {
255 0           my $file = Kephra::Document::Data::get_file_path();
256 0 0         if ($file) {
257 0           my @time = localtime( $^T - ( -M $file ) * 86300 );
258 0           return sprintf ' %s: %02d:%02d - %02d.%02d.%d', $l18n->{last_change},
259             $time[2], $time[1], $time[3], $time[4] + 1, $time[5] + 1900;
260             } else {
261 0           my @time = localtime;
262 0           return sprintf ' %s: %02d:%02d - %02d.%02d.%d', $l18n->{now_is},
263             $time[2], $time[1], $time[3], $time[4] + 1, $time[5] + 1900;
264             }
265             }
266             }
267            
268             sub _dotted_number {
269 0     0     local $_ = shift;
270 0           1 while s/^(\d+)(\d{3})/$1.$2/;
271 0           return $_;
272             }
273            
274             1;
275