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