package Kephra::App::StatusBar;
our $VERSION = '0.09';
use strict;
use warnings;
my (@fields, @abs_border_x, %index, %width);
my $bar;
sub _ref { $bar = ref $_[0] eq 'Wx::StatusBar' ? $_[0] : $bar }
sub _config { Kephra::API::settings()->{app}{statusbar} }
sub _item { $fields[$_[0]] }
sub _l18n { Kephra::Config::Localisation::strings()->{app}{status} }
sub _none_string {
Kephra::Config::Localisation::strings()->{dialog}{general}{none};
}
sub _set_text {
my ($msg, $nr) = @_;
my $win = Kephra::App::Window::_ref();
return if not defined $nr or $nr < 0 or $nr > @fields or not $win or not defined $msg;
$win->SetStatusText($msg, $nr);
}
sub _index_from_mouse_pos {
my $x_pos = shift;
for (0 .. $#abs_border_x) {
return $_ if $width{ $fields[$_] } == -1;
return $_ if $x_pos <= $abs_border_x[$_];
}
}
#
# external API
#
sub create {
my $win = Kephra::App::Window::_ref();
$win->CreateStatusBar(1);
my $bar = $win->GetStatusBar;
my $statusbar_def = Kephra::Config::File::load_from_node_data( _config() );
unless ($statusbar_def) {
$statusbar_def = Kephra::Config::Default::toolbars()->{statusbar};
}
for my $nr (0 .. $#$statusbar_def) {
my @item = split / /, $statusbar_def->[$nr];
if ($item[0] eq 'textpanel' and defined $item[1]) {
$index{$item[1]} = $nr;
$width{$item[1]} = defined $item[2] ? $item[2] : 50;
}
}
$fields[ $index{$_} ] = $_ for keys %index;
$abs_border_x[0] = $width{ $fields[0] };
$abs_border_x[$_] = $abs_border_x[$_-1] + $width{ $fields[$_] } + 2
for 1 .. $#fields;
my $length = scalar keys %index;
$bar->SetFieldsCount( $length );
my @field_width;
$field_width[$_] = $width{ $fields[$_] } for 0 .. $length - 1;
$bar->SetStatusWidths( @field_width );
$win->SetStatusBarPane( $index{message} );
Wx::Event::EVT_LEFT_DOWN ( $bar, sub {
return unless get_interactive();
my ( $bar, $event ) = @_;
my $field = _item( _index_from_mouse_pos( $event->GetX ) );
if ($field eq 'syntaxmode') {Kephra::Document::SyntaxMode::switch_auto()}
#elsif ($field eq 'codepage') {Kephra::Document::Property::switch_codepage()}
elsif ($field eq 'tab') {Kephra::Document::Property::switch_tab_mode()}
elsif ($field eq 'EOL') {Kephra::App::EditPanel::Indicator::switch_EOL_visibility()}
elsif ($field eq 'message') {next_file_info(); }
} );
Wx::Event::EVT_RIGHT_DOWN ( $bar, sub {
return unless get_contextmenu_visibility();
my ( $bar, $event ) = @_;
my $x = $event->GetX;
my $index = _index_from_mouse_pos( $x );
my $cell_start = $bar->GetFieldRect($index)->GetTopLeft;
$x = $cell_start->x unless $width{ _item($index) } == -1;
my $y = $cell_start->y;
my $field = _item( $index );
my $menu = \&Kephra::App::ContextMenu::get;
if ($field eq 'syntaxmode'){$bar->PopupMenu( &$menu('status_syntaxmode'),$x,$y)}
elsif ($field eq 'codepage') {$bar->PopupMenu( &$menu('status_encoding'), $x,$y)}
elsif ($field eq 'tab') {$bar->PopupMenu( &$menu('status_tab'), $x,$y)}
elsif ($field eq 'EOL') {$bar->PopupMenu( &$menu('status_eol'), $x,$y)}
elsif ($field eq 'message') {$bar->PopupMenu( &$menu('status_info'), $x,$y)}
});
my $help_index = -1;
Wx::Event::EVT_MOTION ( $bar, sub {
my $index = _index_from_mouse_pos( $_[1]->GetX );
return if $index == $help_index;
$help_index = $index;
info_msg( _l18n()->{help}{ _item( $index ) } );
});
Wx::Event::EVT_LEAVE_WINDOW( $bar, sub { info_msg(''); $help_index = -1 });
Kephra::EventTable::add_call
('caret.move', 'caret_status', \&caret_pos_info, __PACKAGE__);
Kephra::EventTable::add_call
('document.text.change', 'info_msg', \&refresh_info_msg, __PACKAGE__);
Kephra::EventTable::add_call
('editpanel.focus', 'info_msg', \&refresh_info_msg, __PACKAGE__);
show();
}
sub get_visibility { _config()->{'visible'} }
sub switch_visibility {
_config()->{'visible'} ^= 1;
show();
Kephra::App::Window::_ref()->Layout();
}
sub show { Kephra::App::Window::_ref()->GetStatusBar->Show( get_visibility() ) }
sub get_interactive { _config()->{interactive} }
sub get_contextmenu_visibility { _config()->{contextmenu_visible} }
sub switch_contextmenu_visibility { _config()->{contextmenu_visible} ^= 1 }
#
# update cell content
#
sub refresh_cursor {
caret_pos_info();
refresh_info_msg();
}
sub refresh_all_cells {
refresh_cursor();
style_info();
codepage_info();
tab_info();
EOL_info();
info_msg();
}
sub caret_pos_info {
my $ep = Kephra::App::EditPanel::_ref();
my $pos = $ep->GetCurrentPos;
my $line = $ep->LineFromPosition($pos) + 1;
my $lpos = $ep->GetColumn($pos) + 1;
my $value;
# caret pos display
if ( $line > 9999 or $lpos > 9999 )
{ _set_text(" $line : $lpos", $index{cursor} ) }
else { _set_text(" $line : $lpos", $index{cursor} ) }
# selection or pos % display
my ( $sel_beg, $sel_end ) = $ep->GetSelection;
unless ( Kephra::Document::Data::attr('text_selected') ) {
my $chars = $ep->GetLength;
if ($chars) {
my $value = int 100 * $pos / $chars + .5;
$value = ' ' . $value if $value < 10;
$value = ' ' . $value . ' ' if $value < 100;
_set_text( " $value%", $index{selection} );
} else { _set_text( " 100%", $index{selection} ) }
} else {
if ( $ep->SelectionIsRectangle ) {
my $x = abs int $ep->GetColumn($sel_beg) - $ep->GetColumn($sel_end);
my $lines = 1 + abs int $ep->LineFromPosition($sel_beg)
- $ep->LineFromPosition($sel_end);
my $chars = $x * $lines;
$lines = ' ' . $lines if $lines < 100;
if ($lines < 10000) { $value = "$lines : $chars" }
else { $value = "$lines:$chars" }
_set_text( $value, $index{selection} );
} else {
my $lines = 1 + $ep->LineFromPosition($sel_end)
- $ep->LineFromPosition($sel_beg);
my $chars = $sel_end - $sel_beg -
($lines - 1) * Kephra::Document::Data::get_attribute('EOL_length');
$lines = ' ' . $lines if $lines < 100;
if ($lines < 10000) { $value = "$lines : $chars" }
else { $value = "$lines:$chars" }
_set_text( $value, $index{selection});
}
}
}
sub style_info {
my $style = shift
|| Kephra::Document::Data::attr('syntaxmode')
|| _none_string();
_set_text( '' . $style, $index{syntaxmode} );
}
sub codepage_info {
my $codepage = shift || Kephra::Document::Data::attr('codepage');
my $msg = defined $codepage
? Kephra::CommandList::get_cmd_property
( 'document-encoding-'.$codepage, 'label' )
: _none_string();
_set_text( '' . $codepage, $index{codepage} );
}
sub tab_info {
my $mode = Kephra::App::EditPanel::_ref()->GetUseTabs || 0;
my $msg = $mode ? ' HT' : ' ST';
_set_text( $msg, $index{'tab'} );
}
sub EOL_info {
my $mode = shift || Kephra::Document::Data::get_attribute('EOL') || _none_string() || 'no';
my $msg;
if ( $mode eq 'none' or $mode eq 'no' ) { $msg = _none_string() || 'no' }
elsif ( $mode eq 'cr' or $mode eq 'mac' ) { $msg = " Mac" }
elsif ( $mode eq 'lf' or $mode eq 'lin' ) { $msg = "Linux" }
elsif ( $mode eq 'cr+lf' or $mode eq 'win' ) { $msg = " Win" }
_set_text( $msg, $index{EOL} );
}
#
# info messages, last cell
#
sub status_msg { info_msg(@_) }
sub info_msg {
my $msg;
$msg .= $_ for @_;
_set_text( $msg, $index{message} );
}
sub refresh_info_msg { refresh_file_info() }
sub info_msg_nr {
my $nr = shift;
if (defined $nr) { _config()->{msg_nr} = $nr}
else { _config()->{msg_nr} }
}
sub next_file_info {
my $info_nr = _config()->{msg_nr};
$info_nr = $info_nr >= 2 ? 0 : $info_nr + 1;
set_info_msg_nr($info_nr);
}
sub set_info_msg_nr {
my $info_nr = shift || 0;
info_msg_nr($info_nr);
refresh_file_info();
}
sub refresh_file_info {
my $msg = info_msg_nr() ? _get_file_info( _config()->{msg_nr} ) : '';
_set_text( $msg, $index{message} );
}
sub _get_file_info {
my $selector = shift;
return '' unless $selector;
my $l18n = _l18n()->{label};
# show how big file is
if ( $selector == 1 ) {
my $ep = Kephra::App::EditPanel::_ref();
return sprintf ' %s: %s %s: %s',
$l18n->{chars}, _dotted_number( $ep->GetLength ),
$l18n->{lines}, _dotted_number( $ep->GetLineCount );
# show how old file is
} elsif ( $selector == 2 ) {
my $file = Kephra::Document::Data::get_file_path();
if ($file) {
my @time = localtime( $^T - ( -M $file ) * 86300 );
return sprintf ' %s: %02d:%02d - %02d.%02d.%d', $l18n->{last_change},
$time[2], $time[1], $time[3], $time[4] + 1, $time[5] + 1900;
} else {
my @time = localtime;
return sprintf ' %s: %02d:%02d - %02d.%02d.%d', $l18n->{now_is},
$time[2], $time[1], $time[3], $time[4] + 1, $time[5] + 1900;
}
}
}
sub _dotted_number {
local $_ = shift;
1 while s/^(\d+)(\d{3})/$1.$2/;
return $_;
}
1;
=head1 NAME
Kephra::App::StatusBar -
=head1 DESCRIPTION
=cut