Commits

Herbert Breunung committed c585290

joined sp1 branch - still some issues

  • Participants
  • Parent commits b350c99

Comments (0)

Files changed (12)

lib/Kephra/API.pm

  '$doc'    => { switch => 'document',    class => 'Kephra::Document' },
  '$ed'     => { switch => 'editor',      class => 'Kephra::App::Editor' },
 });
-Kephra::API::Command::init();
-Kephra::Config::init();
 
-
-sub app             { $Kephra::App::_ref }
-sub main_window     { $Kephra::App::Window::_ref }
-sub editor          { Kephra::API::Doc::active_editor() }
-sub docbar          { Kephra::App::Part::Editor::active_docbar() }
-sub document        { Kephra::API::Doc::active() }
-sub all_documents   { Kephra::API::Doc::all() }
-sub do_with_all_documents { }
+sub app                 { $Kephra::App::_ref }
+sub main_window         { $Kephra::App::Window::_ref }
+sub docbar              { Kephra::App::Part::Editor::docbar() }
+sub all_docbars         { Kephra::App::Part::Editor::all_docbars() }
+sub passive_docbars     { Kephra::App::Part::Editor::passive_docbars() }
+sub document            { Kephra::API::Doc::active() }
+sub all_documents       { Kephra::API::Doc::all() }
+sub do_with_all_editors {&Kephra::API::Doc::do_with_all_editors }
+sub editor              { Kephra::API::Doc::active_editor() }
 
 sub focus           { Kephra::App::Focus::set(@_) }
 sub focus_back      { Kephra::App::Focus::set_back(@_) }

lib/Kephra/API/Doc.pm

+use v5.10;
 use strict;
 use warnings;
-
-use Kephra::API;
+use Wx;
+use Kephra::App::Editor;
+use Kephra::App::Panel;
 use Kephra::Document;
 
 package Kephra::API::Doc;
+my %document = ('ID'=>{});             # keys of subhashes: ID editor panel file
+my $active;
+my $lowest_free_ID = 1;
+my $lowest_free_anon_NR = 1;
 
-my %document;
-my $active;
-my $previous;
+use constant DOC_CLASS => 'Kephra::Document';
+use Scalar::Util qw(blessed looks_like_number);
 
-sub previous_doc  { $previous }
-sub active    { $active }
-sub active_editor { $active->editor }
-sub set_active_doc{
-	my $any = shift;
-	Kephra::Log::warning('need a parameter!') unless $any;
-	my $new_doc = doc_by_anything( $any ) ;
-	return unless defined $new_doc;
-	_activate($new_doc);
-	return 1;
+
+sub active        { $active || '' }
+sub active_editor { $active->editor->{Kephra::API::docbar()} if $active }
+sub active_panel  { $active->panel->{Kephra::API::docbar()} if $active }
+sub set_active {
+	my $doc = find( shift );
+	$active = $doc if $doc;
 }
-sub _activate {
-	$previous = $active;
-	$active = shift;
-}
-sub add_and_activate {
+sub previous      { App::Kephra::Focus::last( DOC_CLASS ) }
+sub all           { values %{$document{'ID'}} }
+
+sub is { return 1 if blessed($_[0]) and $_[0]->isa( DOC_CLASS ); return 0 }
+
+
+sub add {
 	my $doc = shift;
-	add($doc);
-	_activate($doc);
-}
-sub add {            # silently
-	my $doc = shift;
-	Kephra::Log::warning("add to me only docs, not $doc!") unless $doc->isa('Kephra::Document');
-	$document{$doc->editor} = $doc;
-}
-sub del {
-	my $doc = shift;
-	Kephra::Log::warning("add to me only docs, not $doc!") unless $doc->isa('Kephra::Document');
-	Kephra::Log::warning("$doc was not in the stash!") unless $document{$doc->editor};
-	delete $document{$doc->editor};
+	Kephra::Log::warning('need a ' . DOC_CLASS . " thats in stash, not $doc!", 1)
+		unless is($doc);
+	$document{'ID'}  {$lowest_free_ID} = $doc;
+	add_instance($doc, $_) for values $doc->panel;
+	if ($doc->file_path) {
+		$document{'file'}{$doc->file_path} = $doc;
+	} else {
+		$doc->anon_NR( $lowest_free_anon_NR++ );
+		$document{'anon'}{$doc->anon_NR} = $doc;
+	}
+	$lowest_free_ID++;
 }
 
 
-sub doc_by_anything {
-	my $any = shift;
-	Kephra::Log::warning("need a parameter!") unless $any;
-	return     ref($any) eq ''                  ? doc_by_path ($any)
-			 : $any->isa('Wx::Panel')           ? doc_by_panel($any)
-			 : $any->isa('Kephra::App::Editor') ? doc_by_ed   ($any)
-			 : $any->isa('Kephra::Document')    ? $document{$any->editor} 
-			 :                                    undef;
-}
-sub doc_by_ed {
-	my $ed = shift;
-	Kephra::Log::warning("needs a Kephra::App::Editor, not $ed!")
-		unless $ed->isa('Kephra::App::Editor');
-	return $document{$ed};
-}
-sub doc_by_panel {
-	my $panel = shift;
-	Kephra::Log::warning("needs a Wx::Panel, not $panel!") unless $panel->isa('Wx::Panel');
-	for my $ed (keys %document) {
-		return $document{$ed} if $document{$ed}->panel and $document{$ed}->panel eq $panel;
+sub rename_file {
+	my $doc = find( shift );
+	Kephra::Log::warning('need a ' . DOC_CLASS . " thats in stash, not $doc!", 1)
+		unless is($doc);
+	my $file = $doc->old_file_path;
+	delete $document{'file'}{$file} if $file and $document{'file'}{$file};
+	if ($doc->file_path){
+		$document{'file'}{$doc->file_path} = $doc;
+		unless ($doc->old_file_path) {
+			delete $document{'anon'}{$doc->anon_NR};
+			$doc->anon_NR(0);
+		}
+	} else {
+		if ($doc->old_file_path) {
+			$doc->anon_NR( $lowest_free_anon_NR++ );
+			$document{'anon'}{$doc->anon_NR} = $doc;
+		}
 	}
 }
-sub doc_by_path {
-	my $file_path = shift;
-	Kephra::Log::warning("needs a file path as input!") unless $file_path and -e $file_path;
-	for my $ed (keys %document) {
-		return $document{$ed} if $document{$ed}->file_path eq $file_path;
-	}
+
+
+sub remove {
+	my $doc = shift;
+#say "remove $doc ", scalar keys %{$document{'ID'}}, ' ',scalar keys %{$document{'file'}}; 
+	Kephra::Log::warning('need a ' . DOC_CLASS . ' thats in stash, not $doc!', 1)
+		unless is($doc);
+	delete $document{'ID'}{$doc->ID} if $doc->ID;
+	#remove_instance($doc, $_) for values $doc->panel;
+	delete $document{'file'}{$doc->file_path} if $doc->file_path;
+#say "removed $doc ", scalar keys %{$document{'ID'}}, ' ',scalar keys %{$document{'file'}}; 
 }
-sub all { values %document }
 
-sub dump_all_ed { print "$_ + \n" for keys %document }
+
+sub add_instance {
+	my ($doc, $bar) = @_;
+	return Kephra::Log::warning('need as first parameter a'.DOC_CLASS.' thats in stash, not $doc!', 1)
+		unless is($doc);
+	return Kephra::Log::warning("need as second parameter a Kephra::App::Bar::Document instance")
+		unless blessed($bar) eq 'Kephra::App::Bar::Document';
+	$document{'panel'} { $doc->panel->{$bar}  } = $doc;
+	$document{'editor'}{ $doc->editor->{$bar} } = $doc;
+}
+
+
+sub remove_instance {
+	my ($doc, $bar) = @_;
+	return Kephra::Log::warning('need as first parameter a'.DOC_CLASS.' thats in stash, not $doc!', 1)
+		unless is($doc);
+	return Kephra::Log::warning("need as second parameter a Kephra::App::Bar::Document instance")
+		unless blessed($bar) eq 'Kephra::App::Bar::Document';
+	delete $document{'panel'}{ $doc->panel->{$bar} };
+	delete $document{'editor'}{ $doc->editor->{$bar} };
+}
+
+
+sub find {
+	my $any = shift;
+	Kephra::Log::warning("need a parameter!", 1) unless defined $any and $any;
+	return     looks_like_number($any)                                     ? $document{'ID'}    {$any}
+	         : ref($any) eq ''                                             ? $document{'file'}  {$any}
+	         : $any->isa('Kephra::App::Panel')                             ? $document{'panel'} {$any}
+	         : $any->isa('Kephra::App::Editor')                            ? $document{'editor'}{$any}
+	         :($any->isa(DOC_CLASS) and $document{'ID'}{$any->ID} eq $any) ? $any
+	         :                                                               undef;
+}
+
 
 sub file_loaded {
 	my $file_path = shift;
-	Kephra::Log::warning("needs a file path as input!") unless $file_path and -e $file_path;
-	for my $ed (keys %document) {
-		return 1 if $document{$ed}->file_path and $document{$ed}->file_path eq $file_path;
+	#Kephra::Log::warning("needs a file path as input!") unless $file_path and -e $file_path;
+	for my $doc ( all() ) {
+		return 1 if $doc->file_path and $doc->file_path eq $file_path;
 	}
 }
+
+
+sub all_editors { keys %{$document{'editor'}} }
+sub do_with_all_editors {
+}
+
 1;

lib/Kephra/App.pm

 	$_ref = shift;
 
 	my $win = Kephra::App::Window->new(__PACKAGE__);
-
 	Kephra::File::new();
 
 	$win->Center();

lib/Kephra/App/Bar/Document.pm

-use v5.10;
-use strict;
+use v5.12;
 use warnings;
 use Wx;
 use Wx::AUI;
 use Kephra::API;
-use Kephra::App::Panel;
-use Kephra::App::Util;
+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=>'alt+pageup'},
- 'docbar-move-right'      =>{sub=>'$docbar->move_page_right',      label=>'Move Right',    keys=>'alt+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'},
+ #'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'},
 });
 
 
-my ($is_panel, $is_widget) = Kephra::App::Util::get(qw/is_panel is_widget/);
-
 sub new {
 	my( $class, $parent) = @_;
-	my $self = $class->SUPER::new( $parent, -1, [-1,-1], [-1,-1],
+	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 indexes : vis -> int
-	$self->{'internal_page_order'} = []; # internal order of visual indexes : int -> vis
-	$self->activate_events();
+	$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 activate_events {
+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 ($nb, $event ) = @_;
-		$self->{'DND_page_nr'} = $event->GetSelection;
+		my ($bar, $event ) = @_;
+		$bar->{'DND_page_nr'} = $event->GetSelection;
 	});
 	Wx::Event::EVT_AUINOTEBOOK_END_DRAG($self, -1, sub {
-		my ($nb, $event ) = @_;
-		return unless defined $self->{'DND_page_nr'};
-		$nb->move_page_index_visually($self->{'DND_page_nr'}, $event->GetSelection);
-		$self->{'DND_page_nr'} = undef;
+		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 ($nb, $event ) = @_;
-		my $new_page = $nb->GetPage( $event->GetSelection );
-		Kephra::API::Doc::set_active_doc( $new_page );
+		my ($bar, $event ) = @_;
+		my $new_page = $bar->GetPage( $event->GetSelection );
+		Kephra::API::Doc::set_active( $new_page );
 		Kephra::API::main_window()->refresh_title();
-		Wx::Window::SetFocus( $new_page );
+		Kephra::API::focus( $new_page );
 		$event->Skip;
 	});
 	Wx::Event::EVT_AUINOTEBOOK_PAGE_CLOSE( $self, -1, sub {
-		my ($nb, $event ) = @_; 
+		my ($bar, $event ) = @_; 
 		$event->Veto;
 		Kephra::File::close_active();
 	});
-	#Wx::Event::EVT_AUINOTEBOOK_PAGE_CHANGED(
-	#);
 	# keep focus on editor even when klicking on tab bar
-	#Wx::Event::EVT_LEFT_DOWN($self, sub { Kephra::API::active_editor()->focus; print "--"; });
+	#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 silence_events {
+
+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_CLOSE  ( $self, -1, sub {});
 }
 
+
 sub add_page {
-	my ($self, $new_page, $label, $position) = @_;
-	return unless $new_page and ($is_panel->($new_page) or $is_widget->($new_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;
 
-	$label    = ''                           unless defined $label;
-	$position = 'right'                      if $position eq 'default' or $position == -1;
+	$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 = 1                          unless defined $set_active;
+	$set_active = 0                          unless defined $set_active;
 
-	# put panel under a none-panel
-	unless ($new_page->isa('Kephra::App::Panel')) {
-		my $widget = $new_page;
-		$new_page = Kephra::App::Panel->new( $self, \$widget);# if ($position == 0 or $label);
-		# document property: panel the editor sits on has to be set before EVT_AUINOTEBOOK_PAGE_CHANGED
-		Kephra::DocumentStash::doc_by_ed( $widget )->panel( $new_page ) if $widget->isa('Kephra::Editor'); # and ($position == 0 or $label);
-	}
-	else { $new_page->Reparent( $self ) }
-
-	$self->InsertPage( $position, $new_page, '');# if $position == 0 or $label; # last parameter sets new pace as active
-	$self->set_page_title( $label, $new_page );
+	$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;
+	Kephra::API::main_window()->refresh_title() 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();
 
-	return $new_page;
+	$self;
 }
 
 sub remove_page {
-	my ($self, $internal_position) = @_;
+	my ($self, $page) = @_;
+	my $internal_position = $self->GetPageIndex( $page );
 
-	$self->DeletePage( $internal_position );
+	$self->RemovePage( $internal_position );
 	my $visual_position = $self->{'internal_page_order'}[$internal_position];
 	my $visual = $self->{'visual_page_order'};
 	splice @$visual, $visual_position, 1;
 	$self->refresh_internal_page_order;
 }
 
-sub 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 [];
 	$self->{'internal_page_order'} = $internal;
 }
 
-sub move_page_index_visually { # for dnd only
+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 $index = splice @{$self->{'visual_page_order'}}, $from, 1;
-	splice @{$self->{'visual_page_order'}}, $to, 0, $index;
+	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
+sub move_page_visually  {               # for movements by keyboard
 	my ($self, $from, $to ) = @_;
 	my $max = $self->GetPageCount - 1;
 	return if $from < 0 or $from > $max;
 	my $label = $self->GetPageText( $pos );
 	my $visual = $self->{'visual_page_order'};
 
-	$self->silence_events();
+	$self->unmount_events();
 	$self->RemovePage( $pos );
 	$self->InsertPage( $to, $page, $label);
 	my $removed = splice @$visual, $from, 1;
 	$self->{'visual_page_order'} = $visual;
 	$self->refresh_internal_page_order();
 	$self->SetSelection( $self->{'visual_page_order'}[$to] );
-	$self->activate_events();
+	$self->mount_events();
 }
 
-sub move_page_left  { 
+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 { 
+sub move_page_right     {
 	my ($self) = @_;
 	$self->move_page_visually( 
 		$self->active_visual_pos, $self->next_page_pos_rot_right( $self->GetSelection )
 	$self->move_page_visually( $self->active_visual_pos, $self->rightmost_page_pos );
 }
 
-sub select_page_left  { 
+sub select_page_left    { 
 	my ($self) = @_;
 	$self->raise_page( $self->next_page_pos_rot_left( $self->GetSelection ) );
 }
-sub select_page_right { 
+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 leftmost_page_pos { 0 }
-sub rightmost_page_pos { $_[0]->GetPageCount-1 }
-sub active_visual_pos { $_[0]->{'internal_page_order'}[ $_[0]->GetSelection ] }
-sub next_page_pos_rot_left {
+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 {
+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, $iop) = @_; # can be Index Or Page (panel reference)
-	my $index = int $iop eq $iop ? $iop : $self->GetPageIndex($iop);
-	return if $index < 0 or $index > $self->rightmost_page_pos;
-	$self->SetSelection( $index );
-	my $page = $self->GetPage($index);
-	#print $page->GetChildren,"||\n";
-	Kephra::App::Focus::set($page);
+
+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) = @_;
-	return if ref $page and $page ne ref $page and $page->isa(' Wx::Window');
-	my $position = $page ? $self->GetPageIndex($page) : $self->GetSelection;
-	return unless $position >= 0;
-	$label = '<untitled>' unless $label;
-	my $max_width = 15;
-	if ( length($label) > $max_width and $max_width > 7 ) {
-		$label = substr( $label, 0, $max_width - 2 ) . '..';
-	}
+	$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 );
 }
 
-sub refresh_page_title {
-	my $self = shift;
-	my $doc = shift // Kephra::API::document();
-	my $unsaved_mark = '*';
-	my $position = $self->GetSelection;
-	my $label = $self->GetPageText( $position);
-	chop $label if substr($label,-1) eq $unsaved_mark;
-	$label .= $unsaved_mark if $doc->editor->GetModify;
-	$self->SetPageText($position, $label);
-}
 
-1;
-
+1;

lib/Kephra/App/Editor.pm

 package Kephra::App::Editor;
 our @ISA = 'Wx::StyledTextCtrl';
 #our @ISA = 'Wx::ScintillaTextCtrl';
-
-my $color = Kephra::App::Util::get('create_color');
+use Kephra::App::Util qw(create_color);
 
 sub new {
 	my( $class, $parent, $style) = @_;
 	my ($self, @which) = @_;
 	$self->DragAcceptFiles(1) if $^O eq 'MSWin32'; # enable drop files on win
 	$self->SetDropTarget( Kephra::App::Editor::TextDropTarget->new($self) );
+
 	Wx::Event::EVT_STC_CHANGE       ($self, -1, sub {
 		my ($ed, $event) = @_;
 		$ed->{'change_pos'} = $ed->GetCurrentPos;
 		$event->Skip;
 	} );
+
 	Wx::Event::EVT_KEY_DOWN ($self, sub {
 		my ($ed, $event) = @_;
 		my $key = Kephra::API::KeyMap::keycode_from_event($event);
 	#Wx::Event::EVT_RIGHT_DOWN
 	#Wx::Event::EVT_STC_UPDATEUI
 	Wx::Event::EVT_STC_SAVEPOINTREACHED
-		($self, -1, sub { Kephra::API::docbar()->refresh_page_title() });
+		($self, -1, sub { Kephra::App::Part::Editor::refresh_doc_label() });
 	Wx::Event::EVT_STC_SAVEPOINTLEFT
-		($self, -1, sub { Kephra::API::docbar()->refresh_page_title() });
+		($self, -1, sub { Kephra::App::Part::Editor::refresh_doc_label() });
+	Wx::Event::EVT_SET_FOCUS( $self, sub {
+		my ($ed, $event ) = @_;
+		$event->Skip;
+		Kephra::App::Part::Editor::select_docbar( $ed->GetParent->GetParent );
+	});
 	#Wx::Event::EVT_DROP_FILES       ($ep, sub{});
 	#Wx::Event::EVT_STC_START_DRAG   ($ep, -1, sub {
 	#Wx::Event::EVT_STC_DRAG_OVER    ($ep, -1, sub { $droppos = $_[1]->GetPosition });
 	#Wx::Event::EVT_STC_DO_DROP   
-
 }
 
 sub set_margin {
 		$self->SetMarginSensitive( 0, 1 );
 		$self->SetMarginSensitive( 1, 1 );
 		$self->SetMarginSensitive( 2, 1 );
-		$self->StyleSetForeground(&Wx::wxSTC_STYLE_LINENUMBER, $color->(123,123,137));
-		$self->StyleSetBackground(&Wx::wxSTC_STYLE_LINENUMBER, $color->(226,226,222));
+		$self->StyleSetForeground(&Wx::wxSTC_STYLE_LINENUMBER, create_color(123,123,137));
+		$self->StyleSetBackground(&Wx::wxSTC_STYLE_LINENUMBER, create_color(226,226,222));
 		$self->SetMarginWidth(0,  0);
 		$self->SetMarginWidth(1, 31);
 		$self->SetMarginWidth(2,  0);
 
 	# extra margin left and right inside the white text area
 	$self->SetMargins(2, 2);
+	$self;
 }
 
 sub insert_text {
 
 sub set_colors {
 	my $self = shift;
-	$self->SetCaretLineBack( $color->(250,245,185) );
+	$self->SetCaretLineBack( create_color(250,245,185) );
 	#$self->SetCaretPeriod( 500 );
 	#$self->SetCaretWidth( 2 );
-	$self->SetCaretForeground( $color->(0,0,255) );
+	$self->SetCaretForeground( create_color(0,0,255) );
 	$self->SetCaretLineVisible(1);
-	$self->SetSelForeground( 1, $color->(243,243,243) );
-	$self->SetSelBackground( 1, $color->(0, 17, 119) );
-	$self->SetWhitespaceForeground( 1, $color->(204, 204, 153) );
+	$self->SetSelForeground( 1, create_color(243,243,243) );
+	$self->SetSelBackground( 1, create_color(0, 17, 119) );
+	$self->SetWhitespaceForeground( 1, create_color(204, 204, 153) );
 	$self->SetViewWhiteSpace(1);
 
-	$self->SetEdgeColour( $color->(200,200,255) );
+	$self->SetEdgeColour( create_color(200,200,255) );
 	$self->SetEdgeColumn( 80 );
 	$self->SetEdgeMode( &Wx::wxSTC_EDGE_LINE );
 }

lib/Kephra/App/Focus.pm

 use strict;
 use warnings;
 use Wx;
-use Kephra::API;
-use Kephra::App::Util;
 
 package Kephra::App::Focus;
 my @focus_stack = ();
 my $max_stack_size = 50;
 
-#Kephra::CommandList::register_cmd({'app-focus-set-back'  =>{sub=>'set_back',label=>'',keys=>''},});
+use Kephra::API;
+use Kephra::App::Util qw(is_widget);
+
+Kephra::API::Command::register({
+ 'app-focus-set-back'  =>{ sub=>'set_back', label=>'',  keys=>'' },
+ 'app-focus-stay'      =>{ sub=>'stay',     label=>'',  keys=>'' },
+});
 
 
 sub get  {                              # give widget in focus or one that was before
 
 sub set  {                              # set focus to another widget
 	my ($widget) = @_;
+	return unless defined $widget;
 	#Kephra::Log::note("focus is on :". get()." and will be: $widget");
-	return Kephra::Log::warning( "got no proper widget but $widget", 1 )
-		unless Kephra::App::Util::is_widget($widget);
+	return Kephra::Log::warning( "got no proper widget but $widget", 1 ) unless is_widget($widget);
 	return if $widget eq get();
 	unshift @focus_stack, $widget;
 	pop @focus_stack while stack_size() > $max_stack_size;
 
 sub stay {                              # reset focus to current (last set) entry
 	my ($widget) = get();
-	Kephra::App::Util::is_widget($widget)
+	is_widget($widget)
 		? Wx::Window::SetFocus( $widget )
 		: Kephra::Log::warning( "no widget to stay focussed on", 1 );
 }

lib/Kephra/App/Part/Editor.pm

-use strict;
+use v5.10;
 use warnings;
+use Cwd;
+use File::Find;
+use File::Spec;
+use Kephra::App::Panel;
+use Kephra::App::Bar::Document;
+use Kephra::App::Splitter;
 
 package Kephra::App::Part::Editor;
+our @ISA = 'Kephra::App::Panel';
+my ($active_bar, @passive_bar, $panel, %splitter);
+use Scalar::Util qw(blessed);
 
-use Kephra::API;
-use Kephra::App::Bar::Document;
+Kephra::API::Command::register({
+ 'docbar-prev' =>{sub=>'select_docbar_prev', label=>'Prev Docbar',  keys=>'alt+pageup'},
+ 'docbar-next' =>{sub=>'select_docbar_next', label=>'Next Docbar',  keys=>'alt+pagedown'},
+ 'docbar-del' =>{sub=>'select_docbar_del', label=>'Next Docbar',  keys=>'ctrl+alt+pageup'},
+ 'docbar-add' =>{sub=>'select_docbar_add', label=>'Prev Docbar',  keys=>'ctrl+alt+pagedown'},
+});
 
-#my $_ref; # whole panel widget, parent of all this
-my %doc_bar;
-#my $active;
 
-sub active_docbar{ $doc_bar{'leftup'} }
+sub docbar         { $active_bar }
+sub passive_docbars{ @passive_bar}
+sub all_docbars    { $active_bar, @passive_bar }
 
 sub new {
 	my( $class, $parent) = @_;
-	$doc_bar{'leftup'} = Kephra::App::Bar::Document->new( $parent );
-	# Wx::SplitterWindow->new( $splitter{'left'}, -1 );
-	return $doc_bar{'leftup'};
+	my $self = $panel = $class->SUPER::new($parent);
+
+	my $db  = Kephra::App::Bar::Document->new($self);
+	my $db2 = Kephra::App::Bar::Document->new($self);
+
+	my $splitter = $splitter{'main'} = Kephra::App::Splitter->new
+		({parent => $self, left => $db, right => $db2, dominant_child => 'left'});
+	$self->append( \$splitter );
+	$splitter->resize('equal');
+
+	$active_bar = $db;
+	@passive_bar = ($db2);
+
+	$self;
 }
 
-sub create_document {
-	my $file = shift;
-	my $doc = Kephra::API::document();
-	my $win = Kephra::API::main_window();
-	my $main_doc_bar = active_docbar();
-
-	if ($doc and $doc->editor->is_empty and $file) { # overwrite empty doc
-		$doc->assign_file_path($file);
-		$main_doc_bar->set_page_title( $doc->file_name );
-	} else {                                         # make new editor
-		$doc = Kephra::Document->new();
-		$doc->assign_file_path( $file );
-		$doc->panel( Kephra::App::Panel->new( $main_doc_bar ) );
-		$doc->editor( Kephra::App::Editor->new( $doc->panel ) );
-		$doc->panel->append( \$doc->editor );
-		Kephra::API::Doc::add_and_activate( $doc );
-		$main_doc_bar->add_page($doc->panel, $doc->file_name, -1, 1);
-		Kephra::API::focus( $doc->editor );
+sub select_docbar_del {
+	my $docbar_count = scalar @passive_bar + 1;
+	return if $docbar_count < 2;
+	if    ($docbar_count == 4){
+		
 	}
-	$win->refresh_title();
-
-	return $doc;
+	elsif ($docbar_count == 3){
+		
+	}
+	elsif ($docbar_count == 2){
+		$splitter{'main'}->set({dominant_child => $active_bar});
+		$splitter{'main'}->unsplit();
+	}
+	$passive_bar[-1]->Destroy();
+	delete $passive_bar[-1];
+	Kephra::API::focus($active_bar->GetSelection);
+	#Kephra::API::focus( Kephra::API::document()->panel->{$active_bar} );
+	#Kephra::API::focus( $splitter{'main'} );
+}
+sub select_docbar_add {
+	my $docbar_count = scalar @passive_bar + 1;
+	return if $docbar_count > 3;
+	if    ($docbar_count == 3){
+		
+	}
+	elsif ($docbar_count == 2){
+		
+	}
+	elsif ($docbar_count == 1){
+		$passive_bar[0]->Show(1);
+		$splitter{'main'}->resplit();
+	}
 }
 
-sub remove_document {
-	my $doc = shift;
-	return unless ref $doc and $doc->isa('Kephra::Document');
-	my $main_doc_bar = active_docbar();
-	if ($main_doc_bar->GetPageCount > 1) {
-		$main_doc_bar->remove_page( $main_doc_bar->GetPageIndex( $doc->panel ) );
-		Kephra::API::Doc::del($doc);
-	} else {
-		$doc->editor->ClearAll;
-		$doc->assign_file_path('');
-		$main_doc_bar->set_page_title('');
-	}
-	Kephra::API::main_window()->refresh_title();
+sub select_docbar_next {
+	push @passive_bar, $active_bar;
+	$active_bar = shift @passive_bar;
+	$active_bar->raise_page( $active_bar->GetSelection );
+}
+sub select_docbar_prev {
+	unshift @passive_bar, $active_bar;
+	$active_bar = pop @passive_bar;
+	$active_bar->raise_page( $active_bar->GetSelection );
+}
+sub select_docbar {
+	my $bar = shift;
+	return Kephra::Log::warning("need a Kephra::App::Bar::Document instance")
+		unless ref $bar eq 'Kephra::App::Bar::Document';
+	return if $active_bar eq $bar;
+	my $i;
+	for (0 ..  $#passive_bar){ $i = $_ if $bar eq $passive_bar[$_] }
+	return Kephra::Log::warning("$bar is unknown") unless defined $i;
+
+	@passive_bar = (splice(@passive_bar, $i+1), $active_bar, splice(@passive_bar, 0, $i));
+	$active_bar = $bar;
+	$active_bar->raise_page( $active_bar->GetSelection );
 }
 
-sub raise_document {
-	my $doc = Kephra::API::Doc::doc_by_anything(shift);
-	active_docbar()->raise_page( $doc->{panel} ) if $doc;
-}
 
-sub active_title {
-	my $nb = active_docbar();
-	$nb->GetPageText( $nb->GetSelection );
+sub refresh_doc_label {
+	my $doc = shift // Kephra::API::document();
+	return unless Kephra::API::Doc::is($doc);
+	my $unsaved_mark = '*';
+
+	my $title = $doc->title;
+	$title .= $unsaved_mark if $doc->editor->{$active_bar}->GetModify;
+	$_->SetPageText($_->GetPageIndex( $doc->panel->{$_} ), $title) for all_docbars();
 }
 
 1;

lib/Kephra/App/Splitter.pm

 		if $self->{'dominant_child'} eq 'left' or $self->{'dominant_child'} eq 'top';
 	$self->{'dominant_child'} = 2
 		if $self->{'dominant_child'} eq 'right' or $self->{'dominant_child'} eq 'bottom';
+	$self->{'dominant_child'} = 1 if $self->{'dominant_child'} eq $self->{'child1'};
+	$self->{'dominant_child'} = 2 if $self->{'dominant_child'} eq $self->{'child2'};
 	$self->{'dominant_child'} = 1 
 		unless $self->{'dominant_child'} eq 1 or $self->{'dominant_child'} eq 2;
 
 
 sub unsplit {
 	my $self = shift;
+	$self->{'position'} = $self->GetSashPosition;
 	$self->Unsplit if $self->IsSplit;
 	return Kephra::Log::error("can't initialize with a not existing child widget")
 		if $self->{'dominant_child'} == 1 and not $self->{'child1'}
 		or $self->{'dominant_child'} == 2 and not $self->{'child2'};
 	$self->Initialize( $self->{'child2'} ) if $self->{'dominant_child'} == 2;
-	$self->UpdateSize;
 	Kephra::App::Focus::stay();
 }
 

lib/Kephra/App/Window.pm

 sub set_title { $_ref->SetTitle( $_[1] ) }
 sub refresh_title {
 	my $self = shift;
-	my $doc = Kephra::API::Doc::active();
-	my $title = (ref $doc and $doc->file_name)
-		? $doc->file_name.' ('.$doc->file_path.')'
-		: Kephra::App::Part::Editor::active_title();
+	my $doc = Kephra::API::document();
+	return $self->set_title( $title_end ) unless defined $doc and $doc;
+
+	my $title = $doc->title;
+	$title .= ' ('.$doc->file_path.')' if $doc->file_path;
 	$self->set_title( $title . " - $title_end" );
 }
 

lib/Kephra/Config/Default/Menu.pm

 			'edit-find-prev-comment',
 	],
 	[	{section_name => 'document'},
-		[	{section_name => 'change'},
-			'docbar-select-left',
-			'docbar-select-right',
-			'docbar-select-leftmost',
-			'docbar-select-rightmost',
-			'',
-			'docbar-move-left',
-			'docbar-move-right',
-			'docbar-move-leftmost',
-			'docbar-move-rightmost',
-		],
 		#'',
 		#[	{section_name => 'encoding'},
 			#'+-utf',
 	#],
 	[	{section_name => 'view'},
 		'window-fullscreen-toggle',
+		[	{section_name => 'docbar'},
+			'docbar-select-left',
+			'docbar-select-right',
+			'',
+			'docbar-move-left',
+			'docbar-move-right',
+			'',
+			'',
+		],
+
 	],
 	[	{section_name => 'config'},
 		'+-global-dialog',

lib/Kephra/Document.pm

-package Kephra::Document;
-use Moo;
+use v5.10;
+use File::Spec;
 use Kephra::API;
 use Kephra::File;
-use File::Spec;
-use Kephra::Log;
 
-has editor => (
-	is  => 'rw',
-	isa => sub {Kephra::Log::warning("$_[0] is no editor")
-				unless ref $_[0] eq 'Kephra::App::Editor'},
-);
-has panel => (
-	is  => 'rw',
-	isa => sub {Kephra::Log::error("$_[0] is no panel")
-				unless ref $_[0] eq 'Wx::Panel' or ref $_[0] eq 'Kephra::App::Panel'
-				},
-);
-has file_path    => ( is  => 'rw', );
-has file_dir     => ( is  => 'rw', );
-has file_name    => ( is  => 'rw', );
-#has content      => ( is  => 'rw' );
-has notes        => ( is  => 'rw', );
+package Kephra::Document;
+use Moo; 
+use Scalar::Util qw(blessed);
 
-has syntax_mode  => ( is  => 'rw', default => sub { 'perl' } );
-has readonly     => ( is  => 'rw', );
-has active_config=> ( is  => 'rw', );
-has caret_pos    => ( is  => 'rw', );
-has edit_pos     => ( is  => 'rw', );
-has coding       => ( is  => 'rw', );
-has EOL          => ( is  => 'rw', );
-has tab_size     => ( is  => 'rw', );
-has tab_use      => ( is  => 'rw', );
-has folded_lines => ( is  => 'rw', );
-has marked_lines => ( is  => 'rw', );
+my $max_title_width = 15;
 
-sub assign_file_path {
-	my ($self, $file_path) = @_;
-	return unless defined $file_path and -e $file_path;
-	if ($file_path){
-		$file_path = Kephra::File::normalize_name($file_path);
-		$self->file_path($file_path);
-		my @path_parts = File::Spec->splitpath( $_[0]->file_path );
-		$self->file_dir( $path_parts[1] );
-		$self->file_name( $path_parts[2] );
-	} else {
-		$self->file_path('');
-		$self->file_dir('');
-		$self->file_name('');
-	}
-	$self;
+# export SUB_QUOTE_DEBUG=1
+
+
+has ID     => ( is  => 'rwp' );                             # API::Doc ID
+has title  => ( is  => 'rwp' );                             # shown as tab label
+has editor => ( is  => 'rwp', default => sub { {} } );
+has panel  => ( is  => 'rwp', default => sub { {} } );
+has anon_NR=> ( is  => 'rw' );
+has file_path=>( 
+	is      => 'rw',
+	coerce  =>  sub { Kephra::File::normalize_path($_[0]) },
+	trigger =>  sub {
+		my $self = shift;
+		return if $self->old_file_path and $self->file_path
+				and $self->old_file_path eq $self->file_path;
+		Kephra::API::Doc::rename_file($self) if $self->ID;
+
+		if ($self->file_path) {
+			my @path_parts = File::Spec->splitpath( $self->file_path );
+			$self->_set_file_dir( $path_parts[1] );
+			$self->_set_file_name( $path_parts[2] );
+
+			my $title = $path_parts[2];
+			$title = substr( $title, 0, $max_title_width - 2 ) . '..'
+				if length($title) > $max_title_width and $max_title_width > 7;
+			$self->_set_title($title);
+		} else {
+			$self->_set_title('<untitled '.$self->anon_NR.'>');
+		}
+
+		$self->_set_old_file_path( $self->file_path );
+		$_->set_page_title( $self->title, $self->panel->{$_} )
+			for Kephra::API::all_docbars();
+	});
+has file_dir     => ( is => 'rwp', );
+has file_name    => ( is => 'rwp', );
+has old_file_path=> ( is => 'rwp' );
+has content      => ( is => 'rw', reader=> sub{ $_[0] } );
+has notes        => ( is => 'rw', );
+
+has syntax_mode  => ( is => 'rw', default => sub { 'perl' } );
+has readonly     => ( is => 'rw', );
+has active_config=> ( is => 'rw', );
+has caret_pos    => ( is => 'rw', );
+has edit_pos     => ( is => 'rw', );
+has encoding     => ( is => 'rw', );
+has EOL          => ( is => 'rw', );
+has tab_size     => ( is => 'rw', );
+has tab_use      => ( is => 'rw', );
+has folded_lines => ( is => 'rw', );
+has marked_lines => ( is => 'rw', );
+
+sub BUILDARGS {
+	my ( $self, @args ) = @_;
+	unshift @args, "file_path" if @args % 2 == 1;
+	my %args = @args;
+	$args{'encoding'} = 'utf-8';
+
+	return \%args;
 }
-sub raise {
-	Kephra::API::docbar()->raise_page( shift->panel() );
+
+sub BUILD    {
+	my $self = shift;
+	$self->add_instance($_) for Kephra::API::all_docbars();
+	$self->_set_ID( Kephra::API::Doc::add($self) );
+	$self->_set_title('<untitled '.$self->anon_NR.'>') unless $self->file_path;
 }
+
+sub DEMOLISH { Kephra::API::Doc::remove($_[0]);# say "demolish $_[0]"; 
+}
+
+sub add_instance {
+	my ($self, $bar) = @_;
+	return Kephra::Log::warning("need an existing Kephra::App::Bar::Document instance")
+		unless blessed($bar) eq 'Kephra::App::Bar::Document';
+
+	my @editor = values $self->editor;
+	my $panel = $self->panel->{$bar} = Kephra::App::Panel->new( $bar );
+	my $ed = $self->editor->{$bar} = Kephra::App::Editor->new( $panel );
+	$panel->append( \$ed );
+	$ed->SetDocPointer( $editor[0]->GetDocPointer() ) if @editor;
+	Kephra::API::Doc::add_instance($self, $bar);
+}
+
+sub del_instance {
+	my ($self, $bar) = @_;
+	return Kephra::Log::warning("need an existing Kephra::App::Bar::Document instance")
+		unless blessed($bar) eq 'Kephra::App::Bar::Document'
+		and exists $self->panel->{$bar};
+	Kephra::API::Doc::remove_instance($self, $bar);
+	$bar->remove_page( $self->panel->{$bar} );
+	delete $self->panel->{$bar};
+	delete $self->editor->{$bar};
+}
+sub raise { Kephra::API::focus( shift->panel ) }
 sub insert_before_caret {}
 sub insert_after_caret {}
-sub find {}
 
 1;

lib/Kephra/File.pm

+use v5.10;
 use strict;
 use warnings;
 use File::Spec;
 use Kephra::API;
+use Kephra::App::Dialog;
+use Kephra::File::Local;
 
 package Kephra::File;
 
  'file-close-all'  =>{sub=> 'close_all',    label=> 'Close All',  keys=> 'ctrl+alt+q'},
 });
 
-sub normalize_name {
+sub normalize_path {
 	my $file = shift;
 	return unless defined $file and $file;
 
 }
 
 
-sub new  { Kephra::App::Part::Editor::create_document() }
+sub new  {
+	my $doc = Kephra::Document->new();
+	my $docbar = Kephra::API::docbar();
+	$_->add_page( $doc->panel->{$_}, 'rightmost', $doc->title, 0 ) for Kephra::API::all_docbars();;
+	Kephra::API::focus( $doc->editor->{$docbar} );
+}
+
 sub open {
 	# open dialog if no file was given
-	$_[0] = Kephra::App::Dialog::get_file_open() unless @_;
+	@_ = Kephra::App::Dialog::get_files_open() unless @_;
 
 	# new doc for each file name
 	for my $file (@_){
-		$file = normalize_name( $file );
+		$file = normalize_path( $file );
 		next unless $file and -e $file;
 
 		# raise tab if doc is alread open
 		Kephra::App::Part::Editor::raise_document($file), next
 		  if Kephra::API::Doc::file_loaded($file);
 
-		my $doc = Kephra::App::Part::Editor::create_document($file);
-		next unless ref $doc eq 'Kephra::Document';
-		my $file_content = _read_file( $doc, $file );
-		$doc->editor->EmptyUndoBuffer;
+		my $db = Kephra::API::docbar();
+		my $doc = Kephra::API::document();
+		my $ed = Kephra::API::editor();
+		if ($ed->GetLength) {
+			$doc = Kephra::Document->new($file);
+			$_->add_page( $doc->panel->{$_},'right', $doc->file_name, 1) for Kephra::API::all_docbars();
+			my $content_ref = $doc->editor->{$db}->GetDocPointer();
+			$doc->editor->{$_}->SetDocPointer( $content_ref ) for Kephra::API::passive_docbars()
+		}
+		# reuse it if current doc is empty
+		else {
+			$doc->file_path($file) 
+		}
+		Kephra::API::app()->Yield;
+		Kephra::File::Local::read( $doc, $file );
+		$ed = Kephra::API::editor();
+		$ed->EmptyUndoBuffer;
+		#$ed->mount_events();
 	}
 }
+
 sub reopen {
 	for my $doc (@_){
 		next unless ref $doc eq 'Kephra::Document';
 		Kephra::Log::warning("can't reopen nonexising file"), next
 			unless $doc->file_path and -e $doc->file_path;
-		_read_file( $doc );
+		Kephra::File::Local::read( $doc );
 	}
 }
 sub reopen_active { reopen( Kephra::API::document() ) }
 sub reopen_all    { reopen( Kephra::API::all_documents()   ) }
 
-sub _read_file {
-	my $doc = shift;
-	my $file = normalize_name( shift ) || $doc->file_path;
-	return Kephra::Log::warning("can't load nonexising file") unless $file and -e $file;
-	return Kephra::Log::warning("can't read $file") unless -r $file;
-	my $ed = $doc->editor;
-	CORE::open my $FH, '<', $file;
-	binmode($FH);
-	my $content = do { local $/; <$FH> };
-	if ($content) {
-		$ed->SetText( $content );
-		$ed->SetSavePoint;
-	}
-}
-sub _write_file {
-	my $doc = shift;
-	my $file = normalize_name( shift ) || $doc->file_path;
-	return Kephra::Log::warning("need a file path") unless $file;
-	return Kephra::Log::warning("can't overwrite $file") if -e $file and not -w $file;
-	$doc->assign_file_path($file) unless $doc->file_path eq $file;
-	my $ed = $doc->editor;
-	CORE::open my $FH, '>', $file;
-	print $FH $ed->GetText;
-	$ed->SetSavePoint;
-}
 
 sub save {
 	$_[0] = Kephra::API::document() unless @_;
+	my $docbar = Kephra::API::docbar();
+
 	for my $doc (@_){
 		next unless ref $doc eq 'Kephra::Document';
-		next unless $doc->editor->GetModify;
+		next unless $doc->editor->{$docbar}->GetModify;
 		if ($doc->file_path){
-			_write_file($doc);
+			Kephra::File::Local::write($doc);
 		} else {
 			$doc->raise;
 			save_as($doc);
 
 sub close {
 	$_[0] = Kephra::API::document() unless @_;
+	my $active_bar = Kephra::API::docbar();
+
 	for my $doc (@_) {
 		next unless ref $doc eq 'Kephra::Document';
-		if ($doc->editor->GetModify) {
-			my $save_answer = Kephra::App::Dialog::yes_no_cancel(
-				'do you want to save it before?', 'close unsaved file'
+		my $ed = $doc->editor->{ $active_bar };
+		if ($ed->GetModify) {
+			my $save_answer = Kephra::App::Dialog::yes_no_cancel (
+				'close unsaved file', 'do you want to save it before?'
 			);
 			next if $save_answer == &Wx::wxCANCEL;
 			save($doc) if $save_answer == &Wx::wxYES;
 		}
-		Kephra::App::Part::Editor::remove_document( $doc );
+		if ($active_bar->GetPageCount > 1){
+			$_->remove_page( $doc->panel->{$_} ) for Kephra::API::all_docbars();
+			$doc->DESTROY;
+		} else {
+			next unless $ed->GetLength;
+			$ed->ClearAll();
+			$ed->SetSavePoint;
+			$ed->EmptyUndoBuffer;
+			$doc->file_path('');
+		}
 	}
+	Kephra::API::main_window()->refresh_title();
+	Kephra::API::focus($active_bar->GetSelection);
 }
 sub close_active { Kephra::File::close( Kephra::API::document() )}
 sub close_all    { Kephra::File::close( Kephra::API::all_documents() ) }