package CLI::TabBar; use vars qw($VERSION); $VERSION = '0.7'; use Carp; use Text::Wrap; use Text::Tabs qw(expand unexpand); use strict; sub new { my $proto = shift; my $self = { }; bless($self, $proto); $self->{CurrentTab} = ""; $self->{order} = []; $self->{rows} = []; $self->{screenHeight} = $main::GUI{maxY} - 2 - $self->Height(); $main::GUI{window}->setscrreg($self->Height(),$main::GUI{maxY}-2); return $self; } sub Refresh { my $cw = shift; $cw->RecalculatePositions(); $cw->DrawTabs(); $cw->RaiseTab($cw->{vars}->{CurrentTab},1); } sub Height { my $self = shift; return $#{$self->{rows}} + 1; } sub RecalculatePositions { my $self = shift; my $row = 0; my $col = 0; my $x = 1; $self->{rows} = (); my $width = $main::GUI{maxX} - 1; my $order = 0; foreach my $index (0..$#{$self->{order}}) { my $tag = $self->{order}->[$index]; next if ($self->{tags}->{$tag}->{hidden} == 1); $self->CharacterizeTab($tag,$order); $order++; if ((($x + $self->{tags}->{$tag}->{width}) > $width) && ($col != 0)) { $col = 0; $row++; $x = 1; } $self->{tags}->{$tag}->{row} = $row; $self->{tags}->{$tag}->{realRow} = $row; $self->{tags}->{$tag}->{col} = $col; $self->{tags}->{$tag}->{x} = $x; $x += $self->{tags}->{$tag}->{width}; $col++; $self->{rows}->[$row]->{width} = $x; $self->{rows}->[$row]->{count} = $col; } $Text::Wrap::columns = $main::GUI{maxX} - 1; $self->{screenHeight} = $main::GUI{maxY} - 2 - $self->Height(); $main::GUI{window}->setscrreg($self->Height(),$main::GUI{maxY}-3); } sub CharacterizeTab { my ($self,$tag,$order) = @_; $self->{tags}->{$tag}->{width} = 1 + length($order) + 1 + length($self->{tags}->{$tag}->{text}) + 1; $self->{tags}->{$tag}->{order} = $order; $self->{tags}->{$tag}->{width} = 0 if ($self->{tags}->{$tag}->{hidden} == 1); } ########################################################################### # # # ########################################################################### sub DrawTabs { my ($self) = @_; my $y = 0; my @string; my $type; my $string; my $length; foreach my $row (reverse(0..$#{$self->{rows}})) { @string = (); $length = 0; foreach my $index (0..$#{$self->{order}}) { my $tag = $self->{order}->[$index]; next if ($self->{tags}->{$tag}->{hidden} == 1); next if ($self->{tags}->{$tag}->{row} != $row); my $type = 4; $type = 5 if ($self->Raised($tag)); push(@string,$type," ".$self->{tags}->{$tag}->{order}.")"); my $subtype = $type; $subtype = $self->{tags}->{$tag}->{highlight} if exists($self->{tags}->{$tag}->{highlight}); push(@string,$subtype,$self->{tags}->{$tag}->{text}); push(@string,$type," "); $length += $self->{tags}->{$tag}->{width}; } push(@string,4," "x($main::GUI{maxX} - $length)); $main::GUI{window}->move($y,0); $main::GUI{window}->clrtoeol(); $length = 0; while($#string > -1) { $type = shift(@string); $string = shift(@string); $main::GUI{window}->attron(main::COLOR_PAIR($type)); $main::GUI{window}->addstr($y,$length,$string); $main::GUI{window}->attrset(0); $length += length($string); } $y++; } $main::GUI{window}->move($y,0); $main::GUI{window}->attrset(0); $main::GUI{window}->refresh(); $self->RaiseTab($self->CurrentTab(),1); } ########################################################################### # # # ########################################################################### sub AddTab { my $self = shift; my (%args) = @_; if (!exists($args{text}) || !exists($args{tag})) { croak("ERROR: AddTab: must set text and tag arguments"); } push(@{$self->{order}},$args{tag}); $self->{tags}->{$args{tag}}->{text} = $args{text}; $self->{tags}->{$args{tag}}->{raisecb} = $args{raisecb} if exists($args{raisecb}); $self->RecalculatePositions(); $self->DrawTabs(); } ########################################################################### # # # ########################################################################### sub DeleteTab { my($self,$tag,$type) = @_; return if !exists($self->{tags}->{$tag}); if ($self->Raised($tag)) { if ($self->{order}->[0] eq $tag) { if ($#{$self->{order}} == 0) { $self->UnpackTab($tag); } else { $self->RaiseTab($self->{order}->[1]); } } else { $self->RaiseTab($self->{order}->[0]); } } #--------------------------------------------------------------------------- # Remove this tag from the order #--------------------------------------------------------------------------- my $order = -1; foreach my $index (0..$#{$self->{order}}) { $order = $index if ($self->{order}->[$index] eq $tag); } splice(@{$self->{order}},$order,1); delete($self->{tags}->{$tag}); $self->RecalculatePositions(); $self->DrawTabs(); } ########################################################################### # # RaiseTab - Code to handle switching over to this tab # ########################################################################### sub RaiseTab { my ($self,$tag,$raiseitanyway) = @_; return if ($tag eq ""); $raiseitanyway = 0 if (!defined($raiseitanyway) || ($raiseitanyway eq "")); return if ($self->Raised($tag) && ($raiseitanyway != 1)); $self->RemoveTransients($self->{CurrentTab}); $self->{CurrentTab} = $tag; $self->UnhighlightTab($tag); if ($self->{tags}->{$tag}->{row} != 0) { foreach my $tempTag (keys(%{$self->{tags}})) { $self->{tags}->{$tempTag}->{row} = $self->{tags}->{$tempTag}->{realRow}; } my $row = $self->{tags}->{$tag}->{row}; foreach my $tempTag (keys(%{$self->{tags}})) { if ($self->{tags}->{$tempTag}->{row} < $row) { $self->{tags}->{$tempTag}->{row} += 1; } else { if ($self->{tags}->{$tempTag}->{row} == $row) { $self->{tags}->{$tempTag}->{row} = 0; } } } } $self->DrawTabs() unless ($raiseitanyway == 1); $self->DrawTabContents($tag); &{$self->{tags}->{$tag}->{raisecb}}() if exists($self->{tags}->{$tag}->{raisecb}); } sub DrawTabContents { my $self = shift; my $tag = shift; my $bottom = $#{$self->{screen}->{$tag}}; my $top = $#{$self->{screen}->{$tag}} - $self->{screenHeight} + 1; $top = 0 if ($top < 0); foreach my $y ($self->Height()..($main::GUI{maxY}-3)) { $main::GUI{window}->move($y,0); $main::GUI{window}->clrtoeol(); } my $y = $main::GUI{maxY}-3; my $type; my $text; my $colorIndex; my $bound; my $piece; my $next; foreach my $line ($top..$bottom) { $main::GUI{window}->scroll(); $main::GUI{window}->move($y,0); $main::GUI{window}->clrtoeol(); my $x = 0; my $text = $self->{screen}->{$tag}->[$line]; while ($text !~ /^\s*$/) { $text =~ s/^\#t\#//; if ($text =~ /^\#c\#\d+\#/) { $text =~ s/^\#c\#(\d+)\#//; $type = $1; if (defined($type)) { $main::GUI{window}->attron(main::COLOR_PAIR($type)); next; } } $colorIndex = index($text,"#c#",1); $bound = (($colorIndex > ($Text::Wrap::columns - $x) || ($colorIndex == -1)) ? ($Text::Wrap::columns - $x) : $colorIndex ); if ($text =~ s/^([^\n]{0,$bound})(\#|\s|\Z(?!\n))//xm) { $piece = $1; $next = $2; $main::GUI{window}->addstr($y,$x,$piece); $x += length($piece); if (($next ne "#") || ($x == $Text::Wrap::columns)) { $x = 0; if (($next eq " ") || (($next eq "\n") && ($text =~ /\S+/))) { $main::GUI{window}->scroll(); $main::GUI{window}->addstr($y,$x," "x12); $x += 12; } } $text = "#".$text if ($next eq "#"); } else { if ($text =~ s/^([^\n]{0,$bound})//) { $piece = $1; $main::GUI{window}->addstr($y,$x,$piece); $x += length($piece); if ($x == $Text::Wrap::columns) { $x = 0; $main::GUI{window}->scroll(); $main::GUI{window}->addstr($y,$x," "x12); $x += 12; } } } } $main::GUI{window}->attrset(0); } $main::GUI{window}->move($main::GUI{maxY}-1,0); $main::GUI{window}->refresh(); } sub Print { my $self = shift; my $tag = $self->CurrentTab(); my $type = "normal"; my $control = ""; if ($_[0] eq "__jarl__:tabbar") { $control = shift; $tag = shift; $type = shift; } if ($_[0] eq "__jarl__:tabbar:transient") { $control = shift; } foreach my $piece (@_) { if (($#{$self->{screen}->{$tag}} == -1) || ($self->{screen}->{$tag}->[$#{$self->{screen}->{$tag}}] =~ /\n$/)) { if ($control eq "__jarl__:tabbar:transient") { push(@{$self->{screen}->{$tag}},"#t#"); } else { push(@{$self->{screen}->{$tag}},""); } } $self->{screen}->{$tag}->[$#{$self->{screen}->{$tag}}] .= "#c#$main::types{$type}#$piece"; } shift(@{$self->{screen}->{$tag}}) if ($#{$self->{screen}->{$tag}} == 99); $self->DrawTabContents($tag) if ($self->Raised($tag)); } sub RemoveTransients { my $self = shift; my $tag = shift; foreach my $line (reverse(0..$#{$self->{screen}->{$tag}})) { splice(@{$self->{screen}->{$tag}},$line,1) if ($self->{screen}->{$tag}->[$line] =~ /^\#t\#/); } } sub CurrentTab { my ($self) = @_; return $self->{CurrentTab}; } sub CurrentText { my ($self) = @_; return $self->{tags}->{$self->{CurrentTab}}->{text}; } sub Raised { my ($self,$tag) = @_; return ($self->{CurrentTab} eq $tag); } sub ExistsTab { my ($self,$tag) = @_; return exists($self->{tags}->{$tag}); } sub HighlightTab { my ($self,$tag,$priority) = @_; return if $self->Raised($tag); $priority = "low" if (!defined($priority) || (($priority ne "low") && ($priority ne "medium") && ($priority ne "high")) ); my $priorityValue = $priority eq "low" ? 1 : ($priority eq "medium" ? 2 : 3); my $highlight = (exists($self->{tags}->{$tag}->{highlight}) ? $self->{tags}->{$tag}->{highlight} : 0 ); if ($priorityValue > $highlight) { $self->{tags}->{$tag}->{highlight} = $priorityValue; } $self->DrawTabs(); } sub UnhighlightTab { my ($self,$tag) = @_; delete($self->{tags}->{$tag}->{highlight}); } sub FindOrder { my $self = shift; my ($tag) = @_; return (exists($self->{tags}->{$tag}->{order}) ? $self->{tags}->{$tag}->{order} : -1); } sub GetOrder { my $self = shift; my $index = shift; foreach my $tag (keys(%{$self->{tags}})) { next unless exists($self->{tags}->{$tag}->{order}); return $tag if ($self->{tags}->{$tag}->{order} == $index); } } sub HideTab { my ($self,$tag) = @_; return if ($self->{tabs}->{order}->[0] eq $tag); $self->{tags}->{$tag}->{hidden} = 1; if ($self->Raised($tag)) { $self->RaiseTab($self->{order}->[0]); } $self->Refresh(); } sub ShowTab { my ($self,$tag) = @_; my $hidden = $self->{tags}->{$tag}->{hidden}; $self->{tags}->{$tag}->{hidden} = 0; $self->Refresh(); $self->RaiseTab($tag) if ($hidden == 1); } 1;