package Tk::SlideShow::Sprite;
use strict;
use vars qw(@ISA); @ISA = qw(Tk::SlideShow::Placeable);
sub New {
my ($class,$id) = @_;
my $s = $class->SUPER::New($id);
$s->{'link'}= [];
bless $s;
return $s;
}
sub null {
my ($class) = @_;
my $s = $class->SUPER::New('__null__');
bless $s;
return $s;
}
sub evalplace {
my $s = shift;
my $ret = "";
if (exists $s->{'multipos'}) {
$s->{'multipos'}[$s->{'curposindex'}] = [$s->x,$s->y];
$ret .= "multipos(". join(',',map {join(',',@$_)} @{$s->{'multipos'}}). ")";
} else {
$ret .= sprintf("place(%d,%d)",$s->x,$s->y);
}
$ret .= sprintf("->fontFamily('%s')",$s->fontFamily)
if exists $s->{'-font'} && $s->{'-font'};
$ret .= sprintf("->color('%s')",$s->color)
if exists $s->{'-color'} && $s->{'-color'};
return $ret;
}
sub place {
my ($s,$x,$y) = @_;
my ($dx,$dy) = ($x-$s->x,$y-$s->y);
Tk::SlideShow->canvas->move($s->id,$dx,$dy);
$s->{'x'} = $x;
$s->{'y'} = $y;
return $s;
}
sub multipos {
my ($s,@xy) = @_;
my $i = 0;
while(@xy) {$s->{'multipos'}[$i] = [splice(@xy,0,2)]; $i++}
$s->place(@{$s->{'multipos'}[0]});
}
sub chpos {
my ($s,$i,%options) = @_;
my $tag = $s->{'id'};
my $lasti;
$s->{'multipos'} = [] unless exists $s->{'multipos'};
my $can = Tk::SlideShow->canvas;
my ($H,$W) = (Tk::SlideShow->h,Tk::SlideShow->w);
if (exists $s->{'curposindex'}) {
$lasti = $s->{'curposindex'};
} else {
$lasti = 0;
}
#print "Saving pos $lasti for $tag\n";
my ($x,$y) = ($s->x,$s->y);
$s->{'multipos'}[$lasti] = [$x,$y];
#print "moving tag $tag to position $i\n";
$s->{'multipos'}[$i] = [$H/2,$W/2]
unless defined $s->{'multipos'}[$i];
my ($destx,$desty) = @{$s->{'multipos'}[$i]};
# number of pixel per second
my $speed = $options{'-speed'} || 1000;
my $distance = (($destx-$x)**2+($desty-$y)**2)**.5;
# printf ("deplacement de %d,%d a $destx,$desty\n",$x,$y);
my $steps = $options{'-steps'} || 5;
my $step = int($distance/$steps);
my $dt = $distance / $speed;
# print "dt=$dt distance=$distance step=$step\n";
my ($x0,$y0) = ($x,$y);
my $dx = ($destx-$x0)/$step;
my $dy = ($desty-$y0)/$step;
sub smallmove {
my ($can,$tag,$t,$step,$x0,$y0,$x,$y,$dx,$dy,$dt) = @_;
my $tx = $x0+$t*$dx;
my $ty = $y0+$t*$dy;
my ($tdx,$tdy) = (int($tx-$x),int($ty-$y));
$can->move($tag,$tdx,$tdy);
my $spri = Tk::SlideShow::Dict->Get($tag);
for my $l ($spri->links) {$l->show;}
$x += $tdx; $y += $tdy;
$can->update;
$can->after(int($dt/$step*1000),
[\&smallmove,$can,$tag,$t+1,$step,$x0,$y0,$x,$y,$dx,$dy,$dt])
if $t <= $step ;
}
smallmove($can,$tag,1,$step,$x0,$y0,$x,$y,$dx,$dy,$dt);
($s->{'x'},$s->{'y'}) = ($destx, $desty);
$s->{'curposindex'} = $i;
}
sub text {
shift;
my $id = shift;
my $text = shift;
my $s = New('Tk::SlideShow::Sprite',$id);
my $c = Tk::SlideShow->canvas;
my $item =
$c->createText
(Tk::SlideShow->w/2,Tk::SlideShow->h/ 2,'-text', $text,
-font, Tk::SlideShow->f1, -tags,$id);
$c->itemconfigure($item,@_);
$s->{-font} = ""; bindfontchoosermenu($id);
$s->{-color} = ""; bindcolorchoosermenu($id);
$s->pan(1);
$s->cursor('umbrella');
return $s;
}
# managing font for Sprites with text
{
my (%f,@f);
my $fontmenu; my $lbox;
my ($curit, $cursp);
sub initFontChooser {
Tk::SlideShow->addkeyhelp('Double-Click Button 1 on text items',
'to access font chooser');
my $can = Tk::SlideShow->canvas;
my $mw = Tk::SlideShow->mw;
open(FONT,"xlsfonts |") or die;
while(<FONT>) {next unless /^-/;
my @a = split /-/;
# avoiding non scalable fonts
next unless $a[9] == 0;
$f{$a[2]} = 1;}
close (FONT);
$fontmenu = $mw->Menu;
my $lb = $fontmenu->Scrolled('Listbox')->pack;
$lbox = $lb->Subwidget('listbox');
$lbox->bind('<Double-1>',
sub {
my $fontindex = $lbox->curselection;
if (defined $curit and defined $cursp) {
my $font = $can->itemcget($curit,-font);
$font->configure('-family',$f[$fontindex]);
$cursp->{-font} = $f[$fontindex];
}
#print "item = $curit\n";
$fontmenu->unpost;
$curit =$cursp = undef;
});
@f = sort keys %f;
$lb->insert('end',@f);
}
sub bindfontchoosermenu {
my $tagorid = shift;
my $c = Tk::SlideShow->canvas;
$c->bind($tagorid,'<Double-1>',
sub {
my $e = (shift)->XEvent;
$curit = Tk::SlideShow->current_item;
$cursp = Tk::SlideShow::Sprite->Get($curit)
if defined $curit;
$fontmenu->post($e->X,$e->Y);
}
);
}
sub fontFamily {
my ($s,$fam) = @_;
my $can = Tk::SlideShow->canvas;
return $s->{-font} unless defined $fam;
$s->{-font} = $fam;
my $font = $can->itemcget($s->{'id'},-font);
$font->configure('-family',$fam);
return $s;
}
}
# managing color for Sprites with color
{
my (%color,@color);
my $colormenu; my $lbox;
my ($curit, $cursp);
sub initColorChooser {
Tk::SlideShow->addkeyhelp('Double-Click Button 3 on canvas items',
'to access color chooser');
my $can = Tk::SlideShow->canvas;
my $mw = Tk::SlideShow->mw;
$colormenu = $mw->Menu;
@color = qw(red green blue yellow black purple magenta);
my $lb = $colormenu->Scrolled('Listbox')->pack;
$lbox = $lb->Subwidget('listbox');
$lb->insert('end',@color);
$lbox->bind('<Double-1>',
sub {
my $colorindex = $lbox->curselection;
if (defined $curit and defined $cursp) {
$can->itemconfigure($curit,-fill,$color[$colorindex]);
#print "on passe a la couleur=$colorindex :".$color[$colorindex]."\n";
$cursp->{-color} = $color[$colorindex] ;
}
#print "item = $curit\n";
$colormenu->unpost;
$curit =$cursp = undef;
});
}
sub bindcolorchoosermenu {
my $tagorid = shift;
my $c = Tk::SlideShow->canvas;
$c->bind($tagorid,'<Double-2>',
sub {
my $e = (shift)->XEvent;
$curit = Tk::SlideShow->current_item;
$cursp = Tk::SlideShow::Sprite->Get($curit)
if defined $curit;
$colormenu->post($e->X,$e->Y);
}
);
}
sub color {
my ($s,$col) = @_;
my $can = Tk::SlideShow->canvas;
return $s->{-color} unless defined $col;
$s->{-color} = $col;
$can->itemconfigure($s->{'id'},-fill,$col);
#print "on met $s->{'id'} en $col\n";
return $s;
}
}
sub point {
shift; my $id = shift;
my $s = Tk::SlideShow::Sprite->New($id);
my $c = Tk::SlideShow->canvas;
my $item =
$c->createOval(qw(0 0 5 5),-fill,'blue', -tags ,$id);
$s->pan(1);
return $s;
}
sub anim {
shift;
my $id = shift;
my $fn;
if (not -e $id) {
$fn = shift;
die "je ne trouve pas $fn\n" unless -e $fn;
} else { $fn = $id;}
my $s = Tk::SlideShow::Sprite->New($id);
$s->{'state'} = shift || 1;
my $freq = shift || 200;
my $c = Tk::SlideShow->canvas;
my $mw = Tk::SlideShow->mw;
my $im = $mw->Animation('-format' => 'gif',-file => $fn);
$im->start_animation($freq) if $s->{'state'};
Tk::SlideShow->addkeyhelp('Click Button 3 on animated gif',
'to toggle animation');
$c->bind($id,'<3>',
[ sub {
my ($c,$s,$im) = @_;
if ($s->{'state'}) {
#print "stopping ".$s->id."\n";
$im->stop_animation;
} else {
#print "starting ".$s->id."\n";
$im->start_animation($freq);
}
$s->{'state'} = 1 - $s->{'state'};
},$s,$im]);
$c->createImage(Tk::SlideShow->w/2,Tk::SlideShow->h/2,-image, $im, -tags,$id, @_);
$s->pan(1);
return $s;
}
sub image {
shift;
my $id = shift;
my $s = Tk::SlideShow::Sprite->New($id);
my $c = Tk::SlideShow->canvas;
my $mw = Tk::SlideShow->mw;
my $fn;
if (not -e $id) {
$fn = shift;
} else {
$fn = $id;
}
$mw->Photo($id,-file => $fn);
$c->createImage(Tk::SlideShow->w/2,Tk::SlideShow->h/2,-image, $id, -tags,$id, @_);
$s->pan(1);
return $s;
}
sub window {
shift;
my $id = shift;
my $s = Tk::SlideShow::Sprite->New($id);
my $c = Tk::SlideShow->canvas;
my $mw = Tk::SlideShow->mw;
my $window = shift;
$c->createWindow(Tk::SlideShow->w/2, Tk::SlideShow->h/2,
-window, $window, -tags,$id, @_);
#printf("%s %s window\n",Tk::SlideShow->w/2, Tk::SlideShow->h/2);
$s->pan(3);
return $s;
}
sub hommeord {
shift; # on supprime la classe
my $s = Tk::SlideShow::Sprite->New(@_);
my $c = Tk::SlideShow->canvas;
my $id = $s->id;
$c->createLine(qw(10 20 10 40 25 40 25 50),-width ,4,-fill, 'black', -tags ,$id); #chaise
$c->createLine(qw(15 15 15 35 30 35 30 50 35 50),-width ,4,-fill,'blue', -tags ,$id);# corps
$c->createOval(qw(11 11 18 18),-fill,'blue', -tags ,$id);# tete
$c->createLine(qw(15 25 30 25),-width ,4,-fill,'blue', -tags ,$id);# pieds
$c->createLine(qw(30 27 40 22),-width ,4,-fill,'red', -tags ,$id);# clavier
$c->createPolygon(qw(35 20 40 0 55 10 55 20),-width ,2,-fill,'red', -tags ,$id); # ecran
$c->createLine(qw(45 20 45 30 35 30 35 30),-width ,2, -fill,'red', -tags ,$id);# support d'ecran
$s->pan(1);
return $s;
}
sub moteur {
shift;
my $s = Tk::SlideShow::Sprite->New(@_);
my $c = Tk::SlideShow->canvas;
my $id = $s->id;
$c->createOval(qw(0 0 50 50),-fill,'blue', -tags ,$id);
$c->createText(qw(0 0),'-text',$id,-anchor,'e',-tags ,$id);
my @ids;
my @colors = qw(red blue);
push @ids, $c->createLine(qw(10 10 40 40),-width ,10,-fill, 'red', -tags ,$id);
push @ids, $c->createLine(qw(25 0 25 50),-width ,10,-fill, 'blue', -tags ,$id);
push @ids, $c->createLine(qw(10 40 40 10),-width ,10,-fill, 'blue', -tags ,$id);
push @ids, $c->createLine(qw(0 25 50 25),-width ,10,-fill, 'blue', -tags ,$id);
$c->raise($ids[0]);
$s->{'ids'} = [@ids];
$s->{'toggle'} = 1;
sub toggle {
my $s = shift;
my $c = Tk::SlideShow->canvas;
$s->{'r'}->cancel if exists $s->{'r'};
$c->itemconfigure ($s->{'ids'}[$s->{'toggle'}],-fill, 'blue');
$s->{'toggle'}++; $s->{'toggle'} %= @{$s->{'ids'}};
$c->itemconfigure ($s->{'ids'}[$s->{'toggle'}],-fill, 'red');
$c->raise($s->{'ids'}[$s->{'toggle'}]);
$s->{'r'} = $c->after(100,[\&toggle,$s]);
}
$c->bind($id,'<3>',
sub {
if (exists $s->{'r'}) {
$s->{'r'}->cancel;
delete $s->{'r'}
} else {
&toggle($s)
}
});
toggle($s);
$s->pan(1);
return $s;
}
sub framed {
shift;
my ($id,$text) = @_;
my $s = Tk::SlideShow::Sprite->New($id);
my $c = Tk::SlideShow->canvas;
my $t = $text || $id;
my $idw = $c->createText(0,0,'-text',$t,
-justify, 'center',
-font => Tk::SlideShow->f1, -tags => $id);
$c->createRectangle($c->bbox($idw), -fill,'light blue',-tags => $id);
$c->raise($idw);
$s->pan(1);
return $s;
}
sub compuman {
my ($p,$id) = @_;
my $s = Tk::SlideShow::Sprite->New($id);
my $can = $p->canvas;
my @o1 = (-width ,4,-fill, 'black', -tags ,$id);
my @o2 = (-fill,'blue', -tags ,$id);
my @o3 = (-width ,4,-fill,'red', -tags ,$id);
$can->createLine(qw(10 20 10 40 25 40 25 50),@o1); #chair
$can->createLine(qw(15 15 15 35 30 35 30 50 35 50),@o1); # body
$can->createOval(qw(11 11 18 18),@o2); # head
$can->createLine(qw(15 25 30 25),@o1); # feet
$can->createLine(qw(30 27 40 22),@o3); # keyborad
$can->createPolygon(qw(35 20 40 0 55 10 55 20),@o3); # ecran
$can->createLine(qw(45 20 45 30 35 30 35 30),@o3); #
($s->{'x'},$s->{'y'}) = (0,0);
$s->pan(1);
return $s;
}
sub tickertape {
my ($p,$id,$text,$len,%options) = @_;
my $spri = $p->newSprite($id)->pan(1);
my ($mw,$can,$H,$W) = ($p->mw,$p->canvas,$p->h,$p->w);
my $delay = 50;
my $chunk = 5;
# extracting my own options
if (exists $options{'-delay'}) {
$delay = $options{'-delay'}; delete $options{'-delay'};}
if (exists $options{'-chunk'}) {
$chunk = $options{'-chunk'}; delete $options{'-chunk'};}
my $idw = $can->createText(0,0,
'-text',substr($text,0,$len),
-tags => $id,
%options
);
my @bbox = $can->bbox($id);
my $larg = $bbox[2]-$bbox[0];
my $haut = $bbox[3]-$bbox[1];
my $bg = $can->cget(-background);
my $scan = $mw->Canvas(-height,$haut,-width,$larg,-background,$bg);
$can->createWindow($W/2,$H/2,'-anchor','nw','-window',$scan,'-tags',$id);
$can->delete($idw);
my @def = (-anchor, 'nw','-text',$text,'-tags' => $id, %options);
$idw = $scan->createText(0,0,@def);
@bbox = $scan->bbox($idw);
my $txtwidth = $bbox[2];
$scan->createText($txtwidth,0, @def);
$can->createRectangle($can->bbox($id),-width,20,-outline,$bg,-tags,$id);
sub tourne {
my ($spri,$can,$scan,$txtwidth,$delay,$chunk) = @_;
my $tag = $spri->id;
$scan->move($tag, (0 - $chunk) ,0);
$scan->move($tag, $txtwidth,0) if ($scan->bbox($tag))[2] < $scan->Width;
$can->after($delay,
[\&tourne,$spri,$can,$scan,$txtwidth,$delay,$chunk]);
}
tourne($spri,$can,$scan,$txtwidth,$delay,$chunk);
return $spri;
}
1;