package Tk::TabBar;

use vars qw($VERSION %TYPES);
$VERSION = '0.7';

use Tk;
require Tk::Frame;

use Carp;
use strict;
use base qw(Tk::Frame);
Construct Tk::Widget 'TabBar';

$TYPES{fixed} = 0;
$TYPES{docked} = 1;
$TYPES{undocked} = 2;
$TYPES{0} = "fixed";
$TYPES{1} = "docked";
$TYPES{2} = "undocked";

sub Populate {
  my ($cw, $args) = @_;

  my %args = %{$args};
  $cw->{args} = \%args;

  $args->{-height} = 30;
  $args->{-highlightthickness} = 0;

  $cw->{vars}->{Height} = 30;

  $cw->{vars}->{Tabs}->{DockableBG} = 
    $cw->ParseArg($args,"-tabdockablebg","black");

  $cw->{vars}->{Tabs}->{Background} =
    $cw->ParseArg($args,"-tabbackground","white");

  $cw->{vars}->{Tabs}->{DisabledBackground} =
    $cw->ParseArg($args,"-tabdisabledbackground",$cw->{vars}->{Tabs}->{Background});

  $cw->{vars}->{Tabs}->{Foreground} =
    $cw->ParseArg($args,"-tabforeground","black");

  $cw->{vars}->{Tabs}->{Highlight}->{Low} =
    $cw->ParseArg($args,"-tabhighlightlow","red");

  $cw->{vars}->{Tabs}->{Highlight}->{Medium} =
    $cw->ParseArg($args,"-tabhighlightmedium","purple");

  $cw->{vars}->{Tabs}->{Highlight}->{High} =
    $cw->ParseArg($args,"-tabhighlighthigh","white");

  $cw->{vars}->{Tabs}->{Fill} =
    $cw->ParseArg($args,"-tabfill","black");

  $cw->{vars}->{Tabs}->{Font} =
    $cw->ParseArg($args,"-tabfont","");

  $cw->{vars}->{Tabs}->{PadX} =
    $cw->ParseArg($args,"-tabpadx",0);

  $cw->{vars}->{Tabs}->{PadY} =
    $cw->ParseArg($args,"-tabpady",0);

  $cw->{vars}->{Tabs}->{Thickness} =
    $cw->ParseArg($args,"-tabthickness",1);

  $cw->{vars}->{Undocked} = 
    $cw->ParseArg($args,"-undocked",0);

  $cw->{vars}->{UndockedTitlePrefix} =
    $cw->ParseArg($args,"-undockedtitleprefix","Undocked");

  $cw->{vars}->{CurrentTab} = "";

  $cw->{tabs}->{order} = [];

  $cw->{rows}->[0]->{width} = 0;
  $cw->{rows}->[0]->{count} = 0;

  $cw->{frame} =
    $cw->
      Frame(-background=>$cw->{vars}->{Tabs}->{Background},
	   )->pack(-side=>'top',
		   -padx=>0,
		   -pady=>0,
		   -fill=>'both',
		   -expand=>1);

  $cw->{canvas} =
    $cw->{frame}->
      Canvas(%{$args})->pack(-side=>'top',
			     -fill=>'both');

  $cw->{popup}->{menu} =
    $cw->
      Menu(-tearoff=>0,
	   -background=>$cw->{vars}->{Tabs}->{Background},
	   -foreground=>$cw->{vars}->{Tabs}->{Foreground},
	   (
	    (ref($cw->{vars}->{Tabs}->{Font}) eq "Tk::Font") ?
	    (-font=>$cw->{vars}->{Tabs}->{Font}) :
	    (
	     ($cw->{vars}->{Tabs}->{Font} ne "") ?
	     (-font=>$cw->{vars}->{Tabs}->{Font}) :
	     ()
	    )
	   ),
	  );

  $cw->{popup}->{menu}->
    add("command",
	-label=>"Undock",
	-state=>"disabled",
	-background=>$cw->{vars}->{Tabs}->{Background},
	-foreground=>$cw->{vars}->{Tabs}->{Foreground},
	(
	 (ref($cw->{vars}->{Tabs}->{Font}) eq "Tk::Font") ? 
	 (-font=>$cw->{vars}->{Tabs}->{Font}) : 
	 (
	  ($cw->{vars}->{Tabs}->{Font} ne "") ? 
	  (-font=>$cw->{vars}->{Tabs}->{Font}) : 
	  ()
	 )
	),
	-command=>sub{
	  $cw->UnDockTab($cw->{vars}->{ActiveTab});
	}
       );

  $cw->{popup}->{menu}->
    add("command",
	-label=>"Dock",
	-state=>"disabled",
	-background=>$cw->{vars}->{Tabs}->{Background},
	-foreground=>$cw->{vars}->{Tabs}->{Foreground},
	(
	 (ref($cw->{vars}->{Tabs}->{Font}) eq "Tk::Font") ? 
	 (-font=>$cw->{vars}->{Tabs}->{Font}) : 
	 (
	  ($cw->{vars}->{Tabs}->{Font} ne "") ? 
	  (-font=>$cw->{vars}->{Tabs}->{Font}) : 
	  ()
	 )
	),
	-command=>sub{
	  $cw->parent->parent->parent->DockTab($cw->{vars}->{ActiveTab});
	}
       );

  $cw->{canvas}->CanvasBind("<Configure>",
			    sub {
			      $cw->Refresh();
			    }
			   );
}


sub ParseArg {
  my $cw = shift;
  my ($args,$arg,$default) = @_;
  return (exists($args->{$arg}) ? delete($args->{$arg}) : $default);
}


sub Refresh {
  my $cw = shift;

  #print "($cw) Refresh: start\n";

  $cw->RecalculatePositions();
  $cw->DrawTabs();
  $cw->RaiseTab($cw->{vars}->{CurrentTab},1);

  #print "($cw) Refresh: finish\n";
}


sub RecalculatePositions {
  my $cw= shift;

  my $row = 0;
  my $col = 0;
  my $x = 0;

  $cw->{rows} = ();

  my $canvasWidth = $cw->{canvas}->width();
  $canvasWidth = $cw->{canvas}->reqwidth() if ($canvasWidth < 10);

  foreach my $index (0..$#{$cw->{tabs}->{order}}) {
    my $tag = $cw->{tabs}->{order}->[$index];
    $cw->CharacterizeTab($tag);

    if ((($x + $cw->{tabs}->{tags}->{$tag}->{width}) > $canvasWidth) && 
	($col != 0)) {
      $col = 0;
      $row++;
      $x = 0;
    }

    $cw->{tabs}->{tags}->{$tag}->{row} = $row;
    $cw->{tabs}->{tags}->{$tag}->{realRow} = $row;
    $cw->{tabs}->{tags}->{$tag}->{col} = $col;
    $cw->{tabs}->{tags}->{$tag}->{x} = $x;

    $x += $cw->{tabs}->{tags}->{$tag}->{width};
    $col++;
    $cw->{rows}->[$row]->{width} = $x;
    $cw->{rows}->[$row]->{count} = $col;
  }

  $cw->CharacterizeCanvas();
}



sub CharacterizeTab {
  my ($cw,$tag) = @_;
  
  #print "($cw) CharacterizeTab: tag($tag)\n";

  $cw->{canvas}->
    createText(10000,10000,
	       -text=>$cw->{tabs}->{tags}->{$tag}->{text},
	       (
		(ref($cw->{vars}->{Tabs}->{Font}) eq "Tk::Font") ? 
		(-font=>$cw->{vars}->{Tabs}->{Font}) : 
		(
		 ($cw->{vars}->{Tabs}->{Font} ne "") ? 
		 (-font=>$cw->{vars}->{Tabs}->{Font}) : 
		 ()
		)
	       ),
	       -tags=>[ "tktabbartest" ]);

  my ($x1,$y1,$x2,$y2) = $cw->{canvas}->bbox("tktabbartest");

  $cw->{canvas}->delete("tktabbartest");

  $cw->{vars}->{Height} = $y2 - $y1 + 18;
  $cw->{tabs}->{tags}->{$tag}->{width} = $x2 - $x1 + 14;
  $cw->{tabs}->{tags}->{$tag}->{width} = 0
    if ($cw->{tabs}->{tags}->{$tag}->{hidden} == 1);
}


sub CharacterizeCanvas {
  my $cw = shift;
  $cw->{canvas}->configure(-height=>(($#{$cw->{rows}}+1)*$cw->{vars}->{Height}));
  $cw->{vars}->{Width} = $cw->{canvas}->width();
}


###########################################################################
#
#
#
###########################################################################
sub DrawTabs {
  my ($cw) = @_;

  #print "($cw) DrawTabs: start\n";

  $cw->{canvas}->delete("all");

  $cw->{canvas}->
    createRectangle(0,($cw->{vars}->{Height}-5),
		    10000,((($#{$cw->{rows}}+1)*$cw->{vars}->{Height})+5),
		    -fill=>$cw->{vars}->{Tabs}->{DisabledBackground},
		    -outline=>$cw->{vars}->{Tabs}->{DisabledBackground},
		    -tags=>["disabledTabs"]);

  foreach my $index (0..($#{$cw->{rows}}-1)) {
    $cw->{canvas}->
      createLine(0,((($#{$cw->{rows}}-$index)*$cw->{vars}->{Height})-6),
		 10000,((($#{$cw->{rows}}-$index)*$cw->{vars}->{Height})-6),
		 -width=>$cw->{vars}->{Tabs}->{Thickness},
		 -fill=>$cw->{vars}->{Tabs}->{Fill},
		 -tags=>["disabledLines"]);
  }

  my @tabs;

  foreach my $index (0..$#{$cw->{tabs}->{order}}) {
    my $tag = $cw->{tabs}->{order}->[$index];
    $cw->DrawTab($tag,$cw->{tabs}->{tags}->{$tag}->{text})
      unless ($cw->{tabs}->{tags}->{$tag}->{hidden} == 1);
    push(@tabs,$tag) if (($cw->{tabs}->{tags}->{$tag}->{x} == 0) && 
			 ($cw->{tabs}->{tags}->{$tag}->{row} != 0));
  }

  $cw->{canvas}->
    createLine(0,((($#{$cw->{rows}}+1)*$cw->{vars}->{Height})-6),
	       10000,((($#{$cw->{rows}}+1)*$cw->{vars}->{Height})-6),
	       -width=>$cw->{vars}->{Tabs}->{Thickness},
	       -fill=>$cw->{vars}->{Tabs}->{Fill},
	       -tags=>["line"]);
  $cw->{canvas}->
    createRectangle(0,((($#{$cw->{rows}}+1)*$cw->{vars}->{Height})-5),
		    10000,((($#{$cw->{rows}}+1)*$cw->{vars}->{Height})+5),
		    -fill=>$cw->{vars}->{Tabs}->{Background},
		    -outline=>$cw->{vars}->{Tabs}->{Background},
		    -tags=>["line"]);

  #print "($cw) DrawTabs: currentTab($cw->{vars}->{CurrentTab})\n";

  foreach (@tabs) {
    $cw->{canvas}->raise("disabledLines","all");
    $cw->{canvas}->raise($_,"disabledLines");
  }

  $cw->RaiseTab($cw->{vars}->{CurrentTab},1)
    if !($cw->Raised(""));

  #print "($cw) DrawTabs: finish\n";
}


###########################################################################
#
#
#
###########################################################################
sub DrawTab {
  my($cw,$tag,$text) = @_;

  #print "($cw) DrawTab: start\n";
  #print "($cw) DrawTab: tag($tag) text($text)\n";

  my $openSpace = $cw->{tabs}->{tags}->{$tag}->{x};
  my $row = $cw->{tabs}->{tags}->{$tag}->{row};

  #print "($cw) DrawTab: openSpace($openSpace) row($row)\n";

  my $baseY = ($#{$cw->{rows}} - $row) * $cw->{vars}->{Height};

  #print "($cw) DrawTab: baseY($baseY)\n";
 
  my $highlight = (exists($cw->{tabs}->{tags}->{$tag}->{highlight}) ? 
		   $cw->{tabs}->{tags}->{$tag}->{highlight} : 
		   0
		  );

  my $textFill = ($highlight == 0 ?
		  $cw->{vars}->{Tabs}->{Foreground} :
		  (
		   ($highlight == 1) ?
		   $cw->{vars}->{Tabs}->{Highlight}->{Low} :		   
		   (
		    ($highlight == 2) ?
		    $cw->{vars}->{Tabs}->{Highlight}->{Medium} :
		    $cw->{vars}->{Tabs}->{Highlight}->{High}
		   )
		  )
		 );
  
  $cw->{canvas}->
    createPolygon((1+$openSpace),$baseY+($cw->{vars}->{Height}-6),
		  (1+$openSpace),$baseY+5,
		  (3+$openSpace),$baseY+3,
		  (($cw->{tabs}->{tags}->{$tag}->{width}-2)+$openSpace),$baseY+3,
		  (($cw->{tabs}->{tags}->{$tag}->{width})+$openSpace),$baseY+5,
		  (($cw->{tabs}->{tags}->{$tag}->{width})+$openSpace),$baseY+($cw->{vars}->{Height}-6),
		  -width=>$cw->{vars}->{Tabs}->{Thickness},
		  -fill=>$cw->{vars}->{Tabs}->{Background},
		  -outline=>$cw->{vars}->{Tabs}->{Fill},
		  -tags=>[ $tag , "tab-$tag" , "tabs" ]);
  $cw->{canvas}->
    createLine((1+$openSpace),$baseY+($cw->{vars}->{Height}-6),
	       (($cw->{tabs}->{tags}->{$tag}->{width})+$openSpace),$baseY+($cw->{vars}->{Height}-6),
	       -fill=>$cw->{vars}->{Tabs}->{Background},
	       -tags=>[ $tag , "tab-$tag" , "tabs" ]);
  
  $cw->{canvas}->
    createLine((0+$openSpace),$baseY+($cw->{vars}->{Height}-6),
	       (2+$openSpace),$baseY+($cw->{vars}->{Height}-6),
	       -fill=>$cw->{vars}->{Tabs}->{Fill},
	       -tags=>[ $tag ]);
  
  $cw->{canvas}->
    createLine(($cw->{tabs}->{tags}->{$tag}->{width}+$openSpace),$baseY+5,
	       ($cw->{tabs}->{tags}->{$tag}->{width}+$openSpace),$baseY+($cw->{vars}->{Height}-6),
	       -fill=>"black",
	       -tags=>[ $tag ]);
  
  $cw->{canvas}->
    createLine(($cw->{tabs}->{tags}->{$tag}->{width}-1+$openSpace),$baseY+4,
	       ($cw->{tabs}->{tags}->{$tag}->{width}+$openSpace),$baseY+5,
	       -fill=>"black",
	       -tags=>[ $tag ]);

  my $type = (exists($cw->{tabs}->{tags}->{$tag}->{type}) ?
	      $cw->{tabs}->{tags}->{$tag}->{type} :
	      $TYPES{fixed}
	     );
  
  if (($type eq $TYPES{docked}) || ($type eq $TYPES{undocked})) {
    $cw->{canvas}->
      createPolygon((2+$openSpace),$baseY+8,
		    (6+$openSpace),$baseY+4,
		    (2+$openSpace),$baseY+4,
		    -width=>0,
		    -fill=>$cw->{vars}->{Tabs}->{DockableBG},
		    -tags=>[ $tag ]);
    $cw->{canvas}->
      createLine((1+$openSpace),$baseY+5,
		 (3+$openSpace),$baseY+3,
		 -fill=>$cw->{vars}->{Tabs}->{Fill},
		 -tags=>[ $tag ]);
  }
  
  $cw->{canvas}->
    createText((($cw->{tabs}->{tags}->{$tag}->{width}/2)+$openSpace),$baseY+(($cw->{vars}->{Height}-4)/2),
	       -text=>$text,
	       (
		(ref($cw->{vars}->{Tabs}->{Font}) eq "Tk::Font") ? 
		(-font=>$cw->{vars}->{Tabs}->{Font}) : 
		(
		 ($cw->{vars}->{Tabs}->{Font} ne "") ? 
		 (-font=>$cw->{vars}->{Tabs}->{Font}) : 
		 ()
		)
	       ),
	       -fill=>$textFill,
	       -tags=>[ $tag , "text$tag" ]);

  $cw->{canvas}->
    bind($tag,"<Button-1>",sub{ $cw->RaiseTab($tag); });
  
  $cw->{canvas}->
    bind($tag,"<Button-3>",sub{
	   $cw->{vars}->{ActiveTab} = $tag;
	   $cw->{popup}->{menu}->entryconfigure(0,-state=>"disabled");
	   $cw->{popup}->{menu}->entryconfigure(1,-state=>"normal");
	   $cw->{popup}->{menu}->
	     Popup(-popover=>"cursor",
		   -popanchor=>"nw");
	 })
      if ($type eq $TYPES{undocked});

  $cw->{canvas}->
    bind($tag,"<Button-3>",sub{
	   $cw->{vars}->{ActiveTab} = $tag;
	   $cw->{popup}->{menu}->entryconfigure(0,-state=>"normal");
	   $cw->{popup}->{menu}->entryconfigure(1,-state=>"disabled");
	   $cw->{popup}->{menu}->
	     Popup(-popover=>"cursor",
		   -popanchor=>"nw");
	 })
      if ($type eq $TYPES{docked});

  #print "($cw) DrawTab: finish\n";
}


###########################################################################
#
#
#
###########################################################################
sub AddTab {
  my ($cw,@args) = @_;
  my %args;
  while($#args > -1) {
    my $key = shift(@args); $key =~ s/^\-//; $args{ lc($key) } = shift(@args); 
  }

  $args{type} = "fixed" if !exists($args{type});

  #print "($cw) AddTab: start\n";
  #print "($cw) AddTab: type($args{type}) tag($args{tag}) text($args{text})\n";

  if ((!exists($args{text}) && ($args{type} ne "docking")) || 
      !exists($args{tag})) {
    croak("ERROR: AddTab: must set text and tag arguments");
  }

  $args{text} = $cw->{tabs}->{tags}->{$args{tag}}->{text}
    if ($args{type} eq "docking");

  if (($args{type} ne "fixed") && ($args{type} ne "docked") &&
      ($args{type} ne "undocked") && ($args{type} ne "docking")) {
    croak("ERROR: type($args{type}) not correct in call to AddTab\n");
  }

  splice(@{$cw->{tabs}->{order}},$#{$cw->{tabs}->{order}}+1,0,$args{tag});

  ($cw->{tabs}->{tags}->{$args{tag}}->{type} = $TYPES{$args{type}})
    unless ($args{type} eq "fixed");
  ($cw->{tabs}->{tags}->{$args{tag}}->{type} = $TYPES{docked})
    if ($args{type} eq "docking");
  $cw->{tabs}->{tags}->{$args{tag}}->{text} = $args{text};

  my $packframe;

  if ((($args{type} eq "docked") || ($args{type} eq "undocked")) &&
      ($cw->{vars}->{Undocked} == 0)) {

    my $toplevel = $cw->{frame}->Toplevel();

    $toplevel->withdraw() if ($args{type} eq "docked");

    $cw->{tabs}->{tags}->{$args{tag}}->{tabbar} =
      $toplevel->
	TabBar(%{$cw->{args}},
	       -undocked=>1
	      )->pack(-side=>"top",
		      -fill=>"both",
		      -expand=>1);

    $cw->{tabs}->{tags}->{$args{tag}}->{tabbar}->HideCanvas()
      if ($args{type} eq "docked");

    $packframe =
      $cw->{tabs}->{tags}->{$args{tag}}->{tabbar}->AddTab(-type=>"undocked",
							  -tag=>$args{tag},
							  -text=>$args{text});

    $cw->{tabs}->{tags}->{$args{tag}}->{tabbar}->RaiseTab($args{tag});

    $toplevel->wmCapture() if ($args{type} eq "docked");

    $cw->{tabs}->{tags}->{$args{tag}}->{frame} = $toplevel;

    $cw->DeleteTab($args{tag},"undocked") if ($args{type} eq "undocked");
  }

  if (($args{type} eq "fixed") || ($cw->{vars}->{Undocked} == 1)) {
    $packframe =
      $cw->{tabs}->{tags}->{$args{tag}}->{frame} =
	$cw->{frame}->Frame(-background=>$cw->{vars}->{Tabs}->{Background});
  }

  #---------------------------------------------------------------------------
  # Characterize the tab and get the height and width
  #---------------------------------------------------------------------------
  $cw->CharacterizeTab($args{tag});

  #---------------------------------------------------------------------------
  # Now calculate the row and column number that the tab should have and
  # update the rows hash, and the tab info.
  #---------------------------------------------------------------------------
  my $realRow;
  my $row;
  my $col;
  my $x;

  my $order = $cw->FindOrder($args{tag});
  if ($order > 0) {
    $row = $cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$order - 1]}->{row};
    $realRow = $cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$order - 1]}->{realRow};
  } else {
    $row = 0;
    $realRow = 0;
  }

  my $rowWidth = $cw->{rows}->[$row]->{width};
  my $canvasWidth = $cw->{canvas}->width();
  $canvasWidth = $cw->{canvas}->reqwidth() if ($canvasWidth < 10);

  if (($rowWidth + $cw->{tabs}->{tags}->{$args{tag}}->{width}) > $canvasWidth) {
    $cw->{rows}->[$#{$cw->{rows}}+1]->{width} = 
      $cw->{tabs}->{tags}->{$args{tag}}->{width};
    $cw->{rows}->[$#{$cw->{rows}}]->{count} = 1;
    $row = $#{$cw->{rows}};
    $realRow = $#{$cw->{rows}};
    $col = 0;
    $x = 0;
  } else {
    $x = $cw->{rows}->[$row]->{width};
    $cw->{rows}->[$row]->{width} += $cw->{tabs}->{tags}->{$args{tag}}->{width};
    $cw->{rows}->[$row]->{count}++;
    $col = $cw->{rows}->[$row]->{count} - 1;
  }

  $cw->{tabs}->{tags}->{$args{tag}}->{row} = $row;
  $cw->{tabs}->{tags}->{$args{tag}}->{realRow} = $realRow;
  $cw->{tabs}->{tags}->{$args{tag}}->{col} = $col;
  $cw->{tabs}->{tags}->{$args{tag}}->{x} = $x;

  #print "($cw) AddTab: row($row) col($col) x($x)\n";

  $cw->CharacterizeCanvas();

  #---------------------------------------------------------------------------
  # Draw the tabs if this is not an undocked window.
  #---------------------------------------------------------------------------
  $cw->DrawTabs() if (($args{type} ne "undocked") ||
		      $cw->{vars}->{Undocked} == 1);

  #print "($cw) AddTab: finish\n";

  #---------------------------------------------------------------------------
  # Return the frame the user should use to pack everything into.
  #---------------------------------------------------------------------------
  return $packframe;
}


sub RaiseFirstAvailable {
  my $cw = shift;
  my $tag = shift;

  if ($cw->FirstShown() eq $tag) {
    if ($#{$cw->{tabs}->{order}} == 0) {
      $cw->UnpackTab($tag);
    } else {
      $cw->RaiseTab($cw->SecondShown())
	unless ($cw->SecondShown eq "");
    }
  } else {
    $cw->RaiseTab($cw->FirstShown());
  }
}


###########################################################################
#
#
#
###########################################################################
sub DeleteTab {
  my($cw,$tag,$type) = @_;

  #print "($cw) DeleteTab: start\n";
  #print "($cw) DeleteTab: tag($tag) type($type)\n";

  $type = "" unless defined($type);

  return if !exists($cw->{tabs}->{tags}->{$tag});

  if ($cw->Raised($tag)) {
    $cw->RaiseFirstAvailable($tag);
  }

  $cw->{canvas}->delete($tag);

  #---------------------------------------------------------------------------
  # Now reposition the other tabs
  #---------------------------------------------------------------------------

  #print "($cw) DeleteTab: from row($cw->{tabs}->{tags}->{$tag}->{row}) col($cw->{tabs}->{tags}->{$tag}->{col})\n";

  my $canvasWidth = $cw->{canvas}->width();
  $canvasWidth = $cw->{canvas}->reqwidth() if ($canvasWidth < 10);

  $cw->{rows}->[$cw->{tabs}->{tags}->{$tag}->{row}]->{count}--;
  $cw->{rows}->[$cw->{tabs}->{tags}->{$tag}->{row}]->{width} -=
    $cw->{tabs}->{tags}->{$tag}->{width};

  my $order = $cw->FindOrder($tag);
  foreach my $index (($order+1)..$#{$cw->{tabs}->{order}}) {
    my $currTag = $cw->{tabs}->{order}->[$index];
    my $oldRow = $cw->{tabs}->{tags}->{$currTag}->{row};

    if ($oldRow == $cw->{tabs}->{tags}->{$tag}->{row}) {
      #print "($cw) DeleteTab: tag($currTag) is on the same row...\n";
      #print "($cw) DeleteTab: moving tag($currTag) from col($cw->{tabs}->{tags}->{$currTag}->{col}) and x($cw->{tabs}->{tags}->{$currTag}->{x})\n";
      $cw->{tabs}->{tags}->{$currTag}->{col}--;
      if ($index == ($order+1)) {
	$cw->{tabs}->{tags}->{$currTag}->{x} =
	  $cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$index-1]}->{x};
      } else {
	$cw->{tabs}->{tags}->{$currTag}->{x} =
	  $cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$index-1]}->{x} + 
	    $cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$index-1]}->{width};
      }

      #print "($cw)            to col($cw->{tabs}->{tags}->{$currTag}->{col}) and x($cw->{tabs}->{tags}->{$currTag}->{x})\n";
    } else {
      #print "($cw) DeleteTab: tag($currTag) is not on the same row...\n";
      #print "($cw) DeleteTab: tag($currTag) is in col($cw->{tabs}->{tags}->{$currTag}->{col})\n";
      if ($cw->{tabs}->{tags}->{$currTag}->{col} == 0) {
	#print "($cw) DeleteTab: check if tag($currTag) can be moved to the previous row\n";
	if (($cw->{rows}->[$oldRow-1]->{width} + $cw->{tabs}->{tags}->{$currTag}->{width}) < $canvasWidth) {
	  #print "($cw) DeleteTab: it can...\n";

	  my $newRow = $oldRow - 1;

	  #print "($cw) DeleteTab: moving tag($currTag) from row($oldRow) and col($cw->{tabs}->{tags}->{$currTag}->{col})\n";

	  $cw->{rows}->[$oldRow]->{count}--;
	  $cw->{rows}->[$oldRow]->{width} -=
	    $cw->{tabs}->{tags}->{$currTag}->{width};
	  $cw->{tabs}->{tags}->{$currTag}->{row}--;
	  $cw->{tabs}->{tags}->{$currTag}->{realRow}--;
	  $cw->{rows}->[$newRow]->{count}++;
	  $cw->{tabs}->{tags}->{$currTag}->{col} =
	    $cw->{rows}->[$newRow]->{count} - 1;
	  $cw->{tabs}->{tags}->{$currTag}->{x} =
	    $cw->{rows}->[$newRow]->{width};
	  $cw->{rows}->[$newRow]->{width} += 
	    $cw->{tabs}->{tags}->{$currTag}->{width};

	  #print "($cw)              to row($newRow) and col($cw->{tabs}->{tags}->{$currTag}->{col})\n";

	  foreach my $i (($index+1)..$#{$cw->{tabs}->{order}}) {
	    last if ($cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$i]}->{row} != $oldRow);
	    #print "($cw) DeleteTab: moving tag($cw->{tabs}->{order}->[$i]) from col($cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$i]}->{col})\n";

	    $cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$i]}->{col}--;
	    if ($cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$i]}->{col} == 0) {
	      $cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$i]}->{x} = 0;
	    } else {
	      $cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$i]}->{x} =
		$cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$i-1]}->{x} +
		  $cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$i-1]}->{width};
	    }	
	    #print "($cw)            to col($cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$i]}->{col})\n";
	  }
	}
      }
    }
  }

  #---------------------------------------------------------------------------
  # Clear out the emtpy rows and adjust the canvas settings
  #---------------------------------------------------------------------------
  foreach my $j (reverse(0..$#{$cw->{rows}})) {
    splice(@{$cw->{rows}},$j,1) if ($cw->{rows}->[$j]->{count} == 0);
  }
  $cw->CharacterizeCanvas();

  #---------------------------------------------------------------------------
  # Remove this tag from the order
  #---------------------------------------------------------------------------
  $order = $cw->FindOrder($tag);
  splice(@{$cw->{tabs}->{order}},$order,1);
  if ($type ne "undocked") {
    #print "($cw) DeleteTab: ok now let's free that memory...\n";
    $cw->{tabs}->{tags}->{$tag}->{frame}->destroy();
    #print "($cw) DeleteTab: killed the GUI...\n";
    delete($cw->{tabs}->{tags}->{$tag});
    #print "($cw) DeleteTab: killed the data...\n";
    #print "($cw) DeleteTab: done freeing memory...\n";
  }

  #---------------------------------------------------------------------------
  # Redraw the tabs
  #---------------------------------------------------------------------------
  $cw->DrawTabs();
  #print "($cw) DeleteTab: finish\n";
}


###########################################################################
#
#
#
###########################################################################
sub RaiseTab {
  my ($cw,$tag,$raiseitanyway) = @_;

  return if ($tag eq "");

  #print "($cw) RaiseTab: tag($tag) raiseitanyway($raiseitanyway)\n";

  my $type = (exists($cw->{tabs}->{tags}->{$tag}->{type}) ?
	      $cw->{tabs}->{tags}->{$tag}->{type} :
	      $TYPES{fixed});

  if ($type eq $TYPES{undocked}) {
    if ($#{$cw->{tabs}->{order}} > -1) {
      $tag = $cw->{tabs}->{order}->[0];
    } else {
      $tag = "";
    }
  }

  return if ($tag eq "");

  $raiseitanyway = 0 if (!defined($raiseitanyway) || ($raiseitanyway eq ""));

  return if ($cw->Raised($tag) && ($raiseitanyway != 1));

  $cw->{canvas}->itemconfigure("tabs",-fill=>$cw->{vars}->{Tabs}->{DisabledBackground});
  $cw->{canvas}->itemconfigure("tab-$tag",-fill=>$cw->{vars}->{Tabs}->{Background});
  $cw->{canvas}->raise("line");
  $cw->{canvas}->raise($tag);

  #print "($cw) RaiseTab: before currentTab($cw->{vars}->{CurrentTab})\n";

  $cw->UnpackTab($cw->{vars}->{CurrentTab}) if !($cw->Raised(""));
  $cw->{vars}->{CurrentTab} = $tag;
  $cw->PackTab($tag);

  #print "($cw) RaiseTab: after currentTab($cw->{vars}->{CurrentTab})\n";

  $cw->UnhighlightTab($tag);

  if ($cw->{tabs}->{tags}->{$tag}->{row} != 0) {
    #print "($cw) RaiseTab: configure the positions...\n";

    foreach my $tempTag (keys(%{$cw->{tabs}->{tags}})) {
      #print "($cw) RaiseTab: resetting tag($tempTag) from row($cw->{tabs}->{tags}->{$tempTag}->{row}) to row($cw->{tabs}->{tags}->{$tempTag}->{realRow})\n";
      $cw->{tabs}->{tags}->{$tempTag}->{row} =
	$cw->{tabs}->{tags}->{$tempTag}->{realRow};
    }
    my $row = $cw->{tabs}->{tags}->{$tag}->{row};
    #print "($cw) RaiseTab: now raise the right row of tabs...\n";
    foreach my $tempTag (keys(%{$cw->{tabs}->{tags}})) {
      if ($cw->{tabs}->{tags}->{$tempTag}->{row} < $row) {
	#print "($cw) RaiseTab: moving tag($tempTag) from row($cw->{tabs}->{tags}->{$tempTag}->{row})\n";
	$cw->{tabs}->{tags}->{$tempTag}->{row} += 1;
	#print "($cw)           to row($cw->{tabs}->{tags}->{$tempTag}->{row})\n";
      } else {
	if ($cw->{tabs}->{tags}->{$tempTag}->{row} == $row) {
	  #print "($cw) RaiseTab: moving tag($tempTag) from row($cw->{tabs}->{tags}->{$tempTag}->{row}) to row(0)\n";
	  $cw->{tabs}->{tags}->{$tempTag}->{row} = 0;
	}
      }	
    }
    $cw->DrawTabs(0);
  }

}


sub Raised {
  my ($cw,$tag) = @_;
  return ($cw->{vars}->{CurrentTab} eq $tag);
}


sub ExistsTab {
  my ($cw,$tag) = @_;
  return exists($cw->{tabs}->{tags}->{$tag});
}




###########################################################################
#
#
#
###########################################################################
sub PackTab {
  my($cw,$tag) = @_;

  return if ($cw->{tabs}->{tags}->{$tag}->{hidden} == 1);

  $cw->{tabs}->{tags}->{$tag}->{frame}->
    pack(-side=>'bottom',
	 -padx=>0,
	 -pady=>0,
	 -ipadx=>$cw->{vars}->{Tabs}->{PadX},
	 -ipady=>$cw->{vars}->{Tabs}->{PadY},
	 -fill=>'both',
	 -expand=>1);
}


###########################################################################
#
#
#
###########################################################################
sub UnpackTab {
  my($cw,$tag) = @_;

  #print "($cw) UnpackTab: tag($tag)\n";

  $cw->{tabs}->{tags}->{$tag}->{frame}->packForget();
}


sub UnDockTab {
  my ($cw,$tag) = @_;

  #print "($cw) UnDockTab: tag($tag)\n";

  $cw->{tabs}->{tags}->{$tag}->{frame}->wmRelease();
  my $geom = $cw->geometry();
  $geom =~ s/[\+\-]\d+[\+\-]\d+//;
  $cw->{tabs}->{tags}->{$tag}->{frame}->geometry($geom);
  $cw->{tabs}->{tags}->{$tag}->{frame}->
    title($cw->{vars}->{UndockedTitlePrefix}." - ".$cw->{tabs}->{tags}->{$tag}->{text});
  $cw->{tabs}->{tags}->{$tag}->{frame}->deiconify();
  $cw->{tabs}->{tags}->{$tag}->{frame}->MapWindow();

  $cw->{tabs}->{tags}->{$tag}->{tabbar}->ShowCanvas();

  $cw->{tabs}->{tags}->{$tag}->{type} = $TYPES{undocked};

  $cw->DeleteTab($tag,"undocked");
}



sub DockTab {
  my ($cw,$tag) = @_;

  #print "($cw) DockTab: tag($tag)\n";

  $cw->{tabs}->{tags}->{$tag}->{frame}->wmCapture();
  $cw->{tabs}->{tags}->{$tag}->{tabbar}->HideCanvas();

  $cw->AddTab(-type=>"docking",
	      -tag=>$tag);
  $cw->RaiseTab($tag);
}



sub FirstShown {
  my ($cw) = @_;

  foreach my $index (0..$#{$cw->{tabs}->{order}}) {
    return $cw->{tabs}->{order}->[$index]
      if ($cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$index]}->{hidden} == 0);
  }
  return 0;
}

sub SecondShown {
  my ($cw) = @_;

  my $count = 0;
  foreach my $index (0..$#{$cw->{tabs}->{order}}) {
    $count++
      if ($cw->{tabs}->{tags}->{$cw->{tabs}->{order}->[$index]}->{hidden} == 0);
    return $cw->{tabs}->{order}->[$index] if ($count == 2);
  }
  return;
}


sub HideTab {
  my ($cw,$tag) = @_;

#  return if ($cw->{tabs}->{order}->[0] eq $tag);

  $cw->{tabs}->{tags}->{$tag}->{hidden} = 1;
  if ($cw->Raised($tag)) {
    $cw->RaiseTab($cw->FirstShown());
  }
  $cw->Refresh();
}


sub ShowTab {
  my ($cw,$tag) = @_;

  my $hidden = $cw->{tabs}->{tags}->{$tag}->{hidden};
  $cw->{tabs}->{tags}->{$tag}->{hidden} = 0;
  $cw->Refresh();
  $cw->RaiseTab($tag) if ($hidden == 1);
}




sub ShowCanvas {
  my ($cw) = @_;
  #print "($cw) ShowCanvas: showing\n";
  $cw->{canvas}->pack(-side=>'top',
		      -fill=>'both');
}


sub HideCanvas {
  my ($cw) = @_;
  #print "($cw) HideCanvas: hiding\n";
  $cw->{canvas}->packForget();
}



sub HighlightTab {
  my ($cw,$tag,$priority) = @_;

  #print "($cw) HighlightTab: tag($tag) priority($priority)\n";

  return if $cw->Raised($tag);

  #print "($cw) HighlightTab: tab is not raised... go ahead and highlight...\n";

  $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 $textFill = ($priority eq "low" ?
		  $cw->{vars}->{Tabs}->{Highlight}->{Low} :		   
		  (
		   $priority eq "medium" ?
		   $cw->{vars}->{Tabs}->{Highlight}->{Medium} :
		   $cw->{vars}->{Tabs}->{Highlight}->{High}
		  )
		 );

  my $highlight = (exists($cw->{tabs}->{tags}->{$tag}->{highlight}) ? 
		   $cw->{tabs}->{tags}->{$tag}->{highlight} : 
		   0
		  );

  if ($priorityValue > $highlight) {
    $cw->{canvas}->itemconfigure("text$tag",-fill=>$textFill);
    $cw->{tabs}->{tags}->{$tag}->{highlight} = $priorityValue;
  }
}


sub UnhighlightTab {
  my ($cw,$tag) = @_;

  $cw->{canvas}->itemconfigure("text$tag",-fill=>$cw->{vars}->{Tabs}->{Foreground});
  delete($cw->{tabs}->{tags}->{$tag}->{highlight});
}


sub FindOrder {
  my $cw = shift;
  my ($tag) = @_;
  foreach my $index (0..$#{$cw->{tabs}->{order}}) {
    return $index if ($cw->{tabs}->{order}->[$index] eq $tag);
  }
}


1;
