Source

Kephra / lib / Kephra / App / Bar / Document.pm

use v5.12;
use warnings;
use Wx;
use Wx::AUI;
use Kephra::API;
use Kephra::API::Command;

package Kephra::App::Bar::Document;
our @ISA = 'Wx::AuiNotebook';
our $_ref;

use Scalar::Util qw(blessed looks_like_number);


Kephra::API::Command::register({
 'docbar-select-left'     =>{sub=>'$docbar->select_page_left',     label=>'Previous Tab',  keys=>'ctrl+pageup'},
 'docbar-select-right'    =>{sub=>'$docbar->select_page_right',    label=>'Next Tab',      keys=>'ctrl+pagedown'},
 #'docbar-select-leftmost'=>{sub=>'$docbar->select_page_leftmost', label=>'First Tab',     keys=>'ctrl+shift+pageup'},
 #'docbar-select-rightmost'=>{sub=>'$docbar->select_page_rightmost',label=>'Last Tab',      keys=>'ctrl+shift+pagedown'},
 'docbar-move-left'       =>{sub=>'$docbar->move_page_left',       label=>'Move Left',     keys=>'ctrl+shift+pageup'},
 'docbar-move-right'      =>{sub=>'$docbar->move_page_right',      label=>'Move Right',    keys=>'ctrl+shift+pagedown'},
 #'docbar-move-leftmost'   =>{sub=>'$docbar->move_page_leftmost',   label=>'Move Leftmost', keys=>'alt+shift+pageup'},
 #'docbar-move-rightmost'  =>{sub=>'$docbar->move_page_rightmost',  label=>'Move Rightmost',keys=>'alt+shift+pagedown'},
});


sub new {
	my( $class, $parent) = @_;
	my $self = $_ref = $class->SUPER::new( $parent, -1, [-1,-1], [-1,-1],
		&Wx::wxAUI_NB_TOP | &Wx::wxAUI_NB_TAB_MOVE | &Wx::wxAUI_NB_WINDOWLIST_BUTTON |
		&Wx::wxAUI_NB_SCROLL_BUTTONS | &Wx::wxAUI_NB_CLOSE_ON_ACTIVE_TAB
	);

	$self->{'visual_page_order'} = [];   # visual order of internal pos : vis -> int
	$self->{'internal_page_order'} = []; # internal order of visual pos : int -> vis

	$_->add_instance($self) for Kephra::API::all_documents();
	$self->mount_events();

	return $self;
}

sub Destroy {
	my ($self) = @_;
	$_->del_instance($self) for Kephra::API::all_documents();
	$self->SUPER::Destroy( );
	1;
}

sub mount_events {
	my ($self) = @_;
	#Wx::Event::EVT_SET_FOCUS ($self,  sub { print "focus--\n";$_[1]->Skip });
	Wx::Event::EVT_AUINOTEBOOK_BEGIN_DRAG( $self, -1, sub {
		my ($bar, $event ) = @_;
		$bar->{'DND_page_nr'} = $event->GetSelection;
	});
	Wx::Event::EVT_AUINOTEBOOK_END_DRAG($self, -1, sub {
		my ($bar, $event ) = @_;
		return unless defined $bar->{'DND_page_nr'};
		$bar->move_page_position_visually($bar->{'DND_page_nr'}, $event->GetSelection);
		$bar->{'DND_page_nr'} = undef;
		Kephra::App::Focus::stay();
	});
	Wx::Event::EVT_AUINOTEBOOK_PAGE_CHANGED( $self, -1, sub {
		my ($bar, $event ) = @_;
		my $new_page = $bar->GetPage( $event->GetSelection );
		Kephra::API::Doc::set_active( $new_page );
		Kephra::API::main_window()->refresh_title();
		Kephra::API::focus( $new_page );
		$event->Skip;
	});
	Wx::Event::EVT_AUINOTEBOOK_PAGE_CLOSE( $self, -1, sub {
		my ($bar, $event ) = @_; 
		$event->Veto;
		Kephra::File::close_active();
	});
	# keep focus on editor even when klicking on tab bar
	#Wx::Event::EVT_LEFT_DOWN( $self, sub { Kephra::API::active_editor()->focus; print "--down"; });
	#$self->Connect( -1, -1, &Wx::wxEVT_SET_FOCUS, sub {  print "--"; } )
	#Wx::Event::EVT_SET_FOCUS( $self, sub { my ($bar, $event ) = @_; $event->Skip; say "--bar"; });
}

sub unmount_events {
	my ($self) = @_;
	Wx::Event::EVT_AUINOTEBOOK_BEGIN_DRAG( $self, -1, sub {});
	Wx::Event::EVT_AUINOTEBOOK_END_DRAG  ( $self, -1, sub {});
	Wx::Event::EVT_AUINOTEBOOK_PAGE_CHANGED( $self, -1, sub {});
	Wx::Event::EVT_AUINOTEBOOK_PAGE_CLOSE  ( $self, -1, sub {});
}


sub add_page {
	my ($self, $new_page, $position, $title, $set_active) = @_;
	return Kephra::Log::warning( "got no panel", 1 ) until Kephra::App::Util::is_panel($new_page);
	my $active_pos = $self->GetSelection;

	$title    = ''                           unless defined $title;
	$position = 'right'                      if $position eq 'default' or $position eq -1;
	$position = $self->rightmost_page_pos+1  if $position eq 'rightmost';
	$position = $active_pos + 1              if $position eq 'right';
	$position = $active_pos                  if $position eq 'left';
	$position = $self->leftmost_page_pos     if $position eq 'leftmost';
	$set_active = 0                          unless defined $set_active;

	$new_page->Reparent($self);
	$self->InsertPage( $position, $new_page, $title, $set_active);
	#$self->set_page_title( $title, $new_page );
	Kephra::API::focus($new_page) if $set_active;

	# inserting new index to position translators
	for   (@{$self->{'visual_page_order'}}){ $_++ if $_ >= $position }
	splice @{$self->{'visual_page_order'}},  $position, 0, $position;
	$self->refresh_internal_page_order();

	$self;
}

sub remove_page {
	my ($self, $page) = @_;
	my $internal_position = $self->GetPageIndex( $page );

	$self->RemovePage( $internal_position );
	my $visual_position = $self->{'internal_page_order'}[$internal_position];
	my $visual = $self->{'visual_page_order'};
	splice @$visual, $visual_position, 1;
	for (@$visual) {$_-- if $_ >= $internal_position}
	$self->{'visual_page_order'} = $visual;
	$self->refresh_internal_page_order;
}


sub refresh_internal_page_order {       # sync visual_page_order index with internal_page_order after each change
	my ($self) = @_;
	my $visual = $self->{'visual_page_order'};
	return unless ref $visual eq ref [];
	my $internal;
	$internal->[ $visual->[$_] ] = $_ for 0 .. @$visual-1;
	$self->{'internal_page_order'} = $internal;
}

sub move_page_position_visually {          # for dnd only
	my ($self, $from, $to ) = @_;
	return unless $from >= 0 and $from < $self->GetPageCount;
	return unless $to >= 0 and $to < $self->GetPageCount;
	my $position = splice @{$self->{'visual_page_order'}}, $from, 1;
	splice @{$self->{'visual_page_order'}}, $to, 0, $position;
	$self->refresh_internal_page_order();
}

sub move_page_visually  {               # for movements by keyboard
	my ($self, $from, $to ) = @_;
	my $max = $self->GetPageCount - 1;
	return if $from < 0 or $from > $max;
	return if $to < 0 or $to > $max;
	return if $from == $to;

	my $pos = $self->{'visual_page_order'}[ $from ];
	my $page = $self->GetPage( $pos );
	my $label = $self->GetPageText( $pos );
	my $visual = $self->{'visual_page_order'};

	$self->unmount_events();
	$self->RemovePage( $pos );
	$self->InsertPage( $to, $page, $label);
	my $removed = splice @$visual, $from, 1;
	if ($from < $to) { for (@$visual) {$_-- if $_ > $removed and $_ <= $to} }
	else             { for (@$visual) {$_++ if $_ < $removed and $_ >= $to} }
	splice @$visual, $to, 0, $to;
	$self->{'visual_page_order'} = $visual;
	$self->refresh_internal_page_order();
	$self->SetSelection( $self->{'visual_page_order'}[$to] );
	$self->mount_events();
}

sub move_page_left      {
	my ($self) = @_;
	$self->move_page_visually ( 
		$self->active_visual_pos, $self->next_page_pos_rot_left( $self->GetSelection )
	);
}
sub move_page_right     {
	my ($self) = @_;
	$self->move_page_visually( 
		$self->active_visual_pos, $self->next_page_pos_rot_right( $self->GetSelection )
	);
}
sub move_page_leftmost  { 
	my ($self) = @_;
	$self->move_page_visually( $self->active_visual_pos, $self->leftmost_page_pos );
}
sub move_page_rightmost { 
	my ($self) = @_;
	$self->move_page_visually( $self->active_visual_pos, $self->rightmost_page_pos );
}

sub select_page_left    { 
	my ($self) = @_;
	$self->raise_page( $self->next_page_pos_rot_left( $self->GetSelection ) );
}
sub select_page_right   { 
	my ($self) = @_;
	$self->raise_page( $self->next_page_pos_rot_right( $self->GetSelection ) );
}
sub select_page_leftmost  { $_[0]->raise_page( $_[0]->leftmost_page_pos ) }
sub select_page_rightmost { $_[0]->raise_page( $_[0]->rightmost_page_pos ) }

sub active_visual_pos     { $_[0]->{'internal_page_order'}[ $_[0]->GetSelection ] }
sub leftmost_page_pos     { 0 }
sub rightmost_page_pos    { $_[0]->GetPageCount-1 }
sub valid_page_pos        { 
	1 if $_[1] >= $_[0]->leftmost_page_pos and $_[1]<= $_[0]->rightmost_page_pos
}
sub next_page_pos_rot_left{
	my ($self) = @_; # take in position of internal order
	my $pos = $self->{'internal_page_order'}[ $_[1] ];
	$self->{'visual_page_order'}[$pos == 0 ? $self->rightmost_page_pos : $pos-1]
}
sub next_page_pos_rot_right{
	my ($self) = @_; # take in position of internal order
	my $pos = $self->{'internal_page_order'}[ $_[1] ];
	$self->{'visual_page_order'}[$pos == $self->rightmost_page_pos ? 0 : $pos+1]
}


sub raise_page    {
	my ($self, $pop) = @_; # can be Position Or Page (panel reference)
	my $position = int $pop eq $pop ? $pop : $self->GetPageIndex($pop);
	return unless $self->valid_page_pos( $position );
	# if just selecting the currrent, only tab drives focus nuts
	$self->SetSelection( $position ) unless $position == $self->GetSelection;
	my $page = $self->GetPage($position);
	my $doc = Kephra::API::Doc::find($page);
	Kephra::API::Doc::set_active( $doc );
	Kephra::API::focus ( defined $doc ? $doc->editor->{$self} : $page );
	Kephra::API::main_window()->refresh_title();

}


sub active_title { $_[0]->GetPageText( $_[0]->GetSelection ) }

sub set_page_title {
	my ($self, $label, $page) = @_;
	$page = $self->GetSelection unless defined $page;
	return Kephra::Log::warning("need a Kephra::App::Panel or valid position number") 
		unless (looks_like_number($page) and $self->valid_page_pos($page))
		or (blessed($page) and $page->isa('Kephra::App::Panel'));
	my $found = $self->GetPageIndex($page);
	my $position = $found eq &Wx::wxNOT_FOUND ? $page : $found;
	$self->SetPageText( $position, $label );
}


1;
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.