# -*-Perl-*-
use Tk;
require "$libdir/xpm";

# single bar graph pseudo-widget, built out of Tk canvases.

package MGM::Bar;
use vars qw($font);

$font=MGM::Font::new(MGM::Xpm::read($main::fontfile));

sub drawborder{
    my($w,$width,$height,$relief,$dim,$lit)=@_;
    $z=0;
    
    if($relief eq 'sunken' ||
       $relief eq 'groove'){
	$w->createLine($width-1,0, 0,0, 0,$height-1, -capstyle=>'projecting',
		       -fill=>$dim);
	$w->createLine($width-1,0, $width-1,$height-1, 0,$height-1, 
		       -capstyle=>'projecting',-fill=>$lit);

	if($relief eq 'groove'){
	    $z=1;
	    $width-=1;
	    $height-=1;
	    $relief='raised';
	}
    }
    if($relief eq 'raised'){
	$w->createLine($width-1,$z, $width-1,$height-1, $z,$height-1, 
		       -capstyle=>'projecting',-fill=>$dim);
	$w->createLine($width-1,$z, $z,$z, $z,$height-1, 
		       -capstyle=>'projecting',-fill=>$lit);
    }
}

sub place{
    my$this=shift;
    $this->{"below"}->place(@_);
    $this;
}

sub new{
    my ($ref,$p,$width,$height,$num)=@_;
    
    $orient=$main::orient;

    # we're not as flat as we like to think 
    my$this=bless {};
    
    my$below=$this->{"below"}=$p->Canvas(Name=>$num);

    my$above=$this->{"above"}=$below->Canvas()->place(-relx=>0,-rely=>0,
						      -anchor=>'nw', 
						      -bordermode=>'outside');
    
    # we configure the color and label via a configurable X resource;
    # it's cleaner than setting up a system that alters a single X resource

    $this->{"aforeXr"}='litforeground';
    $this->{"abackXr"}='litbackground';
    $this->{"labelXr"}='label';

    $this->{"width"}=$width;
    $this->{"height"}=$height;
    $this->{"num"}=$num;
    $this->{"value"}=0;

    $this->drawit;
    $this;
}

sub configure{
    my$this=shift;
    my ($arg,$val);
    while(defined($arg=shift)){
	$val=shift;   

        if(!defined($val)){last;}
	$this->{"$arg"}=$val;
    }

    $this->{'below'}->delete('xpmlabel');
    $this->{'above'}->delete('xpmlabel');
    
    $this->drawit;
    $this->set($this->{'value'});
}

sub drawit{
    my$this=shift;
    my$below=$this->{'below'};
    my$above=$this->{'above'};

    $orient=$main::orient;

    my$width=$this->{"width"};
    my$height=$this->{"height"};
    my$num=$this->{"num"};

    my $pad=$below->optionGet("textpad","");
    my $relief=$below->optionGet('dimrelief','');
    my $arelief=$below->optionGet('litrelief','');

    my $afore=$below->optionGet($this->{"aforeXr"},'');
    my $aback=$below->optionGet($this->{"abackXr"},'');
    my $label=$below->optionGet($this->{"labelXr"},'');

    my $fore=$below->optionGet('dimforeground','');
    my $back=$below->optionGet('dimbackground','');
    my $ratio=$below->optionGet('ratio','');
    
    my$border=0;
#    $border=2 if ($relief eq 'groove');
#    $border=1 if ($relief eq 'sunken');
#    $border=1 if ($relief eq 'raised');

    my$aborder=0;
    $aborder=2 if ($arelief eq 'groove');
    $aborder=1 if ($arelief eq 'sunken');
    $aborder=1 if ($arelief eq 'raised');
    
    my($r,$g,$b)=$below->rgb($back);
    $r/=256;
    $g/=256;
    $b/=256;
    my$lum=$r*.3+$g*.5+$b*.2;
    my$dimdim=sprintf "#%02x%02x%02x", $r*.5,$g*.5,$b*.5;
    my$dimlit=sprintf "#%02x%02x%02x", 
          &main::min($r+$lum*.7,255),&main::min($g+$lum*.7,255),
          &main::min($b+$lum*.7,255);

    if($orient eq 'vertical'){
	my$text=$font->maketext($label,$width-($pad*2),$height-($pad*2),
			      $ratio,1,1);
	
	my$unlittext=$below->Pixmap($below->PathName.".unlittext",
				    -data=>$text->write($fore,$back,32));
	my$littext=$below->Pixmap($below->PathName.".littext",
				  -data=>$text->write($afore,$aback,32));

	$this->{"barlength"}=$height;
	$this->{"litrelief"}=$arelief;
	$this->{"cfborder"}=$aborder;

	$below->configure(-borderwidth=>$aborder,
			  -background=>$aback,
			  -highlightthickness=>0,
			  -width=>($width-$aborder*2),
			  -height=>($height-$aborder*2),
			  -relief=>$arelief);
	
	$above->configure(-borderwidth=>0,
			  -background=>$back,
			  -highlightthickness=>0,
			  -width=>$width,
			  -height=>$height,
			  -relief=>'flat');
	
	$this->{"reliefhack"}->destroy if(defined($this->{"reliefhack"}));
	if($aborder){
	    $this->{"reliefhack"}=$above->
		Label(-borderwidth=>$aborder,
		      -background=>$aback,
		      -highlightthickness=>0,
		      -width=>($width-$aborder*2),
		      -height=>4,
		      -relief=>$arelief)->
			  place('-x'=>0,-rely=>1.0,'-y'=>-$aborder,
				-anchor=>'nw',-bordermode=>'outside');
	}
    


	$below->createImage($pad,$height-$pad,-image=>$littext,-anchor=>'sw',
			    -tags=>['xpmlabel']);
	$above->createImage($pad,$height-$pad,-image=>$unlittext,
			    -anchor=>'sw',-tags=>['xpmlabel']);
	&drawborder($above,$width,$height,$relief,$dimdim,$dimlit);
	
    }else{
	my$text=$font->maketext($label,$height-($pad*2),$width-($pad*2),
			      $ratio,0,1);
	my$unlittext=$below->Pixmap($below->PathName.".unlittext",
				    -data=>$text->write($fore,$back,32));
	my$littext=$below->Pixmap($below->PathName.".littext",
				  -data=>$text->write($afore,$aback,32));

	$this->{"barlength"}=$width;
	$this->{"cfborder"}=$aborder;
	$below->configure(-borderwidth=>0,
			  -background=>$back,
			  -highlightthickness=>0,
			  -width=>$width,
			  -height=>$height-$border*2,
			  -relief=>'flat');
	
	$above->configure(-borderwidth=>$aborder,
			  -background=>$aback,
			  -highlightthickness=>0,
			  -width=>($width-2*$aborder),
			  -height=>($height-2*$aborder),
			  -relief=>$arelief);
	
	$above->createImage($pad,$height-$pad,-image=>$littext,-anchor=>'sw',
			    -tags=>['xpmlabel']);
	$below->createImage($pad,$height-$pad,-image=>$unlittext,
			    -anchor=>'sw',-tags=>['xpmlabel']);
	&drawborder($below,$width,$height,$relief,$dimdim,$dimlit);
	
    }

    $this;
}

sub set{
    my$bar=shift;
    my$per=shift;

    $bar->{'value'}=$per;
    my $orient=$main::orient;
    if($orient eq 'vertical'){
	$bar->{'above'}->
	    configure('-height'=>($bar->{"barlength"}-
				  $per+$bar->{"cfborder"}));
    }else{
	my $border=$bar->{"cfborder"};
	$bar->{'above'}->
	    configure('-width'=>($per-2*$bar->{"cfborder"}));
    }
}

package MGM::Graph;
use vars qw(%numbers %prompts);

# all the labels are the same size/color, but we have to do this after the toplevel is created so we have the size/color resources

sub cacheem{
    my$size=$main::toplevel->optionGet("labelsize","");
    my$fg=$main::foreground;
    my$bg=$main::background;
    my$orient=$main::orient;
    while(defined(my$num=shift)){
	if(!defined($numbers{"$num"})){
	    $numbers{"$num"}=$main::toplevel->
		Pixmap(-data=>$MGM::Bar::font->
		       maketext("$num",$size,undef,1,
				$orient eq 'vertical'?1:undef)->
		       write($fg,$bg,32,32));
	}
    }
}

sub cacheinit{
    if(!defined($numbers)){
	&cacheem("0","1","2","4","8","16","32","64","128","256","512");
    }
}

sub cacheprompt{
    my$prompt=shift;
    
    if(!defined($prompts{"$prompt"})){
	my$size=$main::toplevel->optionGet("labelsize","");
	my$fg=$main::foreground;
	my$bg=$main::background;
	my$orient=$main::orient;
	
	$prompts{"$prompt"}=$main::toplevel->Pixmap(-data=>
	    $MGM::Bar::font->maketext("$prompt",$size,undef,1,
				      $orient eq 'vertical'?1:undef)->
					  write($fg,$bg,32,32));
	$prompts{"k$prompt"}=$main::toplevel->Pixmap(-data=>
	    $MGM::Bar::font->maketext("k$prompt",$size,undef,1,
				      $orient eq 'vertical'?1:undef)->
					  write($fg,$bg,32,32));
	$prompts{"M$prompt"}=$main::toplevel->Pixmap(-data=>
	    $MGM::Bar::font->maketext("M$prompt",$size,undef,1,
				      $orient eq 'vertical'?1:undef)->
					  write($fg,$bg,32,32));
	$prompts{"G$prompt"}=$main::toplevel->Pixmap(-data=>
	    $MGM::Bar::font->maketext("G$prompt",$size,undef,1,
				      $orient eq 'vertical'?1:undef)->
					  write($fg,$bg,32,32));
    }
}

sub promptsize{
    my($prompt,$setting)=@_;

    if($main::orient eq 'vertical'){
	($numbers{"$setting"}->width,
	 $numbers{"$setting"}->height+$prompts{"$prompt"}->height);
    }else{
	($numbers{"$setting"}->height,
	 $numbers{"$setting"}->width+$prompts{"$prompt"}->width);
    }
}

sub scalemod{
    my$scaleset=shift;
    my$multiplier='';
    
    if($scaleset>512){
	$scaleset/=1024;
	$multiplier="k";
	if($scaleset>512){
	    $scaleset/=1024;
	    $multiplier="M";
	    if($scaleset>512){
		$scaleset/=1024;
		$multiplier="G";
	    }
	}
    }
    $scaleset=int($scaleset+.5);
    ($scaleset,$multiplier);
}

sub promptlabel{
    my($p,$scaleset,$prompt)=@_;
    my $orient=$main::orient;
    my $mult;

    if($p->{'scalep'}){
	($scaleset,$mult)=&scalemod($scaleset);
	my$label;
	
	my($textw,$textl)=&promptsize("$mult$prompt",$scaleset);
	
	if($orient eq 'vertical'){
	    $label=$p->{"widget"}->Canvas(Name=>'scalerange',
					  -borderwidth=>0,
					  -highlightthickness=>0,
					  -width=>$textw,
					  -height=>$textl,
					  -relief=>'flat')->
					      place('-x'=>0,'-y'=>2,-anchor=>'nw');
	    $label->createImage(0,0,
				-image=>$prompts{"$mult$prompt"},-anchor=>'nw');
	    $label->createImage(0,$prompts{"$mult$prompt"}->height,
				-image=>$numbers{"$scaleset"},-anchor=>'nw');
	}else{
	    $label=$p->{"widget"}->Canvas(Name=>'scalerange',
					  -borderwidth=>0,
					  -highlightthickness=>0,
					  -width=>$textl,
					  -height=>$textw,
					  -relief=>'flat')->
					      place(-relx=>1.0,
						    '-x'=>-2,'-y'=>0,
						    -anchor=>'ne');
	    $label->createImage($numbers{"$scaleset"}->width,0,
				-image=>$prompts{"$mult$prompt"},-anchor=>'nw');
	    $label->createImage(0,0,
				-image=>$numbers{"$scaleset"},-anchor=>'nw');
	}
	$label;
    }
}

sub new{
    my$class=shift;
    my$p=shift;
    my$toplevel=$p->{"toplevel"};

    my$ret=bless {( 'width'=> $p->{"width"},
		  'height'=> $p->{"height"},
		  'name' => $p->{"name"},
		  'rangesetting'=>1,
		  'rangecurrent'=>1,
		  'minscale'=>1,
		  'num' => '1',
		  'fixed' => '0')};
    $ret->{"scaletimer"}=0;
    $ret->{"scalemax"}=0;

    $ret->_configure(@_);

    my$widget=$ret->{"widget"}=
	$toplevel->Canvas(-class=>$ret->{"name"},
				 Name=>$p->{"sequence"});

    $ret->{"scalep"}=($widget->optionGet("scale","") eq 'true');
    $ret->{"scroll"}=($widget->optionGet("scalescroll","") eq 'true');
    $ret->{"scalereturn"}=$widget->optionGet("scalereturn","");
    $ret->{"scalethresh"}=$widget->optionGet("scalethresh","");
    $ret->drawit;
    $ret->{"meter"}=[(map{-1}(1..$ret->{"num"}))];
    $ret;
}

sub calcsize{
    my($this,$scaleset,$prompt,$num)=@_;
    
    my$barw=4*$num;
    my$barl=10;
    my$scalew=0;
    my$textl=0;
    my$textw=0;

    if (&main::moption($this,"scale") eq 'true'){
	my($set,$mult)=&scalemod($scaleset);
	&cacheinit();
	&cacheprompt($prompt);
	&cacheem($set);

	($textw,$textl)=&promptsize("$mult$prompt",$set);
	$textw+=3;
	$textl+=4;
	$scalew=6;
    }

    $scalew=&main::max($scalew,$textw);
    $barl=&main::max($barl,$textl);

    ($barw+$scalew,$barl,$scalew);
}

sub calcxysize{
    my($w,$l)=&calcsize(@_);

    if($main::orient eq 'vertical'){
	($w,$l);
    }else{
	($l,$w);
    }
}
    
sub drawit{
    my$this=shift;
    
    # a 'graph' consists of a scale, and <n> bars under central control

    my $num=$this->{"num"};
    if($num){

	my $name=$this->{"name"};
	my $prompt=$this->{"prompt"};
	my $fixed=$this->{"fixed"};
	
	my $height=$this->{"height"};
	my $width=$this->{"width"};
	my $widget=$this->{"widget"};

	$widget->configure(-borderwidth=>0,
			   -highlightthickness=>0,
			   -width=>$width,
			   -height=>$height,
			   -relief=>'flat');
	
	my $rangesetting=$this->{"rangesetting"};
	my($dummy,$dummy2,$scalew)=&calcsize($this,$rangesetting,$prompt,$num);
	$this->{"scalew"}=$scalew;
	$this->{"numlabel"}=$this->promptlabel($rangesetting,$prompt);
	
	my $orient=$main::orient;
	if($orient eq 'vertical'){
	    $this->drawvscale if($scalew);
	    
	    $this->{"barlength"}=$height;
	    my$barwidth=$width-$scalew;
	    my$frame=$this->{"barframe"}=
		$widget->Frame(Name=>'bar',
			       -width=>$barwidth,
			       -height=>$height,
			       -borderwidth=>0)->
				   place('-x'=>$scalew,
					 '-y'=>0,
					 '-anchor'=>'nw');
	    
	    $barwidth/=$num;
	    $barwidth=int($barwidth);
	    my$x=0;
	    for(my$i=0;$i<$num;$i++){
		$this->{$i}=MGM::Bar->new($frame,$barwidth-1,
					  $height,
					  $i)->place('-x'=>$x,'-y'=>0,
						     '-anchor'=>'nw');
		$x+=$barwidth;
	    }
	}else{
	    $this->drawhscale if($scalew);
	    
	    $this->{"barlength"}=$width;
	    my$barwidth=$height-$scalew;
	    my$frame=$this->{"barframe"}=
		$widget->Frame(Name=>'bar',
			       -width=>$width,
			       -height=>$barwidth,
			       -borderwidth=>0)->
				   place('-y'=>$scalew,
					 '-x'=>0,
					 -anchor=>'nw');
	    
	    $barwidth/=$num;
	    $barwidth=int($barwidth);
	    my$y=0;
	    for(my$i=0;$i<$num;$i++){
		$this->{$i}=MGM::Bar->new($frame,$width,
					  $barwidth-1,
					  $i)->place('-x'=>0,'-y'=>$y,
						     -anchor=>'nw');
		$y+=$barwidth;
	    }
	}
    }
}

sub place{
    my$this=shift;
    $this->{"widget"}->place(@_);
    $this;
}

sub _configure{
    my$this=shift;
    my ($arg,$val);
    while(defined($arg=shift)){
	$val=shift;   

        if(!defined($val)){last;}
	$this->{"$arg"}=$val;
    }

    # enforce power of two dynamic ranging
    $this->{"rangesetting"}=$this->{"minscale"} if($this->{"minscale"}>
						   $this->{"rangesetting"});
    $this->{"rangecurrent"}=$this->{"minscale"} if($this->{"minscale"}>
						   $this->{"rangecurrent"});
    if($this->{"fixed"}==0){
	my$i=1;
	while($i<$this->{"rangesetting"}){
	    $i*=2;
	}
	$this->{"rangesetting"}=$i;
    }
    $this->{"rangediff"}=$this->{"rangesetting"}-
	$this->{"rangecurrent"};
}

# we can't configure anything that requires size changes.
sub configure{
    my$this=shift;
    my%copy=%$this;
    
    $this->_configure(@_);

    if($copy{"rangesetting"} != $this->{"rangesetting"}){
	my$val=int($this->{'rangesetting'});
	
	$this->{"numlabel"}->destroy;
	$this->{"numlabel"}=$this->promptlabel($val,$this->{'prompt'});
	$this->{"rangediff"}=$this->{"rangesetting"}-
	    $this->{"rangecurrent"};
	$this->{"scaletimer"}=0; # reset the timer
	$this->{"scalemax"}=0;
	$this->_animate();
    }
}

# a way to configure individual bars
sub barconfigure{
    my$this=shift;
    my$bar=shift;
    $bar=$this->{$bar};
    $bar->configure(@_);
}

sub drawvscale{
    my$this=shift;

    # length is in barlength
    # current scale setting in rangecurrent
    # scale 'goal' in rangesetting (may smooth-scroll)
    # current max meter setting in metermax
    # (other meter settings in meter0, meter1, meter2....)

    # build new scale 
    my$widget=$this->{"widget"};
    my$color=$widget->optionGet("scalecolor","");
    my$height=$this->{"height"};
    my$width=4;
    my$xo=$this->{"scalew"}-2;

    $widget->createLine($xo,0,$xo,$height-1,$xo-$width,$height-1,
			-tags=>['newscale'],-fill=>$color,
			-capstyle=>'projecting');

    # powers of two. tics no closer than every 4 pixels

    my$max=0.;
    if($this->{"rangesetting"}){
	$max=$height/$this->{"rangecurrent"}*$this->{"rangesetting"};
    }else{
	if($this->{"rangecurrent"}){
	    $max=$height/$this->{"rangecurrent"};
	}
    }
    if($this->{"rangecurrent"}==$this->{"rangesetting"}){
	$widget->createLine($xo,0,$xo-$width,0,
			    -tags=>['newscale'],-fill=>$color,
			    -capstyle=>'projecting');
    }

    my$step=1;
    for(my$div=2;;$div*=2){
	my$flag=0;
	last if($width<1);
	last if($max/$div<4);
	for(my$tic=1;;$tic+=$step){
	    my$y=$height-$max/$div*$tic;
	    if($y>=0){
		$widget->createLine($xo,$y,$xo-$width,$y,
				    -tags=>['newscale'],-fill=>$color,
				    -capstyle=>'projecting');
		$flag=1;
	    }else{
		last;
	    }
	}
	$width-- if ($flag);
	$step=2;
    }
    
    # replace old scale with new scale 
    
    $widget->delete('scale');
    $widget->addtag('scale',withtag=>'newscale');
}

sub drawhscale{
    my$this=shift;

    # length is in barlength
    # current scale setting in rangecurrent
    # scale 'goal' in rangesetting (may smooth-scroll)
    # current max meter setting in metermax
    # (other meter settings in meter0, meter1, meter2....)

    # build new scale 
    my$widget=$this->{"widget"};
    my$color=$widget->optionGet("scalecolor","Scalecolor");
    my$yo=$this->{"scalew"}-2;
    my$width=$this->{"width"};
    my$height=4;

    $widget->createLine(0,$yo-$height,0,$yo,$width-1,$yo,
			-tags=>['newscale'],-fill=>$color,
			-capstyle=>'projecting');
    
    # powers of two. tics no closer than every 4 pixels
    my$max=0.;
    if($this->{"rangesetting"}){
	$max=$width/$this->{"rangecurrent"}*$this->{"rangesetting"};
    }else{
	if($this->{"rangecurrent"}){
	    $max=$width/$this->{"rangecurrent"};
	}
    }
    if($this->{"rangecurrent"}==$this->{"rangesetting"}){
	$widget->createLine($width-1,$yo-$height,$width-1,$yo,
			    -tags=>['newscale'],-fill=>$color,
			    -capstyle=>'projecting');
    }
  
    my$step=1;
    for(my$div=2;;$div*=2){
	my$flag=0;
	last if($max/$div<4);
	last if($height<1);
	for(my$tic=1;;$tic+=$step){
	    my$x=$max/$div*$tic;
	    if($x<$width){
		$widget->createLine($x,$yo-$height,$x,$yo,
				    -tags=>['newscale'],-fill=>$color,
				    -capstyle=>'projecting');
		$flag=1;
	    }else{
		last;
	    }
	}
	$height-- if ($flag);
	$step=2;
    }

    # replace old scale with new scale 
    
    $widget->delete('scale');
    $widget->addtag('scale',withtag=>'newscale');
}

sub _newscale{
    my$this=shift;
    my$val=$this->{'rangesetting'};

    $this->{"numlabel"}->destroy;
    $this->{"numlabel"}=$this->promptlabel($val,$this->{'prompt'});
    $this->{"rangediff"}=$this->{"rangesetting"}-$this->{"rangecurrent"};
    $this->_animate();
}

sub _animate{
    my $this=shift;

    $scalep=$this->{"scalep"};
    $scrollp=$this->{"scroll"};
    
    if(!$scalep || !$scrollp){
	$this->{"rangecurrent"}=$this->{"rangesetting"};
	undef $this->{"anitimer"};
    }else{
	if($this->{"rangesetting"}==0){
	    if($this->{"rangecurrent"}<.02){
		$this->{"rangecurrent"}=$this->{"rangesetting"};
		undef $this->{"anitimer"};
	    }else{
		$this->{"rangecurrent"}+=$this->{"rangediff"}*.1;
		$this->{"anitimer"}->cancel if(defined($this->{"anitimer"}));
		$this->{"anitimer"}=$this->{"widget"}->after(30,sub{$this->set;});
	    }
	}else{
	    if(abs($this->{"rangecurrent"}/($this->{"rangesetting"})-1)<.02){
		$this->{"rangecurrent"}=$this->{"rangesetting"};
		undef $this->{"anitimer"};
	    }else{
		$this->{"rangecurrent"}+=$this->{"rangediff"}*.1;
		$this->{"anitimer"}->cancel if(defined($this->{"anitimer"}));
		$this->{"anitimer"}=$this->{"widget"}->after(30,sub{$this->set;});
	    }
	}
    }

    if($main::orient eq 'vertical'){
	$this->drawvscale;
    }else{
	$this->drawhscale;
    }
    my$length=$this->{"barlength"};
    my$num=$this->{"num"};
    if($this->{"rangecurrent"}){
	for(my$i=0;$i<$num;$i++){
	    $this->{$i}->
		set($this->{"meter"}->[$i]*$length/$this->{"rangecurrent"});
	}
    }else{
	for(my$i=0;$i<$num;$i++){
	    $this->{$i}->
		set(0);
	}
    }
}

sub set{
    my$this=shift;
    my$num=$this->{"num"};

    if($num){
	my$length=$this->{"barlength"};
	
	# length is in barlength
	# current scale setting in rangecurrent
	# scale 'goal' in rangesetting (may smooth-scroll)
	
	if($#_>=0){
	    # we have new values incoming.  We need to do full maneuvers
	    
	    if($#_!=$num-1){
		# might as well.  prevents spurious error printing when 
		# something unexpected happens to a module (like a CPU
		# disappearing ;-)
		
		push @_,$#_+1,map{0}(1..$num); #lazy
		$#_=$num-1;
	    }
	    
	    # find the largest value for scale adjustment
	    my$metermax=0;
	    map{$metermax=$_ if ($metermax<$_)}(@_, @{$this->{"meter"}},
						$this->{"scalemax"});
	    $this->{"scalemax"}=$metermax;
	    my$fixed=$this->{"fixed"};
	    
	    # raise the scale range?
	    my$redrawflag=0;
	    if($fixed==0 && $metermax>$this->{"rangesetting"}){
		splice @{$this->{"meter"}},0,$#_+1,@_;
		while($metermax>$this->{"rangesetting"}){
		    if($this->{"rangesetting"} == 0){
			$this->{"rangesetting"}=1;
		    }else{
			$this->{"rangesetting"}*=2;
		    }
		    $this->{"scaletimer"}=0; # reset the timer
		    $this->{"scalemax"}=$metermax;
		    $this->_newscale();
		}
	    }else{
		# lower the scale range?
		my$scaletimer=$this->{"scaletimer"}+1;
		if($fixed==0 && $scaletimer>=$this->{"scalereturn"} &&
		   $this->{"rangesetting"}>$this->{"minscale"} && 
		   $metermax*$this->{"scalethresh"}<$this->{"rangesetting"} &&
		   $this->{"rangesetting"}==$this->{"rangecurrent"}){
		    
		    $this->{"rangesetting"}=int($this->{"rangesetting"}/2);
		    $this->{"scaletimer"}=0;
		    $this->{"scalemax"}=0;
		    splice @{$this->{"meter"}},0,$#_+1,@_;
		    $this->_newscale();
		    
		}else{
		    my$meter=$this->{"meter"};
		    for(my$i=0;defined(my$val=shift);$i++){
			if($meter->[$i]!=$val){
			    $meter->[$i]=$val;
			    $val*=$length/$this->{"rangecurrent"};
			    $this->{$i}->set($val);
			}
		    }
		    
		    if($scaletimer>=$this->{"scalereturn"}){
			$this->{"scaletimer"}=0;
			$this->{"scalemax"}=0;
		    }else{
			$this->{"scaletimer"}=$scaletimer;
			$this->{"scalemax"}=$metermax;
		    }
		}
	    }
	    
	}else{
	    # just scale animation.  No reconfig
	    $this->_animate();
	}
    }
}

1;


