package Kephra::App::EditPanel::Fold;
our $VERSION = '0.05';
use strict;
use warnings;
#
sub _ep_ref {
Kephra::App::EditPanel::is($_[0]) ? $_[0] : Kephra::App::EditPanel::_ref()
}
sub _config { Kephra::App::EditPanel::Margin::_config()->{fold} }
sub _attribute { 'folded_lines' }
#
sub _is_head_level { # is this the fold level of a head node ?
my $level = shift;
return 1 if ($level % 1024) < (($level >> 16) % 1024);
}
sub _is_node {
my $line = shift;
return 1 if _ep_ref()->GetFoldParent($line+1) == $line;
}
sub _get_line { #
my ($ep, $event) = @_;
$ep = _ep_ref();
my $line = Kephra::App::EditPanel::Margin::clicked_on_line($event);
# save position where context menu poped so we can fold there
if ($line == -1){
if (defined $event and ref $event eq 'Wx::StyledTextEvent'){
$line = $ep->LineFromPosition( $event->GetPosition() );
}
else { $line = $ep->GetCurrentLine() }
}
return $line;
}
#
sub store {
for my $doc_nr (@{Kephra::Document::Data::all_nr()}) {
my $ep = Kephra::Document::Data::_ep($doc_nr);
my @lines;
for (0 .. $ep->GetLineCount()-1) {
push @lines, $_ unless $ep->GetFoldExpanded( $_ );
}
Kephra::Document::Data::set_attribute( _attribute(), \@lines, $doc_nr);
}
}
sub restore {
my $doc_nr = Kephra::Document::Data::valid_or_current_doc_nr(shift);
my $ep = Kephra::Document::Data::_ep($doc_nr);
return if $doc_nr < 0 or not ref $ep;
my $lines = Kephra::Document::Data::get_attribute( _attribute(), $doc_nr);
return unless ref $lines eq 'ARRAY';
for (reverse @$lines){
$ep->ToggleFold($_) if $ep->GetFoldExpanded($_);
}
}
#
# folding functions
#
sub toggle_here {
my $ep = _ep_ref();
my $line = _get_line(@_);
$ep->ToggleFold($line);
Kephra::Edit::Goto::next_visible_pos() if _config()->{keep_caret_visible}
and not $ep->GetFoldExpanded($line);
}
sub toggle_recursively {
my $ep = _ep_ref();
my $line = _get_line(@_);
unless ( _is_node( $line ) ) {
$line = $ep->GetFoldParent($line);
return if $line == -1;
}
my $node_xpanded = not $ep->GetFoldExpanded($line);
my $cursor = $ep->GetLastChild($line, -1);
while ($cursor >= $line) {
$ep->ToggleFold($cursor) if $ep->GetFoldExpanded($cursor) xor $node_xpanded;
$cursor--;
}
Kephra::Edit::Goto::next_visible_pos() if _config()->{keep_caret_visible} and not $node_xpanded;
}
sub toggle_siblings { toggle_siblings_of_line( _get_line(@_) ) }
sub toggle_siblings_of_line {
my $ep = _ep_ref();
my $line = shift;
return if $line < 0 or $line > ($ep->GetLineCount()-1);
my $level = $ep->GetFoldLevel($line);
my $parent = $ep->GetFoldParent($line);
my $xp = not $ep->GetFoldExpanded($line);
my $first_line = $parent;
my $cursor = $ep->GetLastChild($parent, -1 );
($first_line, $cursor) = (-1, $ep->GetLineCount()-2) if $parent == -1;
while ($cursor > $first_line){
$ep->ToggleFold($cursor) if $ep->GetFoldLevel($cursor) == $level
and ($ep->GetFoldExpanded($cursor) xor $xp);
$cursor--;
}
Kephra::Edit::Goto::next_visible_pos() if _config()->{keep_caret_visible}
and not $xp;
$ep->EnsureCaretVisible;
}
sub toggle_level {
my $ep = _ep_ref();
my $line = _get_line(@_);
return if $line < 0 or $line > ($ep->GetLineCount()-1);
my $level = $ep->GetFoldLevel($line);
my $xp = not $ep->GetFoldExpanded($line);
for (0 .. $ep->GetLineCount()-1) {
$ep->ToggleFold($_) if $ep->GetFoldLevel($_) == $level
and ($ep->GetFoldExpanded($_) xor $xp);
}
Kephra::Edit::Goto::next_visible_pos() if _config()->{keep_caret_visible}
and not $xp;
$ep->EnsureCaretVisible;
}
sub toggle_all {
my $ep = _ep_ref();
my $newline = my $oldline = $ep->GetLineCount();
# looking for the head of heads // capi di capi
while ($oldline == $newline and $oldline > 0){
$newline = --$oldline;
$newline = $ep->GetFoldParent($newline) while $ep->GetFoldParent($newline) > -1;
}
my $root_unfolded = $ep->GetFoldExpanded($newline);
$root_unfolded ? fold_all() : unfold_all();
Kephra::Edit::Goto::next_visible_pos() if _config()->{keep_caret_visible}
and $root_unfolded;
}
sub fold_all {
my $ep = _ep_ref();
my $cursor = $ep->GetLineCount()-1;
while ($cursor > -1) {
$ep->ToggleFold($cursor) if $ep->GetFoldExpanded($cursor);
$cursor--;
}
}
sub unfold_all {
my $ep = _ep_ref();
my $cursor = $ep->GetLineCount()-1;
while ($cursor > -1) {
$ep->ToggleFold($cursor) unless $ep->GetFoldExpanded($cursor);
$cursor--;
}
}
sub show_folded_children {
#my $ep = _ep_ref();
#my $parent = _get_line(@_);
#unless ( _is_head_level( $ep->GetFoldLevel($parent) ) ) {
#$parent = $ep->GetFoldParent($parent);
#return if $parent == -1;
#}
#$ep->ToggleFold($parent) unless $ep->GetFoldExpanded($parent);
#my $cursöor = $ep->GetLastChild( $parent, -1 );
#my $level = $ep->GetFoldLevel($parent) >> 16;
#while (@cursor > $parent) {
#$ep->ToggleFold($cursor) if $ep->GetFoldLevel($cursor) % 2048 == $level
#and $ep->GetFoldExpanded($cursor);
#$cursor--;
#}
}
1;
=head1 NAME
Kephra::App::EditPanel::Fold - code folding functions
=head1 DESCRIPTION
=cut