package Kephra::App::Panel::Output;
our $VERSION = '0.11';
use strict;
use warnings;
use Cwd();
use Wx qw(wxTheClipboard);
use Wx::Perl::ProcessStream qw(
EVT_WXP_PROCESS_STREAM_STDOUT
EVT_WXP_PROCESS_STREAM_STDERR
EVT_WXP_PROCESS_STREAM_EXIT
);
use Wx::DND;
my $output;
my $proc;
sub _ref { if (ref $_[0] eq 'Wx::TextCtrl') {$output = $_[0]} else {$output} }
sub _config { Kephra::API::settings()->{app}{panel}{output} }
sub _splitter { $Kephra::app{splitter}{bottom} }
sub _process { $proc }
sub is_process { 1 if ref $_[0] eq 'Wx::Perl::ProcessStream::Process' }
sub create {
my $win = Kephra::App::Window::_ref();
my $edit = Kephra::App::EditPanel::_ref();
my $output;
if (_ref()) {$output = _ref()}
else {
$output = Wx::TextCtrl->new
($win, -1,'', [-1,-1], [-1,-1],
&Wx::wxTE_READONLY|&Wx::wxTE_PROCESS_ENTER|&Wx::wxTE_MULTILINE|&Wx::wxTE_LEFT);
}
_ref($output);
my $config = _config();
my $color = \&Kephra::Config::color;
$output->SetForegroundColour( &$color( $config->{fore_color} ) );
$output->SetBackgroundColour( &$color( $config->{back_color} ) );
$output->SetFont( Wx::Font->new
($config->{font_size}, &Wx::wxFONTSTYLE_NORMAL, &Wx::wxNORMAL, &Wx::wxLIGHT, 0,
$config->{font_family})
);
#$output->SetEditable(0);
Kephra::EventTable::add_call('panel.output.run', 'panel_output', sub {
});
Kephra::EventTable::add_call
( 'app.splitter.bottom.changed', 'panel_notepad', sub {
if ( get_visibility() and not _splitter()->IsSplit() ) {
show( 0 );
return;
}
save_size();
});
EVT_WXP_PROCESS_STREAM_STDOUT( $win, sub {
my ($self, $event) = @_;
$event->Skip(1);
say( $event->GetLine );
} );
EVT_WXP_PROCESS_STREAM_STDERR( $win, sub {
my ($self, $event) = @_;
$event->Skip(1);
say( $event->GetLine );
} );
EVT_WXP_PROCESS_STREAM_EXIT ( $win, sub {
my ($self, $event) = @_;
$event->Skip(1);
$event->GetProcess->Destroy;
Kephra::EventTable::trigger('panel.output.run');
} );
Wx::Event::EVT_LEFT_DOWN($output, sub {
my ($op, $event) = @_;
unless ($^O =~ /darwin/i) {
my ($beside, $col, $row) = $op->HitTest( Wx::Point->new($event->GetX, $event->GetY) );
my ($begin, $end) = $op->GetSelection;
if ($beside != &Wx::wxTE_HT_UNKNOWN and $begin != $end) {
my $pos = $op->XYToPosition($col, $row);
copy_selection() if $pos >= $begin and $pos <= $end;
}
}
$event->Skip;
});
Wx::Event::EVT_MIDDLE_DOWN($output, sub {
my ($op, $event) = @_;
Kephra::Edit::Search::set_find_item( $op->GetStringSelection() );
Kephra::Edit::Search::find_next();
});
Wx::Event::EVT_KEY_DOWN( $output, sub {
my ( $op, $event ) = @_;
my $key = $event->GetKeyCode;
if ($key == &Wx::WXK_RETURN) {
copy_selection();
} elsif ($key == &Wx::WXK_F12) {
Kephra::App::Panel::Notepad::append( $output->GetStringSelection() )
if $event->ShiftDown;
}
});
$output->Show( get_visibility() );
$output;
}
sub get_visibility { _config()->{visible} }
sub switch_visibility { show( get_visibility() ^ 1 ) }
sub ensure_visibility { switch_visibility() unless get_visibility() }
sub show {
my $visibile = shift;
my $config = _config();
$visibile = $config->{visible} unless defined $visibile;
my $win = Kephra::App::Window::_ref();
my $cpanel = $Kephra::app{panel}{center};
my $output = _ref();
my $splitter = _splitter();
if ($visibile) {
$splitter->SplitHorizontally( $cpanel, $output );
$splitter->SetSashPosition( -1*$config->{size}, 1);
} else {
$splitter->Unsplit();
$splitter->Initialize( $cpanel );
}
$output->Show($visibile);
$win->Layout;
$config->{visible} = $visibile;
Kephra::EventTable::trigger('panel.output.visible');
}
sub save { save_size() }
sub save_size {
my $splitter = _splitter();
return unless $splitter->IsSplit();
my $wh=Kephra::App::Window::_ref()->GetSize->GetHeight;
_config()->{size} = -1*($wh-($wh-$splitter->GetSashPosition));
}
sub clear {
_ref()->Clear;
if (Wx::wxMAC()) {_ref()->SetFont
( Wx::Font->new(_config()->{font_size}, &Wx::wxFONTSTYLE_NORMAL,
&Wx::wxNORMAL, &Wx::wxLIGHT, 0, _config()->{font_family})
)}
}
sub print { _ref()->AppendText( $_ ) for @_ }
sub say { &print; _ref()->AppendText( "\n" ) }
sub new_output {
ensure_visibility();
_config()->{append}
? &print(_ref()->IsEmpty ? '' : "\n\n")
: &clear();
&print( @_ );
}
sub copy_selection {
my $selection = _ref()->GetStringSelection();
return unless $selection;
wxTheClipboard->Open;
wxTheClipboard->SetData( Wx::TextDataObject->new( $selection ) );
wxTheClipboard->Close;
}
#
sub display_inc { new_output('@INC:'."\n"); &say(" -$_") for @INC }
sub display_env {
new_output('%ENV:'."\n");
&say( " -$_:" . $ENV{$_} ) for sort keys %ENV;
}
sub display_selection_dec {
my $selection = Kephra::Edit::get_selection();
return unless defined $selection and $selection;
my @output = map { ' ' . $_ } unpack 'C*', $selection;
new_output(@output);
}
sub display_selection_hex {
my $selection = Kephra::Edit::get_selection();
return unless defined $selection and $selection;
my @output = map { sprintf '%3X', $_ } unpack 'C*', $selection;
new_output(@output);
}
# to be outsourced into interpreter plugin
sub run {
my $win = Kephra::App::Window::_ref();
my $doc = Kephra::Document::Data::get_file_path();
my $cmd = _config->{interpreter_path};
my $dir = Kephra::File::_dir();
Kephra::File::save();
if ($doc) {
my $cwd = Cwd::cwd();
chdir $dir;
my $proc = Wx::Perl::ProcessStream->OpenProcess
(qq~"$cmd" "$doc"~ , 'Interpreter-Plugin', $win); # -I$dir
chdir $cwd;
new_output();
Kephra::EventTable::trigger('panel.output.run');
if (not $proc) {}
} else {
my $l18n = Kephra::Config::Localisation::strings()->{app};
Kephra::App::StatusBar::info_msg
($l18n->{menu}{document}.' '.$l18n->{general}{untitled}."\n" );
}
}
sub is_running {
my $proc = _process();
$proc->IsAlive if is_process($proc);
}
sub stop {
my $proc = _process();
if ( is_process($proc) ) {
$proc->KillProcess;
$proc->TerminateProcess;
Kephra::EventTable::trigger('panel.output.run');
}
}
1;
=head1 NAME
Kephra::App::Panel::Output - output panel
=head1 DESCRIPTION
=cut