From a5226e6d70495710f122f517db617e5a2f0f3b51 Mon Sep 17 00:00:00 2001 From: mertz Date: Tue, 24 Jun 2003 08:47:19 +0000 Subject: Ajout de la librairie Zinc::Graphics de JLV et d'une demonstration faite par JLV --- Perl/Zinc/Graphics.pm | 1317 ++++++++++++++++++++ Perl/demos/Tk/demos/zinc_data/paper.gif | Bin 0 -> 1529 bytes Perl/demos/Tk/demos/zinc_lib/testGraphics.pl | 1707 ++++++++++++++++++++++++++ Perl/demos/zinc-demos | 7 +- 4 files changed, 3029 insertions(+), 2 deletions(-) create mode 100644 Perl/Zinc/Graphics.pm create mode 100644 Perl/demos/Tk/demos/zinc_data/paper.gif create mode 100644 Perl/demos/Tk/demos/zinc_lib/testGraphics.pl diff --git a/Perl/Zinc/Graphics.pm b/Perl/Zinc/Graphics.pm new file mode 100644 index 0000000..bd312c8 --- /dev/null +++ b/Perl/Zinc/Graphics.pm @@ -0,0 +1,1317 @@ +#!/usr/bin/perl +#----------------------------------------------------------------------------------- +# +# Graphics.pm +# module de fonctions graphiques +# +#----------------------------------------------------------------------------------- +# Gestion de ressources globales : gradiants zinc (couleurs et dégradés nommés) +# patterns (fichiers bitmap X11) +# textures (fichiers texture) +# images (fichiers GIF, JPEG, PNG) +#----------------------------------------------------------------------------------- +# Fonctions Zinc : buildZincItem (réalisation d'un item zinc à partir d'une table de description) +# +# Fonctions géométriques : roundedRectangleCoords +# HippoCoords +# polygonCoords +# roundedCurveCoords +# polylineCoords +# tabBoxCoords +# roundedAngle +# roundedCurve +# perpendicularPoint +# lineAngle +# vertexAngle +# arc_pts +# rad_point +# +# Fonctions picturales : setGradiants +# getPattern +# getTexture +# getImage +# init_pixmaps +#----------------------------------------------------------------------------------- +# Authors: Jean-Luc Vinot +# +# $Id: +#----------------------------------------------------------------------------------- +package Graphics; + +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(&buildZincItem &setGradiants &getTexture &getPattern &getImage &roundedAngle &roundedCurveCoords + &polylineCoords &polygonCoords &TabBoxCoords &pathLineCoords &rad_point &arc_pts); + +use strict; +use Carp; +use Tk; +use Math::Trig; + +# constante facteur point directeur +my $const_ptd_factor = .5523; + +my @Gradiants; +my %textures; +my %images; +my %bitmaps; + +my $font_7 = '-cenapii-bleriot mini-book-r-normal--7-70-75-75-p-*-iso8859-15'; + + +#----------------------------------------------------------------------------------- +# Graphics::buildZincItem +# Création d'un objet Zinc de représentation +# paramètres : +# widget : +# parentgroup : +# style : {hash table options} +# specific_tags : [list of specific tags] to add to params -tags +# name : nom de l'item +#----------------------------------------------------------------------------------- +# type d'item valide : +# les items natifs zinc : group, rectangle, arc, curve, text, icon +# les items ci-après permettent de spécifier des curves 'particulières' : +# -roundedrectangle : rectangle à coin arrondi +# -hippodrome : hippodrome +# -polygone : polygone régulier à n cotés (convexe ou en étoile) +# -roundedcurve : curve multicontours à coins arrondis (rayon unique) +# -polyline : curve multicontours à coins arrondis (le rayon pouvant être défini +# spécifiquement pour chaque sommet) +# -pathline : création d'une ligne 'épaisse' avec l'item Zinc triangles +# décalage par rapport à un chemin donné (largeur et sens de décalage) +# dégradé de couleurs de la ligne (linéaire, transversal ou double) +#----------------------------------------------------------------------------------- +sub buildZincItem { + my ($zinc, $parentgroup, $style, $specific_tags, $name) = @_; + $parentgroup = 1 if !$parentgroup; + + my @tags = ($specific_tags) ? @{$specific_tags} : (); + my $params_tags; + + if ($style->{'-params'}->{'-tags'}) { + $params_tags = delete $style->{'-params'}->{'-tags'}; + push (@tags, @{$params_tags}) if $params_tags; + } + + my $itemtype = $style->{'-itemtype'}; + my $coords = $style->{'-coords'}; + + # création de l'item Zinc + my $item; + + # gestion des polygones particuliers et à coin arrondi + if ($itemtype eq 'roundedrectangle') { + $itemtype = 'curve'; + $style->{'-params'}->{'-closed'} = 1; + $coords = &roundedRectangleCoords($coords, %{$style}); + + } elsif ($itemtype eq 'hippodrome') { + $itemtype = 'curve'; + $style->{'-params'}->{'-closed'} = 1; + $coords = &HippoCoords($coords, %{$style}); + + } elsif ($itemtype eq 'polygone') { + $itemtype = 'curve'; + $style->{'-params'}->{'-closed'} = 1; + $coords = &polygonCoords($coords, %{$style}); + + } elsif ($itemtype eq 'roundedcurve' or $itemtype eq 'polyline') { + $itemtype = 'curve'; + if ($itemtype eq 'roundedcurve') { + $style->{'-params'}->{'-closed'} = 1; + $coords = &roundedCurveCoords($coords, %{$style}); + + } else { + $coords = &polylineCoords($coords, %{$style}); + } + + # multi-contours + if ($style->{'-contours'}) { + my @contours = @{$style->{'-contours'}}; + my $numcontours = scalar(@contours); + for (my $i = 0; $i < $numcontours; $i++) { + # radius et corners peuvent être défini spécifiquement pour chaque contour + my ($type, $way, $coords, $radius, $corners, $corners_radius) = @{$contours[$i]}; + $radius = $style->{'-radius'} if (!defined $radius); + my $newcoords; + if ($itemtype eq 'roundedcurve') { + $newcoords = &roundedCurveCoords($coords, -radius => $radius, -corners => $corners); + } else { + $newcoords = &polylineCoords($coords, -radius => $radius, -corners => $corners, -corners_radius => $corners_radius); + } + + $style->{'-contours'}->[$i] = [$type, $way, $newcoords]; + } + } + } elsif ($itemtype eq 'pathline') { + $itemtype = 'triangles'; + if ($style->{'-metacoords'}) { + $coords = &metaCoords(%{$style->{'-metacoords'}}); + + } + + if ($style->{'-graduate'}) { + my $numcolors = scalar(@{$coords}); + $style->{'-params'}->{'-colors'} = &pathGraduate($zinc, $numcolors, $style->{'-graduate'}); + } + + $coords = &pathLineCoords($coords, %{$style}); + + } + + if ($itemtype eq 'group') { + $item = $zinc->add($itemtype, + $parentgroup, + %{$style->{'-params'}}, + -tags => \@tags, + ); + + $zinc->coords($item, $coords) if $coords; + + } elsif ($itemtype eq 'text' or $itemtype eq 'icon') { + my $imagefile; + if ($itemtype eq 'icon') { + $imagefile = $style->{'-params'}->{'-image'}; + $style->{'-params'}->{'-image'} = &init_pixmap($zinc, $imagefile) if $imagefile; + } + + $item = $zinc->add($itemtype, + $parentgroup, + -position => $coords, + %{$style->{'-params'}}, + -tags => \@tags, + ); + + $style->{'-params'}->{'-image'} = $imagefile if $imagefile; + + } else { + $item = $zinc->add($itemtype, + $parentgroup, + $coords, + %{$style->{'-params'}}, + -tags => \@tags, + ); + + if ($itemtype eq 'curve' and $style->{'-contours'}) { + foreach my $contour (@{$style->{'-contours'}}) { + $zinc->contour($item, @{$contour}); + } + } + + # gestion du mode norender + if ($style->{'-texture'}) { + my $texture = &getTexture($zinc, $style->{'-texture'}); + $zinc->itemconfigure($item, -tile => $texture) if $texture; + } + + if ($style->{'-fillpattern'}) { + my $bitmap = &getBitmap($style->{'-fillpattern'}); + $zinc->itemconfigure($item, -fillpattern => $bitmap) if $bitmap; + } + + + } + + # transformation scale de l'item si nécessaire + $zinc->scale($item, @{$style->{'-scale'}}) if ($style->{'-scale'}); + + # transformation rotate de l'item si nécessaire + $zinc->rotate($item, deg2rad($style->{'-rotate'})) if ($style->{'-rotate'}); + + # transformation scale de l'item si nécessaire + $zinc->translate($item, @{$style->{'-translate'}}) if ($style->{'-translate'}); + + # remise étét initial de la table de hash + $style->{'-params'}->{'-tags'} = $params_tags if ($params_tags); + + return $item; + +} + +#----------------------------------------------------------------------------------- +# FONCTIONS GEOMETRIQUES +#----------------------------------------------------------------------------------- + +#----------------------------------------------------------------------------------- +# Graphics::metaCoords +# retourne une liste de coordonnées en utilisant la fonction d'un autre type d'item +# paramètres : (options) +# -type : type de primitive utilisée +# -coords : coordonnées nécessitée par la fonction [type]Coords +# + options spécialisées passés à la fonction [type]Coords +#----------------------------------------------------------------------------------- +sub metaCoords { + my (%options) = @_; + my $pts; + + my @options = keys(%options); + my $type = delete $options{'-type'}; + my $coords = delete $options{'-coords'}; + + if ($type eq 'polygone') { + $pts = &polygonCoords($coords, %options); + + } elsif ($type eq 'hyppodrome') { + $pts = &hippoCoords($coords, %options); + + } elsif ($type eq 'polyline') { + $pts = &polylineCoords($coords, %options); + } + + return $pts; +} + +#----------------------------------------------------------------------------------- +# Graphics::roundedRectangleCoords +# calcul des coords du rectangle à coins arrondis +# paramètres : +# coords : point centre du polygone +# options : +# -radius : rayon de raccord d'angle +# -corners : liste des raccords de sommets [0 (aucun raccord)|1] par défaut [1,1,1,1] +#----------------------------------------------------------------------------------- +sub roundedRectangleCoords { + my ($coords, %options) = @_; + my ($x0, $y0, $xn, $yn) = ($coords->[0]->[0], $coords->[0]->[1], + $coords->[1]->[0], $coords->[1]->[1]); + + my @options = keys(%options); + my $radius = $options{'-radius'}; + my $corners = $options{'-corners'} ? $options{'-corners'} : [1, 1, 1, 1]; + + # attention aux formes 'négatives' + if ($xn < $x0) { + my $xs = $x0; + ($x0, $xn) = ($xn, $xs); + } + if ($yn < $y0) { + my $ys = $y0; + ($y0, $yn) = ($yn, $ys); + } + + my $height = &_min($xn -$x0, $yn - $y0); + + if (!defined $radius) { + $radius = int($height/10); + $radius = 3 if $radius < 3; + } + + if (!$radius or $radius < 2) { + return [[$x0, $y0],[$x0, $yn],[$xn, $yn],[$xn, $y0]]; + + } + + + # correction de radius si necessaire + my $max_rad = $height; + $max_rad /= 2 if (!defined $corners); + $radius = $max_rad if $radius > $max_rad; + + # points remarquables + my $ptd_delta = $radius * $const_ptd_factor; + my ($x2, $x3) = ($x0 + $radius, $xn - $radius); + my ($x1, $x4) = ($x2 - $ptd_delta, $x3 + $ptd_delta); + my ($y2, $y3) = ($y0 + $radius, $yn - $radius); + my ($y1, $y4) = ($y2 - $ptd_delta, $y3 + $ptd_delta); + + # liste des 4 points sommet du rectangle : angles sans raccord circulaire + my @angle_pts = ([$x0, $y0],[$x0, $yn],[$xn, $yn],[$xn, $y0]); + + # liste des 4 segments quadratique : raccord d'angle = radius + my @roundeds = ([[$x2, $y0],[$x1, $y0, 'c'],[$x0, $y1, 'c'],[$x0, $y2],], + [[$x0, $y3],[$x0, $y4, 'c'],[$x1, $yn, 'c'],[$x2, $yn],], + [[$x3, $yn],[$x4, $yn, 'c'],[$xn, $y4, 'c'],[$xn, $y3],], + [[$xn, $y2],[$xn, $y1, 'c'],[$x4, $y0, 'c'],[$x3, $y0],]); + + my @pts = (); + for (my $i = 0; $i < 4; $i++) { + if ($corners->[$i]) { + push(@pts, @{$roundeds[$i]}); + + } else { + push(@pts, $angle_pts[$i]); + } + } + + return \@pts; +} + + +#----------------------------------------------------------------------------------- +# Graphics::HippoCoords +# calcul des coords d'un hippodrome +# paramètres : +# coords : coordonnées du rectangle exinscrit +# options : +# -orientation : orientation forcée de l'ippodrome [horizontal|vertical] +# -corners : liste des raccords de sommets [0|1] par défaut [1,1,1,1] +# -trunc : troncatures [left|right|top|bottom|both] +#----------------------------------------------------------------------------------- +sub HippoCoords { + my ($coords, %options) = @_; + my ($x0, $y0, $xn, $yn) = ($coords->[0]->[0], $coords->[0]->[1], + $coords->[1]->[0], $coords->[1]->[1]); + + my @options = keys(%options); + my $orientation = $options{'-orientation'}; + + # orientation forcée de l'hippodrome (sinon hippodrome sur le plus petit coté) + my $height = ($orientation eq 'horizontal') ? abs($yn - $y0) + : ($orientation eq 'vertical') ? abs($xn - $x0) : &_min(abs($xn - $x0), abs($yn - $y0)); + my $radius = $height/2; + my $corners = [1, 1, 1, 1]; + + if ($options{'-corners'}) { + $corners = $options{'-corners'}; + + } elsif ($options{'-trunc'}) { + my $trunc = $options{'-trunc'}; + if ($trunc eq 'both') { + return [[$x0, $y0],[$x0, $yn],[$xn, $yn],[$xn, $y0]]; + + } else { + $corners = ($trunc eq 'left') ? [0, 0, 1, 1] : + ($trunc eq 'right') ? [1, 1, 0, 0] : + ($trunc eq 'top') ? [0, 1, 1, 0] : + ($trunc eq 'bottom') ? [1, 0, 0, 1] : [1, 1, 1, 1]; + + } + } + + # l'hippodrome est un cas particulier de roundedRectangle + # on retourne en passant la 'configuration' à la fonction générique roundedRectangleCoords + return &roundedRectangleCoords($coords, -radius => $radius, -corners => $corners); +} + + +#----------------------------------------------------------------------------------- +# Graphics::polygonCoords +# calcul des coords d'un polygone régulier +# paramètres : +# coords : point centre du polygone +# options : +# -numsides : nombre de cotés +# -radius : rayon de définition du polygone (distance centre-sommets) +# -inner_radius : rayon interne (polygone type étoile) +# -corners : liste des raccords de sommets [0|1] par défaut [1,1,1,1] +# -corner_radius : rayon de raccord des cotés +# -startangle : angle de départ du polygone +#----------------------------------------------------------------------------------- +sub polygonCoords { + my ($coords, %options) = @_; + + my @options = keys(%options); + my $numsides = $options{'-numsides'}; + my $radius = $options{'-radius'}; + if ($numsides < 3 or !$radius) { + print "Vous devez au moins spécifier un nombre de cotés >= 3 et un rayon...\n"; + return undef; + } + + my ($cx, $cy) = ($coords) ? @{$coords} : (0, 0); + my $startangle = ($options{'-startangle'}) ? $options{'-startangle'} : 0; + my $anglestep = 360/$numsides; + my $inner_radius = $options{'-inner_radius'}; + my @pts; + + # points du polygone + for (my $i = 0; $i < $numsides; $i++) { + my ($xp, $yp) = &rad_point($cx, $cy, $radius, $startangle + ($anglestep*$i)); + push(@pts, ([$xp, $yp])); + + # polygones 'étoiles' + if ($inner_radius) { + ($xp, $yp) = &rad_point($cx, $cy, $inner_radius, $startangle + ($anglestep*($i+ 0.5))); + push(@pts, ([$xp, $yp])); + } + } + + + if ($options{'-corner_radius'}) { + return &roundedCurveCoords(\@pts, -radius => $options{'-corner_radius'}, -corners => $options{'-corners'}); + } else { + return \@pts; + } +} + +#----------------------------------------------------------------------------------- +# Graphics::roundedAngle +# curve d'angle avec raccord circulaire +# paramètres : +# zinc : widget +# parentgroup : group zinc parent +# coords : les 3 points de l'angle +# radius : rayon de raccord +#----------------------------------------------------------------------------------- +sub roundedAngle { + my ($zinc, $parentgroup, $coords, $radius) = @_; + my ($pt0, $pt1, $pt2) = @{$coords}; + + my ($corner_pts, $center_pts) = &roundedAngleCoords($coords, $radius); + my ($cx0, $cy0) = @{$center_pts}; + + # valeur d'angle et angle formé par la bisectrice + my ($angle) = &vertexAngle($pt0, $pt1, $pt2); + + $parentgroup = 1 if (!defined $parentgroup); + + # temporaire -> visibilité de l'arc 'conique' correspondant + $zinc->add('arc', $parentgroup, + [[$cx0 - $radius, $cy0 - $radius],[$cx0 + $radius, $cy0 + $radius]], + -priority => 10, + -linecolor => '#9999ff', + -filled => 0, + -visible => 1, + -linewidth => 2, + ); + + # temporaire + $zinc->add('text', $parentgroup, + -position => [$cx0 - $radius + 2, $cy0], + -priority => 20, + -color => '#0000ff', + -text => $angle."°", + -font => $font_7, + -alignment => 'left', + -anchor => 'w', + ); + + $zinc->add('curve', $parentgroup, + [$pt0,@{$corner_pts},$pt2], + -closed => 0, + -linewidth => 1, + -priority => 20, + ); + +} + +#----------------------------------------------------------------------------------- +# Graphics::roundedAngleCoords +# calcul des coords d'un raccord d'angle circulaire +#----------------------------------------------------------------------------------- +# le raccord circulaire de 2 droites sécantes est traditionnellement réalisé par un +# arc (conique) du cercle inscrit de rayon radius tangent à ces 2 droites +# +# Quadratique : +# une approche de cette courbe peut être réalisée simplement par le calcul de 4 points +# spécifiques qui définiront - quelle que soit la valeur de l'angle formé par les 2 +# droites - le segment de raccord : +# - les 2 points de tangence au cercle inscrit seront les points de début et de fin +# du segment de raccord +# - les 2 points de controle seront situés chacun sur le vecteur reliant le point de +# tangence au sommet de l'angle (point secant des 2 droites) +# leur position sur ce vecteur peut être simplifiée comme suit : +# - à un facteur de 0.5523 de la distance au sommet pour un angle >= 90° et <= 270° +# - à une 'réduction' de ce point vers le point de tangence pour les angles limites +# de 90° vers 0° et de 270° vers 360° +# ce facteur sera légérement modulé pour recouvrir plus précisement l'arc correspondant +#----------------------------------------------------------------------------------- +sub roundedAngleCoords { + my ($coords, $radius) = @_; + my ($pt0, $pt1, $pt2) = @{$coords}; + + # valeur d'angle et angle formé par la bisectrice + my ($angle, $bisecangle) = &vertexAngle($pt0, $pt1, $pt2); + + # distance au centre du cercle inscrit : rayon/sinus demi-angle + my $sin = sin(deg2rad($angle/2)); + my $delta = ($sin) ? abs($radius / $sin) : $radius; + + # point centre du cercle inscrit de rayon $radius + my $refangle = ($angle < 180) ? $bisecangle+90 : $bisecangle-90; + my ($cx0, $cy0) = rad_point($pt1->[0], $pt1->[1], $delta, $refangle); + + # points de tangeance : pts perpendiculaires du centre aux 2 droites + my ($px1, $py1) = &perpendicularPoint([$cx0, $cy0], [$pt0, $pt1]); + my ($px2, $py2) = &perpendicularPoint([$cx0, $cy0], [$pt1, $pt2]); + + # point de controle de la quadratique + # facteur de positionnement sur le vecteur pt.tangence, sommet + my $ptd_factor = $const_ptd_factor; + if ($angle < 90 or $angle > 270) { + my $diffangle = ($angle < 90) ? $angle : 360 - $angle; + $ptd_factor -= (((90 - $diffangle)/90) * ($ptd_factor/4)) if $diffangle > 15 ; + $ptd_factor = ($diffangle/90) * ($ptd_factor + ((1 - $ptd_factor) * (90 - $diffangle)/90)); + } else { + my $diffangle = abs(180 - $angle); + $ptd_factor += (((90 - $diffangle)/90) * ($ptd_factor/3)) if $diffangle > 15; + } + + # delta xy aux pts de tangence + my ($d1x, $d1y) = (($pt1->[0] - $px1) * $ptd_factor, ($pt1->[1] - $py1) * $ptd_factor); + my ($d2x, $d2y) = (($pt1->[0] - $px2) * $ptd_factor, ($pt1->[1] - $py2) * $ptd_factor); + + # les 4 points de l'arc 'quadratique' + my $corner_pts = [[$px1, $py1],[$px1+$d1x, $py1+$d1y, 'c'], + [$px2+$d2x, $py2+$d2y, 'c'],[$px2, $py2]]; + + + # retourne le segment de quadratique et le centre du cercle inscrit + return ($corner_pts, [$cx0, $cy0]); + +} + + +#----------------------------------------------------------------------------------- +# Graphics::roundedCurveCoords +# retourne les coordonnées d'une curve à coins arrondis +# paramètres : +# coords : points de la curve +# options : +# -radius : rayon de raccord d'angle +# -corners : liste des raccords de sommets [0|1] par défaut [1,1,1,1] +#----------------------------------------------------------------------------------- +sub roundedCurveCoords { + my ($coords, %options) = @_; + my $numfaces = scalar(@{$coords}); + my @curve_pts; + + my @options = keys(%options); + my $radius = ($options{'-radius'}) ? $options{'-radius'} : 0; + my $corners = $options{'-corners'}; + + for (my $index = 0; $index < $numfaces; $index++) { + if ($corners and !$corners->[$index]) { + push(@curve_pts, $coords->[$index]); + + } else { + my $prev = ($index) ? $index - 1 : $numfaces - 1; + my $next = ($index > $numfaces - 2) ? 0 : $index + 1; + my $anglecoords = [$coords->[$prev], $coords->[$index], $coords->[$next]]; + + my ($quad_pts) = &roundedAngleCoords($anglecoords, $radius); + push(@curve_pts, @{$quad_pts}); + } + } + + return \@curve_pts; + +} + + +#----------------------------------------------------------------------------------- +# Graphics::polylineCoords +# retourne les coordonnées d'une polyline +# paramètres : +# coords : sommets de la polyline +# options : +# -radius : rayon global de raccord d'angle +# -corners : liste des raccords de sommets [0|1] par défaut [1,1,1,1], +# -corners_radius : liste des rayons de raccords de sommets +#----------------------------------------------------------------------------------- +sub polylineCoords { + my ($coords, %options) = @_; + my $numfaces = scalar(@{$coords}); + my @curve_pts; + + my @options = keys(%options); + my $radius = ($options{'-radius'}) ? $options{'-radius'} : 0; + my $corners_radius = $options{'-corners_radius'}; + my $corners = ($corners_radius) ? $corners_radius : $options{'-corners'}; + + for (my $index = 0; $index < $numfaces; $index++) { + if ($corners and !$corners->[$index]) { + push(@curve_pts, $coords->[$index]); + + } else { + my $prev = ($index) ? $index - 1 : $numfaces - 1; + my $next = ($index > $numfaces - 2) ? 0 : $index + 1; + my $anglecoords = [$coords->[$prev], $coords->[$index], $coords->[$next]]; + + my $rad = ($corners_radius) ? $corners_radius->[$index] : $radius; + my ($quad_pts) = &roundedAngleCoords($anglecoords, $rad); + push(@curve_pts, @{$quad_pts}); + } + } + + return \@curve_pts; + +} + +#----------------------------------------------------------------------------------- +# Graphics::pathLineCoords +# retourne les coordonnées d'une pathLine +# paramètres : +# coords : points de path +# options : +# -closed : ligne fermée +# -shifting : sens de décalage [both|left|right] par défaut both +# -linewidth : epaisseur de la ligne +#----------------------------------------------------------------------------------- +sub pathLineCoords { + my ($coords, %options) = @_; + my $numfaces = scalar(@{$coords}); + my @pts; + + my @options = keys(%options); + my $closed = $options{'-closed'}; + my $linewidth = ($options{'-linewidth'}) ? $options{'-linewidth'} : 0; + my $shifting = ($options{'-shifting'}) ? $options{'-shifting'} : 'both'; + + return undef if (!$numfaces or $linewidth < 2); + + my $previous = ($closed) ? $coords->[$numfaces - 1] : undef; + my $next = $coords->[1]; + $linewidth /= 2 if ($shifting eq 'both'); + + for (my $i = 0; $i < $numfaces; $i++) { + my $pt = $coords->[$i]; + + if (!$previous) { + # extrémité de curve sans raccord -> angle plat + $previous = [$pt->[0] + ($pt->[0] - $next->[0]), $pt->[1] + ($pt->[1] - $next->[1])]; + } + + my ($angle, $bisecangle) = &vertexAngle($previous, $pt, $next); + + # distance au centre du cercle inscrit : rayon/sinus demi-angle + my $sin = sin(deg2rad($angle/2)); + my $delta = ($sin) ? abs($linewidth / $sin) : $linewidth; + + if ($shifting eq 'left' or $shifting eq 'right') { + my $adding = ($shifting eq 'left') ? 90 : -90; + push (@pts, &rad_point($pt->[0], $pt->[1], $delta, $bisecangle + $adding)); + push (@pts, @{$pt}); + + } else { + push (@pts, &rad_point($pt->[0], $pt->[1], $delta, $bisecangle+90)); + push (@pts, &rad_point($pt->[0], $pt->[1], $delta, $bisecangle-90)); + + } + + if ($i == $numfaces - 2) { + $next = ($closed) ? $coords->[0] : + [$coords->[$i+1]->[0] + ($coords->[$i+1]->[0] - $pt->[0]), $coords->[$i+1]->[1] + ($coords->[$i+1]->[1] - $pt->[1])]; + } else { + $next = $coords->[$i+2]; + } + + $previous = $coords->[$i]; + } + + if ($closed) { + push (@pts, ($pts[0], $pts[1], $pts[2], $pts[3])); + } + + return \@pts; +} + +#----------------------------------------------------------------------------------- +# Graphics::perpendicularPoint +# retourne les coordonnées du point perpendiculaire abaissé d'un point sur une ligne +#----------------------------------------------------------------------------------- +sub perpendicularPoint { + my ($point, $line) = @_; + my ($p1, $p2) = @{$line}; + + # cas partiuculier de lignes ortho. + my $min_dist = .01; + if (abs($p2->[1] - $p1->[1]) < $min_dist) { + # la ligne de référence est horizontale + return ($point->[0], $p1->[1]); + + } elsif (abs($p2->[0] - $p1->[0]) < $min_dist) { + # la ligne de référence est verticale + return ($p1->[0], $point->[1]); + } + + my $a1 = ($p2->[1] - $p1->[1]) / ($p2->[0] - $p1->[0]); + my $b1 = $p1->[1] - ($a1 * $p1->[0]); + + my $a2 = -1.0 / $a1; + my $b2 = $point->[1] - ($a2 * $point->[0]); + + my $x = ($b2 - $b1) / ($a1 - $a2); + my $y = ($a1 * $x) + $b1; + + return ($x, $y); + +} + + +#----------------------------------------------------------------------------------- +# Graphics::lineAngle +# retourne l'angle d'un point par rapport à un centre de référence +#----------------------------------------------------------------------------------- +sub lineAngle { + my ($x, $y, $xref, $yref) = @_; + my $angle = atan2($y - $yref, $x - $xref); + + $angle += pi/2; + $angle *= 180/pi; + $angle += 360 if ($angle < 0); + + return $angle; + +} + + + +#----------------------------------------------------------------------------------- +# Graphics::vertexAngle +# retourne la valeur de l'angle formée par 3 points +# ainsi que l'angle de la bisectrice +#----------------------------------------------------------------------------------- +sub vertexAngle { + my ($pt0, $pt1, $pt2) = @_; + my $angle1 = &lineAngle(@{$pt1}, @{$pt0}); + my $angle2 = &lineAngle(@{$pt1}, @{$pt2}); + + $angle2 += 360 if $angle2 < $angle1; + my $alpha = $angle2 - $angle1; + my $bisectrice = $angle1 + ($alpha/2); + + return ($alpha, $bisectrice); +} + + +#----------------------------------------------------------------------------------- +# Graphics::arc_pts +# calcul des points constitutif d'un arc +# params : x,y centre, rayon, angle départ, delta angulaire, pas en degré +#----------------------------------------------------------------------------------- +sub arc_pts { + my ($x, $y, $rad, $angle, $extent, $step, $debug) = @_; + my @pts = (); + + + if ($extent > 0) { + for (my $alpha = $angle; $alpha <= ($angle + $extent); $alpha += $step) { + my ($xn, $yn) = &rad_point($x, $y, $rad,$alpha); + push (@pts, ([$xn, $yn])); + } + } else { + for (my $alpha = $angle; $alpha >= ($angle + $extent); $alpha += $step) { + push (@pts, &rad_point($x, $y, $rad,$alpha)); + } + } + + return @pts; +} + + +#----------------------------------------------------------------------------------- +# Graphics::rad_point +# retourne le point circulaire défini par centre-rayon-angle +#----------------------------------------------------------------------------------- +sub rad_point { + my ($x, $y, $rad, $angle) = @_; + my $alpha = deg2rad($angle); + + my $xpt = $x + ($rad * cos($alpha)); + my $ypt = $y + ($rad * sin($alpha)); + + return ($xpt, $ypt); +} + + +#----------------------------------------------------------------------------------- +# Graphics::buildTabBox +# création des items Zinc d'un ensemble de page à onglet +#----------------------------------------------------------------------------------- +sub buidTabBox { + my ($zinc, $group, $style, $specific_tags,) = @_; + + # création d'un groupe principal si besoin + my $groupstyle = delete $style->{'-group'}; + if ($groupstyle) { + $group = &buildZincItem($zinc, $group, $groupstyle); + + } else { + $group = 1 if (!defined $group); + } + + # calcul des shapes + my $coords = $style->{'-coords'}; + my $params = $style->{'-params'}; + my $multi = $style->{'-multi'}; + my $titles = $style->{'-titles'}; + + my ($shapes, $title_coords) = &computeDividers($coords,%{$style}); + + # création des intercalaires + my $i = scalar(@{$shapes}) - 1; + foreach my $shape (reverse @{$shapes}) { + if ($multi) { + while (my ($key, $values) = each(%{$multi})) { + $params->{$key} = $values->[$i]; + } + } + + # item zinc enveloppe intercalaire + my $intergroup = $zinc->add('group', $group); + my %interstyle = (-itemtype => 'curve', + -closed => 1, + -coords => $shape, + -params => $params, + ); + $interstyle{-texture} = $style->{'-texture'} if ($style->{'-texture'}); + my $inter = &buildZincItem($zinc, $intergroup, \%interstyle, $specific_tags); + + # titre de l'onglet + if ($titles) { + my $params = $titles->{'-params'}; + $coords = ($titles->{'-coords'}) ? $titles->{'-coords'}->[$i] : $title_coords->[$i]; + $params->{'-text'} = $titles->{'-text'}->[$i]; + $zinc->add('text', $intergroup, + -position => $coords, + %{$params}, + ); + } + + # zone page interne à l'intercalaire + if ($style->{'-page'}) { + &buildZincItem($zinc, $intergroup, $style->{'-page'}); + } + + # items complémentaires + if ($style->{'-decos'}) { + while (my ($itemname, $itemstyle) = each(%{$style->{'-decos'}})) { + &buildZincItem($zinc, $intergroup, $itemstyle); + } + } + + $i--; + } +} + +#----------------------------------------------------------------------------------- +# TabBoxCoords +# Calcul des shapes de boites à onglets +# +# coords : coordonnées rectangle de la bounding box +# +# options +# -numpages : nombre de pages (onglets) de la boite +# -anchor [n|e|s|w] : ancrage des onglets +# -alignment [left|center|right] : alignement des onglets sur le coté d'ancrage +# -tabwidth [|[,,...]|auto] : largeur des onglets +# -tabheight [|auto] : hauteur des onglets +# -tabshift : décalage onglet +# -radius : rayon des arrondis d'angle +# -overlap : distance de recouvrement des onglets +#----------------------------------------------------------------------------------- +sub TabBoxCoords { + my ($coords, %options) = @_; + my ($x0, $y0, $xn, $yn) = (@{$coords->[0]}, @{$coords->[1]}); + my (@shapes, @titles_coords); + my $inverse; + + my @options = keys(%options); + my $numpages = $options{'-numpages'}; + + if (!defined $x0 or !defined $y0 or !defined $xn or !defined $yn or !$numpages) { + print "Vous devez au minimum spécifier le rectangle englobant et le nombre de pages\n"; + return undef; + + } + + my $anchor = ($options{'-anchor'}) ? $options{'-anchor'} : 'n'; + my $alignment = ($options{'-alignment'}) ? $options{'-alignment'} : 'left'; + my $len = ($options{'-tabwidth'}) ? $options{'-tabwidth'} : 'auto'; + my $thick = ($options{'-tabheight'}) ? $options{'-tabheight'} : 'auto'; + my $biso = ($options{'-tabshift'}) ? $options{'-tabshift'} : 'auto'; + my $radius = ($options{'-radius'}) ? $options{'-radius'} : 0; + my $overlap = ($options{'-overlap'}) ? $options{'-overlap'} : 0; + my $orientation = ($anchor eq 'n' or $anchor eq 's') ? 'horizontal' : 'vertical'; + my $maxwidth = ($orientation eq 'horizontal') ? ($xn - $x0) : ($yn - $y0); + my $tabswidth = 0; + my $align = 1; + + if ($len eq 'auto') { + $tabswidth = $maxwidth; + $len = ($tabswidth + ($overlap * ($numpages - 1)))/$numpages; + + } else { + if (ref($len) eq 'ARRAY') { + foreach my $w (@{$len}) { + $tabswidth += ($w - $overlap); + } + $tabswidth += $overlap; + } else { + $tabswidth = ($len * $numpages) - ($overlap * ($numpages - 1)); + } + + if ($tabswidth > $maxwidth) { + $tabswidth = $maxwidth; + $len = ($tabswidth + ($overlap * ($numpages - 1)))/$numpages; + } + + $align = 0 if ($alignment eq 'center' and (($maxwidth - $tabswidth) > $radius)); + } + + + if ($thick eq 'auto') { + $thick = ($orientation eq 'horizontal') ? int(($yn - $y0)/10) : int(($xn - $y0)/10); + $thick = 10 if ($thick < 10); + $thick = 40 if ($thick > 40); + } + + if ($biso eq 'auto') { + $biso = int($thick/2); + } + + if (($alignment eq 'right' and $anchor ne 'w') or + ($anchor eq 'w' and $alignment ne 'right')) { + + if (ref($len) eq 'ARRAY') { + for (my $i = 0; $i < $numpages; $i++) { + $len->[$i] *= -1; + } + } else { + $len *= -1; + } + $biso *= -1; + $overlap *= -1; + } + + my ($biso1, $biso2) = ($alignment eq 'center') ? ($biso/2, $biso/2) : (0, $biso); + + my (@cadre, @tabdxy); + my ($xref, $yref); + if ($orientation eq 'vertical') { + $thick *= -1 if ($anchor eq 'w'); + my ($startx, $endx) = ($anchor eq 'w') ? ($x0, $xn) : ($xn, $x0); + my ($starty, $endy) = (($anchor eq 'w' and $alignment ne 'right') or + ($anchor eq 'e' and $alignment eq 'right')) ? + ($yn, $y0) : ($y0, $yn); + + $xref = $startx - $thick; + $yref = $starty; + if ($alignment eq 'center') { + my $ratio = ($anchor eq 'w') ? -2 : 2; + $yref += (($maxwidth - $tabswidth)/$ratio); + } + + @cadre = ([$xref, $endy], [$endx, $endy], [$endx, $starty], [$xref, $starty]); + + # flag de retournement de la liste des pts de curve si nécessaire -> sens anti-horaire + $inverse = ($alignment ne 'right'); + + } else { + $thick *= -1 if ($anchor eq 's'); + my ($startx, $endx) = ($alignment eq 'right') ? ($xn, $x0) : ($x0, $xn); + my ($starty, $endy) = ($anchor eq 's') ? ($yn, $y0) : ($y0, $yn); + + + $yref = $starty + $thick; + $xref = ($alignment eq 'center') ? $x0 + (($maxwidth - $tabswidth)/2) : $startx; + + @cadre = ([$endx, $yref], [$endx, $endy], [$startx, $endy], [$startx, $yref]); + + # flag de retournement de la liste des pts de curve si nécessaire -> sens anti-horaire + $inverse = (($anchor eq 'n' and $alignment ne 'right') or ($anchor eq 's' and $alignment eq 'right')); + } + + + for (my $i = 0; $i < $numpages; $i++) { + my @pts = (); + + # décrochage onglet + #push (@pts, ([$xref, $yref])) if $i > 0; + + # cadre + push (@pts, @cadre); + + # points onglets + push (@pts, ([$xref, $yref])) if ($i > 0 or !$align); + + my $tw = (ref($len) eq 'ARRAY') ? $len->[$i] : $len; + @tabdxy = ($orientation eq 'vertical') ? + ([$thick, $biso1],[$thick, $tw - $biso2],[0, $tw]) : ([$biso1, -$thick],[$tw - $biso2, -$thick],[$tw, 0]); + foreach my $dxy (@tabdxy) { + push (@pts, ([$xref + $dxy->[0], $yref + $dxy->[1]])); + } + + + if ($radius) { + my $corners = ($i > 0 or !$align) ? [0, 1, 1, 1, 0, 1, 1, 0] : [0, 1, 1, 0, 1, 1, 0, 0, 0]; + my $curvepts = &roundedCurveCoords(\@pts, -radius => $radius, -corners => $corners); + @{$curvepts} = reverse @{$curvepts} if ($inverse); + push (@shapes, $curvepts); + } else { + reverse @pts if ($inverse); + push (@shapes, \@pts); + } + + if ($orientation eq 'horizontal') { + push (@titles_coords, [$xref + ($tw - ($biso2 - $biso1))/2, $yref - ($thick/2)]); + $xref += ($tw - $overlap); + + } else { + push (@titles_coords, [$xref + ($thick/2), $yref + ($len - (($biso2 - $biso1)/2))/2]); + $yref += ($len - $overlap); + } + + } + + return (\@shapes, \@titles_coords, $inverse); + +} + + + +#----------------------------------------------------------------------------------- +# RESOURCES GRAPHIQUES GRADIANTS, PATTERNS, TEXTURES, IMAGES... +#----------------------------------------------------------------------------------- +#----------------------------------------------------------------------------------- +# Graphics::setGradiants +# création de gradiant nommés Zinc +#----------------------------------------------------------------------------------- +sub setGradiants { + my ($zinc, $grads) = @_; + + # initialise les gradiants de taches + unless (@Gradiants) { + while (my ($name, $gradiant) = each( %{$grads})) { + # création des gradiants nommés + $zinc->gname($gradiant, $name); + push(@Gradiants, $name); + } + } +} + + +#----------------------------------------------------------------------------------- +# Graphics::getPattern +# retourne la ressource bitmap en l'initialisant si première utilisation +#----------------------------------------------------------------------------------- +sub getPattern { + my ($name) = @_; + my $bitmap; + + if (!exists($bitmaps{$name})) { + $bitmap = '@'.Tk::findINC($name); + $bitmaps{$name} = $bitmap; + + } else { + $bitmap = $bitmaps{$name}; + } + + return $bitmap; +} + +#----------------------------------------------------------------------------------- +# Graphics::getTexture +# retourne l'image de texture en l'initialisant si première utilisation +#----------------------------------------------------------------------------------- +sub getTexture { + my ($zinc, $name) = @_; + my $texture; + + if (!exists($textures{$name})) { + $texture = $zinc->Photo(-file => Tk::findINC($name)); + $textures{$name} = $texture; + + } else { + $texture = $textures{$name}; + } + + return $texture; +} + +#----------------------------------------------------------------------------------- +# Graphics::getImage +# retourne la ressource image en l'initialisant si première utilisation +#----------------------------------------------------------------------------------- +sub getImage { + my ($widget, $imagefile) = @_; + + if (!exists($images{$imagefile})) { + my $image = $widget->Photo(-file => Tk::findINC($imagefile)); + $images{$imagefile} = $image if $image; + return $image; + } + + return $images{$imagefile}; + +} + + +#----------------------------------------------------------------------------------- +# Graphics::init_pixmaps +# initialise une liste de fichier image +#----------------------------------------------------------------------------------- +sub init_pixmaps { + my ($widget, @pixfiles) = @_; + my @imgs = (); + + + foreach (@pixfiles) { + push(@imgs, &getImage($widget, $_)); + } + + return @imgs; +} + + +sub _min { + my ($n1, $n2) = @_; + my $mini = ($n1 > $n2) ? $n2 : $n1; + return $mini; + +} + +sub _max { + my ($n1, $n2) = @_; + my $maxi = ($n1 > $n2) ? $n1 : $n2; + return $maxi; + +} + +#----------------------------------------------------------------------------------- +# Graphics::_trunc +# fonction interne de troncature des nombres: n = position décimale +#----------------------------------------------------------------------------------- +sub _trunc { + my ($val, $n) = @_; + my $str; + my $dec; + + ($val) =~ /([0-9]+)\.?([0-9]*)/; + $str = ($val < 0) ? "-$1" : $1; + + if (($2 ne "") && ($n != 0)) { + $dec = substr($2, 0, $n); + if ($dec != 0) { + $str = $str . "." . $dec; + } + } + return $str; +} + + +#----------------------------------------------------------------------------------- +# Graphics::RGB_dec2hex +# conversion d'une couleur RGB (255,255,255) au format Zinc '#ffffff' +#----------------------------------------------------------------------------------- +sub RGB_dec2hex { + my (@rgb) = @_; + return (sprintf("#%04x%04x%04x", @rgb)); +} + +#----------------------------------------------------------------------------------- +# Graphics::pathGraduate +# création d'un jeu de couleurs dégradées pour item pathLine +#----------------------------------------------------------------------------------- +sub pathGraduate { + my ($zinc, $numcolors, $style) = @_; + + my $type = $style->{'-type'}; + my $triangles_colors; + if ($type eq 'linear') { + return &createGraduate($zinc, $numcolors, $style->{'-colors'}, 2); + + } elsif ($type eq 'double') { + my $colors1 = &createGraduate($zinc, $numcolors/2+1, $style->{'-colors'}->[0]); + my $colors2 = &createGraduate($zinc, $numcolors/2+1, $style->{'-colors'}->[1]); + my @colors; + for (my $i = 0; $i <= $numcolors; $i++) { + push(@colors, ($colors1->[$i], $colors2->[$i])); + } + + return \@colors; + + } elsif ($type eq 'transversal') { + my ($c1, $c2) = @{$style->{'-colors'}}; + my @colors = ($c1, $c2); + for (my $i = 0; $i < $numcolors; $i++) { + push(@colors, ($c1, $c2)); + } + + return \@colors; + } +} + +#----------------------------------------------------------------------------------- +# Graphics::createGraduate +# création d'un jeu de couleurs intermédiaires (dégradé) entre n couleurs +#----------------------------------------------------------------------------------- +sub createGraduate { + my ($widget, $totalsteps, $refcolors, $repeat) = @_; + my @colors; + my $i = 0; + + $repeat = 1 if (!$repeat); + my $numgraduates = scalar @{$refcolors} - 1; + + if ($numgraduates < 1) { + print "Le dégradé necessite au minimum 2 couleurs de référence...\n"; + return undef; + } + + my $steps = ($numgraduates > 1) ? $totalsteps/($numgraduates -1) : $totalsteps; + + for (my $c = 0; $c < $numgraduates; $c++) { + my ($c1, $c2) = ($refcolors->[$c], $refcolors->[$c+1]); + + for (my $i = 0 ; $i < $steps ; $i++) { + my $color = computeColor($widget, $c1, $c2, $i/($steps-1)); + for (my $k = 0; $k < $repeat; $k++) { + push (@colors, $color); + } + } + + if ($c < $numgraduates - 1) { + for (my $k = 0; $k < $repeat; $k++) { + pop @colors; + } + } + } + return \@colors; +} + + +#----------------------------------------------------------------------------------- +# Graphics::computeColor +# calcul d'une couleur intermédiaire défini par un ratio ($rate) entre 2 couleur +#----------------------------------------------------------------------------------- +sub computeColor { + my ($widget, $color0, $color1, $rate) = @_; + $rate = 1 if ($rate > 1); + $rate = 0 if ($rate < 0); + + my ($r0, $g0, $b0, $a0) = &ZnColorToRGB($color0); + my ($r1, $g1, $b1, $a1) = &ZnColorToRGB($color1); + + my $r = $r0 + int(($r1 - $r0) * $rate); + my $g = $g0 + int(($g1 - $g0) * $rate); + my $b = $b0 + int(($b1 - $b0) * $rate); + my $a = $a0 + int(($a1 - $a0) * $rate); + + return &hexaRGBcolor($r, $g, $b, $a); +} + +sub ZnColorToRGB { + my ($zncolor) = @_; + + my ($color, $alpha) = split /;/, $zncolor; + my $ndigits = (length($color) > 8) ? 4 : 2; + my $R = hex(substr($color, 1, $ndigits)); + my $G = hex(substr($color, 1+$ndigits, $ndigits)); + my $B = hex(substr($color, 1+($ndigits*2), $ndigits)); + + $alpha = 100 if ($alpha eq ""); + + return ($R, $G, $B, $alpha); + +} + +#----------------------------------------------------------------------------------- +# Graphics::hexaRGBcolor +# conversion d'une couleur RGB (255,255,255) au format Zinc '#ffffff' +#----------------------------------------------------------------------------------- +sub hexaRGBcolor { + my ($r, $g, $b, $a) = @_; + + if (defined $a) { + my $hexacolor = sprintf("#%02x%02x%02x", ($r, $g, $b)); + return ($hexacolor.";".$a); + } + + return (sprintf("#%02x%02x%02x ", ($r, $g, $b))); +} + +1; + diff --git a/Perl/demos/Tk/demos/zinc_data/paper.gif b/Perl/demos/Tk/demos/zinc_data/paper.gif new file mode 100644 index 0000000..3247d35 Binary files /dev/null and b/Perl/demos/Tk/demos/zinc_data/paper.gif differ diff --git a/Perl/demos/Tk/demos/zinc_lib/testGraphics.pl b/Perl/demos/Tk/demos/zinc_lib/testGraphics.pl new file mode 100644 index 0000000..c79ace0 --- /dev/null +++ b/Perl/demos/Tk/demos/zinc_lib/testGraphics.pl @@ -0,0 +1,1707 @@ +#!/usr/bin/perl +#----------------------------------------------------------------------------------- +# +# testGraphics.pl +# Fichier test du module Graphics +# +# Authors: Jean-Luc Vinot +# +# $Id: +#----------------------------------------------------------------------------------- + +use Tk; +use Tk::Zinc; +use Graphics; +use Getopt::Long; +use strict 'vars'; + +my $rotate_angle = .1; +my $zoomfactor = .1; +my $curview; +my ($dx, $dy); + +my $tabanchor = 'n'; +my $tabalign = 'left'; + +my $font_9b = '-cenapii-bleriot mini-bold-r-normal--9-90-75-75-p-75-iso8859-15'; + +my %gradset = (# gradiants zinc + 'boitonglet' => '=axial 0|#ff7777|#ffff99', + 'roundrect1' => '=axial 270|#a7ffa7;70 0|#ffffff;90 5|#00bd00;80 8|#b7ffb7;50 80|#ffffff;70 91|#00ac00;70 95|#006700;60 100', + 'roundrect2' => '=axial 270|#00bd00;80 |#d7ffd7;60', + 'roundrect3' => '=axial 270|#00bd00;100 0|#ffffff;100 14|#ffffff;100 16|#00bd00;90 25|#b7ffb7;60 100', + 'roundrect4' => '=axial 0|#00bd00;100 0|#ffffff;100 20|#00bd00;50 30|#00bd00;90 80|#b7ffb7;60 100', + 'roundrect4ed' => '=path 48 48|#e7ffe7;20 0 70|#007900;20', + 'roundcurve2' => '=axial 270|#d7ffd7;60|#7777ff;80', + 'roundcurve1' => '=axial 270|#2222ff;80 |#d7ffd7;60', + 'roundcurve' => '=axial 270|#7777ff;80 |#d7ffd7;60', + 'roundpolyg' => '=radial -15 -20|#ffb7b7;50|#bd6622;90', + 'rpolyline' => '=axial 90|#ffff77;80 |#ff7700;60', + 'pushbtn1' => '=axial 0|#cccccc;100 0|#ffffff;100 10|#5a5a6a;100 80|#aaaadd;100 100', + 'pushbtn2' => '=axial 270|#ccccff;100 0|#ffffff;100 10|#5a5a7a;100 80|#bbbbee;100 100', + 'pushbtn3' => '=radial -15 -15|#ffffff;100 0|#333344;100 100', + 'pushbtn4' => '=axial 270|#ccccff;100 0|#ffffff;100 10|#7a7a9a;100 80|#bbbbee;100 100', + 'pushbtn_edge' => '=axial 140|#ffffff;100 0|#555566;100 100', + 'pushbtn_edge2' => '=axial 92|#ffffff;100 0|#555566;100 100', + 'logoshape' => '=axial 270|#ffffff|#7192aa', + 'logopoint' => '=radial -20 -20|#ffffff 0|#f70000 48|#900000 80|#ab0000 100', + 'logoptshad' => '=path 0 0|#770000;64 0|#770000;70 78|#770000;0 100', + ); + + +# contenu des pages exemples +my %pagesconf = ('Rectangle' => {'consigne' => {-itemtype => 'text', + -coords => [-285, 155], + -params => {-font => $font_9b, + -text => "Mouse button 1 drag objects,\nEscape key reset transfos.", + -color => '#2222cc', + }, + }, + # roudedrectangle simple + radius 20 + 'rr1' => {-itemtype => 'roundedrectangle', + -coords => [[-200, 30], [50, 130]], + -radius => 20, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundrect2', + -linewidth => 2, + -linecolor => '#000000', + -priority => 20, + -tags => ['move'], + }, + }, + + # roudedrectangle 'carré' (radius automatique) + 'rr2' => {-itemtype => 'roundedrectangle', + -coords => [[-250, -100], [-90, 60]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundrect1', + -linewidth => 3, + -linecolor => '#000000', + -priority => 30, + -tags => ['move'], + }, + }, + # cas particulier -> hippodrome (radius = h/2) + 'rr3' => {-itemtype => 'roundedrectangle', + -coords => [[-30, 80], [130, 160]], + -radius => 40, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundrect3', + -linewidth => 4, + -linecolor => '#000000', + -priority => 30, + -tags => ['move'], + }, + }, + + # utilisation de l'option -corners (pétales de fleur) + 'rr4a' => {-itemtype => 'roundedrectangle', + -coords => [[-30, -60], [110, 10]], + -radius => 40, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundrect3', + -linewidth => 3, + -linecolor => '#000000', + -priority => 30, + -tags => ['move'], + }, + -corners => [1, 0, 1, 0], + }, + 'rr4b' => {-itemtype => 'roundedrectangle', + -coords => [[118, -68], [220, -132]], + -radius => 40, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundrect3', + -linewidth => 3, + -linecolor => '#000000', + -priority => 30, + -tags => ['move'], + }, + -corners => [1, 0, 1, 0], + }, + 'rr4c' => {-itemtype => 'roundedrectangle', + -coords => [[118, -60], [190, 30]], + -radius => 40, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundrect3', + -linewidth => 3, + -linecolor => '#000000', + -priority => 30, + -tags => ['move'], + }, + -corners => [0, 1, 0, 1], + }, + 'rr4d' => {-itemtype => 'roundedrectangle', + -coords => [[40, -152], [110, -68]], + -radius => 40, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundrect3', + -linewidth => 3, + -linecolor => '#000000', + -priority => 30, + -tags => ['move'], + }, + -corners => [0, 1, 0, 1], + }, + + # groupe de 2 boutons avec bordure externe + 'gr8' => {-itemtype => 'group', + -coords => [0, 0], + -params => {-priority => 10, + -tags => ['move'], + -atomic => 1, + }, + -items => {'edge' => {-itemtype => 'roundedrectangle', + -coords => [[174, -36],[266, 146]], + -radius => 26, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundrect4ed', + -linewidth => 1, + -linecolor => '#ffffff', + -priority => 20, + }, + }, + 'top' => {-itemtype => 'roundedrectangle', + -coords => [[180, -30], [260, 53]], + -parentgroup => 'gr8', + -radius => 20, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundrect4', + -linewidth => 2.5, + -linecolor => '#000000', + -priority => 30, + }, + -corners => [1, 0, 0, 1], + }, + 'topico' => {-itemtype => 'curve', + -parentgroup => 'gr8', + -coords => [[220, -10],[200, 30],[240, 30]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => '#ffff00;80', + -linewidth => 1, + -linecolor => '#007900;80', + -priority => 50, + }, + }, + 'bottom' => {-itemtype => 'roundedrectangle', + -parentgroup => 'gr8', + -coords => [[180, 57], [260, 140]], + -radius => 20, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundrect4', + -linewidth => 2.5, + -linecolor => '#000000', + -priority => 30, + }, + -corners => [0, 1, 1, 0], + }, + 'bottomico' => {-itemtype => 'curve', + -parentgroup => 'gr8', + -coords => [[220, 120],[240, 80],[200, 80]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => '#ffff00;80', + -linewidth => 1, + -linecolor => '#007900;80', + -priority => 50, + }, + }, + }, + }, + }, + 'Hippodrome' => {'hp1edge' => {-itemtype => 'hippodrome', + -coords => [[-206, -126], [-114, 46]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn_edge', + -linewidth => 1, + -linecolor => '#ffffff', + -priority => 10, + }, + }, + 'hp1' => {-itemtype => 'hippodrome', + -coords => [[-200, -120], [-120, 40]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn1', + -linewidth => 3, + -linecolor => '#000000', + -priority => 20, + }, + }, + + 'hp2edge' => {-itemtype => 'hippodrome', + -coords => [[-86, -126], [6, 46]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn_edge', + -linewidth => 1, + -linecolor => '#ffffff', + -priority => 10, + }, + }, + 'hp2T' => {-itemtype => 'hippodrome', + -coords => [[-80, -120], [0, -68]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn1', + -linewidth => 3, + -linecolor => '#000000', + -priority => 20, + }, + -orientation => 'vertical', + -trunc => 'bottom', + }, + 'hp2C' => {-itemtype => 'hippodrome', + -coords => [[-80, -66.5], [0, -13.5]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn1', + -linewidth => 3, + -linecolor => '#000000', + -priority => 20, + }, + -trunc => 'both', + }, + 'hp2B' => {-itemtype => 'hippodrome', + -coords => [[-80, -12], [0, 40]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn1', + -linewidth => 3, + -linecolor => '#000000', + -priority => 20, + }, + -orientation => 'vertical', + -trunc => 'top', + }, + + 'hp3edge' => {-itemtype => 'hippodrome', + -coords => [[-204, 96], [204, 144]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn_edge2', + -linewidth => 1, + -linecolor => '#ffffff', + -priority => 10, + }, + }, + 'hp3G' => {-itemtype => 'hippodrome', + -coords => [[-200, 100], [-120, 140]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn2', + -linewidth => 2, + -linecolor => '#000000', + -priority => 20, + }, + -trunc => 'right', + }, + 'hp3Gico' => {-itemtype => 'curve', + -coords => [[-180, 120],[-164, 128],[-164, 112]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => '#000000', + -linewidth => 1, + -linecolor => '#aaaaaa', + -relief => 'raised', + -priority => 30, + }, + -contours => [['add',-1,[[-160, 120],[-144, 128],[-144, 112]]]], + }, + + 'hp3C1' => {-itemtype => 'hippodrome', + -coords => [[-118, 100], [-41, 140]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn2', + -linewidth => 2, + -linecolor => '#000000', + -priority => 20, + }, + -trunc => 'both', + }, + 'hp3C1ico' => {-itemtype => 'curve', + -coords => [[-88, 120],[-72, 128],[-72, 112]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => '#000000', + -linewidth => 1, + -linecolor => '#aaaaaa', + -priority => 30, + -relief => 'raised', + }, + }, + + 'hp3C2' => {-itemtype => 'hippodrome', + -coords => [[-39, 100], [39, 140]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn2', + -linewidth => 2, + -linecolor => '#000000', + -priority => 20, + }, + -trunc => 'both', + }, + 'hp3C2ico' => {-itemtype => 'rectangle', + -coords => [[-6, 114],[6, 126]], + -params => {-filled => 1, + -fillcolor => '#000000', + -linewidth => 1, + -linecolor => '#aaaaaa', + -priority => 30, + }, + }, + 'hp3C3' => {-itemtype => 'hippodrome', + -coords => [[41, 100], [118, 140]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn2', + -linewidth => 2, + -linecolor => '#000000', + -priority => 20, + }, + -trunc => 'both', + }, + 'hp3C3ico' => {-itemtype => 'curve', + -coords => [[88, 120],[72, 112],[72, 128]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => '#000000', + -linewidth => 1, + -linecolor => '#aaaaaa', + -priority => 30, + -relief => 'raised', + }, + }, + + 'hp3D' => {-itemtype => 'hippodrome', + -coords => [[120, 100], [200, 140]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn2', + -linewidth => 2, + -linecolor => '#000000', + -priority => 20, + }, + -trunc => 'left', + }, + 'hp3Dico' => {-itemtype => 'curve', + -coords => [[180, 120],[164, 112],[164, 128]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => '#000000', + -linewidth => 1, + -linecolor => '#aaaaaa', + -priority => 30, + -relief => 'raised', + }, + -contours => [['add',-1,[[160, 120],[144, 112],[144, 128]]]], + }, + + 'hp4aedge' => {-itemtype => 'hippodrome', + -coords => [[27, -126], [85, -68]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn_edge', + -linewidth => 1, + -linecolor => '#ffffff', + -priority => 20, + }, + }, + 'hp4a' => {-itemtype => 'hippodrome', + -coords => [[32, -121], [80, -73]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn3', + -linewidth => 3, + -linecolor => '#000000', + -priority => 30, + }, + }, + 'hp4bedge' => {-itemtype => 'hippodrome', + -coords => [[94, -126], [206, -14]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn_edge', + -linewidth => 1, + -linecolor => '#ffffff', + -priority => 20, + }, + }, + 'hp4b' => {-itemtype => 'hippodrome', + -coords => [[102, -118], [198, -22]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn3', + -linewidth => 3, + -linecolor => '#000000', + -priority => 30, + }, + }, + 'hp5aedge' => {-itemtype => 'hippodrome', + -coords => [[-19, -34], [19, 34]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn_edge', + -linewidth => 1, + -linecolor => '#ffffff', + -priority => 10, + }, + -rotate => 30, + -translate => [45, 30], + }, + 'hp5a' => {-itemtype => 'hippodrome', + -coords => [[-15, -30], [15, 30]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn1', + -linewidth => 2, + -linecolor => '#000000', + -priority => 20, + }, + -rotate => 30, + -translate => [45, 30], + }, + 'hp5bedge' => {-itemtype => 'hippodrome', + -coords => [[-19, -34], [19, 34]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn_edge', + -linewidth => 1, + -linecolor => '#ffffff', + -priority => 10, + }, + -rotate => 30, + -translate => [90, 30], + }, + 'hp5b' => {-itemtype => 'hippodrome', + -coords => [[-15, -30], [15, 30]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn1', + -linewidth => 2, + -linecolor => '#000000', + -priority => 20, + }, + -rotate => 30, + -translate => [90, 30], + }, + + 'hp5cedge' => {-itemtype => 'hippodrome', + -coords => [[-19, -34], [19, 34]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn_edge', + -linewidth => 1, + -linecolor => '#ffffff', + -priority => 10, + }, + -rotate => 30, + -translate => [135, 30], + }, + 'hp5c' => {-itemtype => 'hippodrome', + -coords => [[-15, -30], [15, 30]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn1', + -linewidth => 2, + -linecolor => '#000000', + -priority => 20, + }, + -rotate => 30, + -translate => [135, 30], + }, + + 'hp5dedge' => {-itemtype => 'hippodrome', + -coords => [[-19, -34], [19, 34]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn_edge', + -linewidth => 1, + -linecolor => '#ffffff', + -priority => 10, + }, + -rotate => 30, + -translate => [180, 30], + }, + 'hp5d' => {-itemtype => 'hippodrome', + -coords => [[-15, -30], [15, 30]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn1', + -linewidth => 2, + -linecolor => '#000000', + -priority => 20, + }, + -rotate => 30, + -translate => [180, 30], + }, + + }, + + 'Polygone' => {'triangle' => {-itemtype => 'polygone', + -coords => [-210, -90], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundpolyg', + -linewidth => 2, + -linecolor => '#330000', + -priority => 20, + }, + -numsides => 3, + -radius => 78, + -corner_radius => 10, + -startangle => 90, + }, + 'text1' => {-itemtype => 'text', + -coords => [-210, -90], + -params => {-font => $font_9b, + -text => "Triangle", + -anchor => 'center', + -alignment => 'center', + -color => '#660000', + -priority => 50, + }, + }, + 'carre' => {-itemtype => 'polygone', + -coords => [-80, -70], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundpolyg', + -linewidth => 2, + -linecolor => '#330000', + -priority => 20, + }, + -numsides => 4, + -radius => 70, + -corner_radius => 10, + -startangle => 90, + }, + + 'text2' => {-itemtype => 'text', + -coords => [-80, -70], + -params => {-font => $font_9b, + -text => 'Carré', + -anchor => 'center', + -alignment => 'center', + -color => '#660000', + -priority => 50, + }, + }, + 'pentagone' => {-itemtype => 'polygone', + -coords => [65, -70], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundpolyg', + -linewidth => 2, + -linecolor => '#330000', + -priority => 20, + }, + -numsides => 5, + -radius => 70, + -corner_radius => 10, + -startangle => 270, + }, + + 'text3' => {-itemtype => 'text', + -coords => [65, -70], + -params => {-font => $font_9b, + -text => 'Pentagone', + -anchor => 'center', + -alignment => 'center', + -color => '#660000', + -priority => 50, + }, + }, + + 'hexagone' => {-itemtype => 'polygone', + -coords => [210, -70], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundpolyg', + -linewidth => 2, + -linecolor => '#330000', + -priority => 20, + }, + -numsides => 6, + -radius => 68, + -corner_radius => 10, + }, + 'text4' => {-itemtype => 'text', + -coords => [210, -70], + -params => {-font => $font_9b, + -text => 'Hexagone', + -anchor => 'center', + -alignment => 'center', + -color => '#660000', + -priority => 50, + }, + }, + 'heptagone' => {-itemtype => 'polygone', + -coords => [-215, 90], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundpolyg', + -linewidth => 2, + -linecolor => '#330000', + -priority => 20, + }, + -numsides => 7, + -radius => 64, + -corner_radius => 10, + }, + 'text5' => {-itemtype => 'text', + -coords => [-215, 90], + -params => {-font => $font_9b, + -text => 'Heptagone', + -anchor => 'center', + -alignment => 'center', + -color => '#660000', + -priority => 50, + }, + }, + 'octogone' => {-itemtype => 'polygone', + -coords => [-76, 90], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundpolyg', + -linewidth => 2, + -linecolor => '#330000', + -priority => 20, + }, + -numsides => 8, + -radius => 64, + -corner_radius => 10, + }, + 'text6' => {-itemtype => 'text', + -coords => [-76, 90], + -params => {-font => $font_9b, + -text => 'Octogone', + -anchor => 'center', + -alignment => 'center', + -color => '#660000', + -priority => 50, + }, + }, + + 'petagone' => {-itemtype => 'polygone', + -coords => [66, 90], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundpolyg', + -linewidth => 2, + -linecolor => '#330000', + -priority => 20, + }, + -numsides => 32, + -radius => 64, + -corner_radius => 10, + }, + 'text7' => {-itemtype => 'text', + -coords => [66, 90], + -params => {-font => $font_9b, + -text => '32 cotés...', + -anchor => 'center', + -alignment => 'center', + -color => '#660000', + -priority => 50, + }, + }, + 'etoile' => {-itemtype => 'polygone', + -coords => [210, 90], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundpolyg', + -linewidth => 2, + -linecolor => '#330000', + -priority => 20, + }, + -numsides => 5, + -radius => 92, + -inner_radius => 36, + -corner_radius => 10, + -startangle => 270, + -corners => [1,0,1,0,1,0,1,0,1,0], + }, + 'text8' => {-itemtype => 'text', + -coords => [210, 90], + -params => {-font => $font_9b, + -text => 'Etoile', + -anchor => 'center', + -alignment => 'center', + -color => '#660000', + -priority => 50, + }, + }, + }, + + 'Polyline' => {'consigne' => {-itemtype => 'text', + -coords => [-285, 155], + -params => {-font => $font_9b, + -text => "Mouse button 1 drag objects,\nEscape key reset transfos.", + -color => '#2222cc', + }, + }, + 'a' => {-itemtype => 'polyline', + -coords => [[-200, -115],[-200, -100],[-218, -115],[-280, -115],[-280, -16], + [-218, -16],[-200, -31],[-200, -17.5],[-150, -17.5],[-150,-115]], + -corners_radius => [0, 0, 42, 47, 47, 42, 0, 0, 0, 0, 0, 0], + -params => {-closed => 1, + -filled => 1, + -visible => 1, + -fillcolor => 'rpolyline', + -linewidth => 2, + -linecolor => '#000000', + -priority => 50, + -tags => ['move'], + }, + -contours => [['add', -1, [[-230, -80],[-230, -50],[-200, -50],[-200, -80]],15]], + }, + 'b' => {-itemtype => 'polyline', + -coords => [[-138, -150],[-138, -17.5],[-88, -17.5],[-88, -31],[-70, -16], + [-8, -16],[-8, -115],[-70, -115],[-88, -100],[-88, -150]], + -corners_radius => [0, 0, 0, 0, 42, 47, 47, 42, 0, 0, 0, 0, 0, 0], + -params => {-closed => 1, + -filled => 1, + -visible => 1, + -fillcolor => 'rpolyline', + -linewidth => 2, + -linecolor => '#000000', + -priority => 50, + -tags => ['move'], + }, + -contours => [['add', -1, [[-88, -80],[-88, -50],[-58, -50],[-58, -80]],15]], + }, + 'c' => {-itemtype => 'polyline', + -coords => [[80, -76],[80, -110],[60, -115],[0, -115],[0, -16], + [60, -16],[80, -21],[80, -57],[50, -47],[50, -86]], + -corners_radius => [0, 0, 70, 47, 47, 70, 0, 0, 14, 14, 0, 0, 0,0 ], + -params => {-closed => 1, + -filled => 1, + -visible => 1, + -fillcolor => 'rpolyline', + -linewidth => 2, + -linecolor => '#000000', + -priority => 50, + -tags => ['move'], + }, + }, + 'spirale' => {-itemtype => 'polyline', + -coords => [[215, -144],[139, -144],[139, 0],[268, 0],[268, -116], + [162.5, -116],[162.5, -21],[248, -21],[248, -96],[183, -96], + [183, -40],[231,-40],[231, -80],[199, -80],[199, -55],[215, -55]], + -corners_radius => [0, 76, 68, 61, 55, 50, 45, 40, 35, 30, 26, 22, 18, 14, 11], + -params => {-closed => 1, + -filled => 1, + -visible => 1, + -fillcolor => 'rpolyline', + -linewidth => 2, + -linecolor => '#000000', + -priority => 50, + -tags => ['move'], + }, + }, + 'logo' => {-itemtype => 'group', + -coords => [0, 0], + -params => {-priority => 30, + -atomic => 1, + -tags => ['move'], + }, + -items => {'tkzinc' => {-itemtype => 'polyline', + -coords => [[-150,10],[-44,10],[-44,68],[-28,51],[6,51], + [-19,79],[3,109],[53,51],[5,51],[5,10],[140,10], + [52,115],[96,115],[96,47],[196,47],[196,158], + [155,158],[155,89],[139,89],[139,160],[101, 160], + [101,132],[85,132],[85,160],[-42,160],[-2,115], + [-30,115],[-46,91],[-46,115],[-76,115],[-76,51], + [-98,51],[-98,115],[-130,115],[-130,51],[-150, 51]], + -corners_radius => [0,0,0,0,0,0,0,0,0,0,30,0,0,50,50, + 0,0,8,8,0,0,8,8,0,27], + -params => {-closed => 1, + -filled => 1, + -visible => 1, + -fillcolor => 'logoshape', + -linewidth => 2.5, + -linecolor => '#000000', + -priority => 10, + -fillrule => 'nonzero', + }, + -contours => [['add',1,[[245,88],[245,47],[190,47],[190,158], + [259,158],[259,117],[230,117],[230,88]], + 0, undef, [0,0,55,55,0,0,15,15]]], + }, + 'shad' => {-itemtype => 'arc', + -coords => [[75, 91],[115,131]], + -params => {-priority => 20, + -filled => 1, + -linewidth => 0, + -fillcolor => 'logoptshad', + -closed => 1, + }, + }, + 'point' => {-itemtype => 'arc', + -coords => [[70, 86],[110,126]], + -params => {-priority => 50, + -filled => 1, + -linewidth => 1, + -linecolor => '#a10000', + -fillcolor => 'logopoint', + -closed => 1, + }, + }, + }, + }, + }, + + 'MultiContours' => {'consigne' => {-itemtype => 'text', + -coords => [-285, 155], + -params => {-font => $font_9b, + -text => "Mouse button 1 drag objects,\nEscape key reset transfos.", + -color => '#2222cc', + }, + }, + 'mc1' => {-itemtype => 'roundedcurve', + -coords => [[-30, -170], [-130, 0],[70, 0]], + -radius => 14, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundcurve2', + -linewidth => 1, + -linecolor => '#000000', + -priority => 20, + -tags => ['move'], + -fillrule => 'odd', + }, + -contours => [['add',1,[[-30,-138],[-100,-18],[40,-18]],8], + ['add',1,[[-30,-130],[ -92,-22],[32,-22]],5], + ['add',1,[[-30,-100],[ -68,-36],[8,-36]],5], + ['add',1,[[-30, -92],[ -60,-40],[0,-40]],3],], + }, + 'mc2' => {-itemtype => 'polyline', + -coords => [[-250,-80], [-240,-10],[-285,-10],[-285,80], + [-250, 80],[-250, 40],[-170, 40],[-170,80], + [-100,80],[-100,40],[-20,40],[-20,80],[30,80], + [-10, 0],[-74, -10],[-110, -80]], + -corners_radius => [24,4, 40, 20, 0, 40, 40, 0, 0, 40, 40, 0, 30, 75, 0, 104], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundcurve1', + -linewidth => 2, + -linecolor => '#000000', + -priority => 30, + -tags => ['move'], + }, + -contours => [['add',-1,[[-240,-72],[-230,0],[-169,0],[-185, -72]], + 0, undef, [16, 16, 0, 0]], + ['add', -1, [[-175,-72],[-159,0],[-78,0],[-116, -72]], + 0, undef, [0, 0, 8, 88]], + ['add', 1, [[-245,45],[-245,115],[-175,115],[-175, 45]], + 35], + ['add', -1, [[-225,65],[-225,95],[-195,95],[-195, 65]], + 15], + ['add', 1, [[-95,45],[-95,115],[-25,115],[-25, 45]], + 35], + ['add', -1, [[-75,65],[-75,95],[-45,95],[-45, 65]], + 15], + ], + }, + 'mc3' => {-itemtype => 'roundedcurve', + -coords => [[-10, 170], [256, 170],[312, 60],[48, 60]], + -radius => 34, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundcurve2', + -linewidth => 2.5, + -linecolor => '#000000', + -priority => 40, + -tags => ['move'], + }, + -contours => [['add', -1, [[58, 62],[12, 144],[60, 172],[104, 88]],27], + ['add', 1, [[48, 77],[48, 119],[90, 119],[90, 77]],21], + ['add', -1, [[244, 58],[198, 140],[246, 168],[290, 84]],27], + ['add', 1, [[213, 110],[213, 152],[255, 152],[255, 110]],21], + ['add', -1, [[150, 60],[150, 170],[160, 170],[160, 60]],0]], + }, + 'mc4' => {-itemtype => 'roundedcurve', + -coords => [[222, -150],[138, -150],[180, -50],[138, -150], + [80, -92],[180, -50],[80, -92],[80, -8], + [180, -50],[80, -8],[138, 50],[180, -50], + [138, 50],[222, 50],[179.8, -50],[222, 50], + [280, -8],[180, -50],[280, -8],[280, -92], + [180, -50],[280, -92],[222,-150],[180,-50]], + -radius => 28, + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'roundcurve', + -linewidth => 2, + -linecolor => '#000000', + -priority => 30, + -tags => ['move'], + }, + -contours => [['add', -1, [[160, -70],[160, -30],[200, -30],[200, -70]],20]], + }, + }, + + 'TabBox' => {'bo1' => {-itemtype => 'tabbox', + -coords => [[-240, -140], [240, 120]], + -radius => 8, + -tabwidth => 72, + -tabheight => 28, + -numpages => 8, + -anchor => 'n', + -alignment => 'left', + -overlap => 3, + -tabtitles => ['A', 'B', 'C', 'D', 'E', 'F','G','H'], + -params => {-closed => 1, + -priority => 100, + -filled => 1, + -fillcolor => '#ffffff', + -linewidth => 1.2, + -linecolor => '#000000', + -tags => ['div2', 'divider', 'intercalaire'], + }, + }, + + 'back' => {-itemtype => 'roundedrectangle', + -coords => [[-242, -142], [242, 122]], + -radius => 10, + -params => {-closed => 1, + -filled => 1, + -fillcolor => '#777777;80', + -linewidth => 1, + -linecolor => '#777777;80', + }, + }, + + 'anchor' => {-itemtype => 'text', + -coords => [-120, 138], + -params => {-text => 'tabs anchor', + -color => '#2222cc', + -font => $font_9b, + -anchor => 'center', + -alignment => 'center', + -priority => 40, + }, + }, + + 'anchorN' => {-itemtype => 'hippodrome', + -coords => [[-210, 150], [-165, 176]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn4', + -linewidth => 1.5, + -linecolor => '#000000', + -priority => 20, + -tags => ['sel1','n','btn','selector'], + }, + -trunc => 'right', + }, + 'txtanN' => {-itemtype => 'text', + -coords => [-187, 163], + -params => {-text => 'N', + -color => '#000000', + -font => $font_9b, + -anchor => 'center', + -alignment => 'center', + -priority => 40, + -tags => ['sel1','n','btntext','selector'], + }, + }, + + 'anchorE' => {-itemtype => 'hippodrome', + -coords => [[-163, 150], [-120, 176]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn4', + -linewidth => 1.5, + -linecolor => '#000000', + -priority => 20, + -tags => ['sel1','e','btn','selector'], + }, + -trunc => 'both', + }, + 'txtanE' => {-itemtype => 'text', + -coords => [-141.5, 163], + -params => {-text => 'E', + -color => '#000000', + -font => $font_9b, + -anchor => 'center', + -alignment => 'center', + -priority => 40, + -tags => ['sel1','e','btntext','selector'], + }, + }, + + 'anchorS' => {-itemtype => 'hippodrome', + -coords => [[-118, 150], [-75, 176]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn4', + -linewidth => 1.5, + -linecolor => '#000000', + -priority => 20, + -tags => ['sel1','s','btn','selector'], + }, + -trunc => 'both', + }, + 'txtanS' => {-itemtype => 'text', + -coords => [-96.5, 163], + -params => {-text => 'S', + -color => '#000000', + -font => $font_9b, + -anchor => 'center', + -alignment => 'center', + -priority => 40, + -tags => ['sel1','s','btntext','selector'], + }, + }, + 'anchorW' => {-itemtype => 'hippodrome', + -coords => [[-73, 150], [-28, 176]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn4', + -linewidth => 1.5, + -linecolor => '#000000', + -priority => 20, + -tags => ['sel1','w','btn','selector'], + }, + -trunc => 'left', + }, + 'txtanW' => {-itemtype => 'text', + -coords => [-52, 163], + -params => {-text => 'W', + -color => '#000000', + -font => $font_9b, + -anchor => 'center', + -alignment => 'center', + -priority => 40, + -tags => ['sel1','w','btntext','selector'], + }, + }, + 'alignment' => {-itemtype => 'text', + -coords => [120, 138], + -params => {-text => 'tabs alignment', + -color => '#2222cc', + -font => $font_9b, + -anchor => 'center', + -alignment => 'center', + -priority => 40, + }, + }, + 'alignG' => {-itemtype => 'hippodrome', + -coords => [[30, 150], [90, 176]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn4', + -linewidth => 1.5, + -linecolor => '#000000', + -priority => 20, + -tags => ['sel2','left','btn','selector'], + }, + -trunc => 'right', + }, + 'txtalG' => {-itemtype => 'text', + -coords => [60, 163], + -params => {-text => 'left', + -color => '#000000', + -font => $font_9b, + -anchor => 'center', + -alignment => 'center', + -priority => 40, + -tags => ['sel2','left','btntext','selector'], + }, + }, + 'alignC' => {-itemtype => 'hippodrome', + -coords => [[92, 150], [148, 176]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn4', + -linewidth => 1.5, + -linecolor => '#000000', + -priority => 20, + -tags => ['sel2','center','btn','selector'], + }, + -trunc => 'both', + }, + 'txtalC' => {-itemtype => 'text', + -coords => [120, 163], + -params => {-text => 'center', + -color => '#000000', + -font => $font_9b, + -anchor => 'center', + -alignment => 'center', + -priority => 40, + -tags => ['sel2','center','btntext','selector'], + }, + }, + 'alignD' => {-itemtype => 'hippodrome', + -coords => [[150, 150], [210, 176]], + -params => {-closed => 1, + -filled => 1, + -fillcolor => 'pushbtn4', + -linewidth => 1.5, + -linecolor => '#000000', + -priority => 20, + -tags => ['sel2','right','btn','selector'], + }, + -trunc => 'left', + }, + 'txtalD' => {-itemtype => 'text', + -coords => [180, 163], + -params => {-text => 'right', + -color => '#000000', + -font => $font_9b, + -anchor => 'center', + -alignment => 'center', + -priority => 40, + -tags => ['sel2','right','btntext','selector'], + }, + }, + }, + + 'PathLine' => {'consigne' => {-itemtype => 'text', + -coords => [-285, 155], + -params => {-font => $font_9b, + -text => "Mouse button 1 drag objects,\nEscape key reset transfos.", + -color => '#2222cc', + }, + }, + 'pl1' => {-itemtype => 'pathline', + -metacoords => {-type => 'polygone', + -coords => [0, 0], + -numsides => 12, + -radius => 200, + -inner_radius => 100, + -startangle => -8, + }, + -linewidth => 20, + -closed => 1, + -graduate => {-type => 'linear', + -colors => ['#ff0000', '#ff00ff', '#0000ff', '#00ffff', + '#00ff00', '#ffff00', '#ff0000'], + }, + -params => {-priority => 100, + -tags => ['move'], + }, + }, + + 'pl2' => {-itemtype => 'group', + -coords => [0, 0], + -params => {-priority => 200, + -atomic => 1, + -tags => ['move'], + }, + -items => {'in' => {-itemtype => 'pathline', + -coords => [[30, -60],[-30, -60],[-30, -30], + [-60, -30],[-60, 30],[-30, 30], + [-30, 60],[30, 60],[30, 30], + [60, 30],[60, -30],[30, -30]], + -linewidth => 16, + -closed => 1, + -shifting => 'left', + -graduate => {-type => 'transversal', + -colors => ['#00aa77;100', '#00aa77;0'], + }, + -params => {-priority => 10, + }, + }, + + 'out' => {-itemtype => 'pathline', + -coords => [[30, -60],[-30, -60],[-30, -30], + [-60, -30],[-60, 30],[-30, 30], + [-30, 60],[30, 60],[30, 30], + [60, 30],[60, -30],[30, -30]], + -linewidth => 10, + -closed => 1, + -shifting => 'right', + -graduate => {-type => 'transversal', + -colors => ['#00aa77;100', '#00aa77;0'], + }, + -params => {-priority => 10, + }, + }, + }, + }, + + 'pl3' => {-itemtype => 'group', + -coords => [0, 0], + -params => {-priority => 100, + -atomic => 1, + -tags => ['move'], + }, + -items => {'back' => {-itemtype => 'arc', + -coords => [[-150, -150],[150,150]], + -params => {-priority => 10, + -closed => 1, + -filled => 1, + -fillcolor => '=radial 15 15|#ffffff;40|#aaaaff;10', + -linewidth => 0, + }, + }, + 'light' => {-itemtype => 'pathline', + -metacoords => {-type => 'polygone', + -coords => [0, 0], + -numsides => 30, + -radius => 150, + -startangle => 240, + }, + -linewidth => 20, + -shifting => 'right', + -closed => 1, + -graduate => {-type => 'double', + -colors => [['#ffffff;0', '#222299;0', '#ffffff;0'], + ['#ffffff;100', '#222299;70', '#ffffff;100']], + }, + -params => {-priority => 50, + }, + }, + 'bord' => {-itemtype => 'arc', + -coords => [[-150, -150],[150,150]], + -params => {-priority => 100, + -closed => 1, + -filled => 0, + -linewidth => 2, + -linecolor => '#000033;80' + }, + }, + + }, + }, + }, + + ); + +my %tabtable = ('n' => {-numpages => 8, + -titles => ['A','B','C','D','E','F','G','H'], + -names => ['Avant Garde','Bodini','Clarendon','Didot', + 'Eras','Frutiger','Garamond','Helvetica'], + -images => ['avantgarde.gif','bodini.gif','clarendon.gif','didot.gif', + 'eras.gif','frutiger.gif','garamond.gif','helvetica.gif'], + }, + 'e' => {-numpages => 5, + -titles => ['I','J','K','L','M'], + -names => ['Impact','Jenson','Kabel','Lubalin Graph','Matura'], + -images => ['impact.gif','jenson.gif','kabel.gif','lubalingraph.gif','matura.gif'], + }, + 's' => {-numpages => 8, + -titles => ['N','O','P','Q','R','S','T','U'], + -names => ['New Century Scoolbook','Optima','Peignot','Quorum', + 'Revue','Souvenir','Times New Roman', 'Univers'], + -images => ['newcenturyscoolbook.gif','optima.gif','peignot.gif','quorum.gif', + 'revue.gif','souvenir.gif','timesnewroman.gif','univers.gif'], + }, + 'w' => {-numpages => 5, + -titles => ['V','W','X','Y','Z'], + -names => ['Veljovic','Warnock','X-files','Yellow Submarine','zapf Chancery'], + -images => ['veljovic.gif','warnock.gif','xfiles.gif','yellowsubmarine.gif','zapfchancery.gif'], + }, + ); + + + +# creation de la fenetre principale +my $mw = MainWindow->new(); +$mw->geometry("700x560+0+0"); +$mw->title('Test Graphics Module'); + + +# creation du widget Zinc +my $zinc = $mw->Zinc(-render => 1, + -width => 700, + -height => 560, + -borderwidth => 0, + -lightangle => 140, + -borderwidth => 0, + -backcolor => '#cccccc',); +$zinc->pack(-fill => 'both', -expand => 1); + + +# initialise les gradiants nommés +&setGradiants($zinc, \%gradset); + +# initialise les images de fontes +while (my ($anchor, $table) = each(%tabtable)) { + my @images; + foreach my $filename (@{$table->{'-images'}}) { + my $image = $zinc->Photo(-file => Tk::findINC($filename)); + push(@images, $image); + } + $tabtable{$anchor}->{'-images'} = \@images; +} + +# création de la vue principale +my $tgroup = $zinc->add('group', 1); +$zinc->coords($tgroup, [350, 240]); + +# consigne globale +$zinc->add('text', 1, + -position => [50, 470], + -text => "Global interations :\n, , and keys move content of TabBox pages\n and keys zoom out and zoom in this page\n and keys rotate this page\n key reset transfos", + -font => $font_9b, + -color => '#555555', + -spacing => 2, + ); + +# Création des pages d'exemples +my ($shapes, $tcoords) = &TabBoxCoords([[-315, -210],[315, 210]], + -numpages => 7, + -overlap => 2, + -radius => 8, + -tabheight => 26, + -tabwidth => [92,100,82,82,82,120,80], + ); + +# to find some images (used as textures) needed by this demo +push @INC , Tk->findINC('demos/zinc_data'); +#print "image_path=$image_path\n"; +my $texture = $zinc->Photo(-file => Tk::findINC('paper.gif')); + +# création des items zinc correspondants +my $i = scalar(@{$shapes}) - 1; +my @pagenames = ('Rectangle', 'Hippodrome', 'Polygone', 'Polyline', 'PathLine', 'MultiContours', 'TabBox'); +my @pagegroups; +foreach my $shape (reverse @{$shapes}) { + my $divgroup = $zinc->add('group', $tgroup); + + # création de l'intercalaire + my $divider = $zinc->add('curve', $divgroup, + $shape, + -closed => 1, + -priority => 10, + -linewidth => 1, + -linecolor => '#000000', + -filled => 1, + -tile => $texture, + -tags => ['div1', $i, 'divider', 'intercalaire'], + ); + + # groupe page clippé + my $page = $zinc->add('group', $divgroup, + -priority => 100, + -tags => ['div1', $i, 'page'], + ); + my $clip = $zinc->add('rectangle', $page, + [[-300, -170],[300, 195]], + -linewidth => 1, + -linecolor => '#000099', + -filled => 1, + -fillcolor => '#000000;4', + ); + $zinc->itemconfigure($page, -clip => $clip); + + my $pgroup = $zinc->add('group', $page, + -tags => ['div1', $i, 'content'], + ); + + push(@pagegroups, $pgroup); + + # titre de l'intercalaire + $zinc->add('text', $divgroup, + -position => $tcoords->[$i], + -text => $pagenames[$i], + -font => $font_9b, + -alignment => 'center', + -anchor => 'center', + -color => '#000099', + -priority => 200, + -tags => ['div1', $i, 'divider','titre'], + ); + $i--; +} + +# création du contenu des pages +my $i = 0; +foreach my $pagename (reverse @pagenames) { + my $pagestyle = $pagesconf{$pagename}; + if ($pagestyle) { + my $pgroup = $pagegroups[$i]; + while (my ($itemname, $itemstyle) = each(%{$pagestyle})) { + if ($itemstyle->{'-itemtype'} eq 'tabbox') { + &buildTabBox($zinc, $pgroup, $itemstyle, $itemname); + + } else { + if ($itemstyle->{'-itemtype'} eq 'group') { + my $subgroup = &buildZincItem($zinc, $pgroup, $itemstyle, undef, $itemname); + while (my ($name, $style) = each(%{$itemstyle->{'-items'}})) { + &buildZincItem($zinc, $subgroup, $style, undef, $name); + } + } else { + my $group = ($itemname eq 'consigne') ? $zinc->group($pgroup) : $pgroup; + &buildZincItem($zinc, $group, $itemstyle, undef, $itemname); + } + } + } + } + $i++; +} + +&clickSelector('sel1','n'); +&clickSelector('sel2','left'); +&selectDivider('div1', 0); + +&setBindings; + + +MainLoop; +#----------------------------------------------------------------------- fin de MAIN + + +sub setBindings { + # grab keyboard + $mw->Tk::focus(); + + # plus,moins : Zoom++, Zoom-- + $mw->Tk::bind('', sub {viewZoom('up');}); + $mw->Tk::bind('', sub {viewZoom('down');}); + + # Up, Down, Right, Left : Translate + $mw->Tk::bind('', sub {viewTranslate('up');}); + $mw->Tk::bind('', sub {viewTranslate('down');}); + $mw->Tk::bind('', sub {viewTranslate('left');}); + $mw->Tk::bind('', sub {viewTranslate('right');}); + + + # >, < : Rotate counterclockwise et clockwise + $mw->Tk::bind('', sub {viewRotate('cw');}); + $mw->Tk::bind('', sub {viewRotate('ccw');}); + + # Escape : reset transfos + $mw->Tk::bind('', sub {$zinc->treset('move'); + $zinc->raise('move'); + $zinc->treset($curview);}); + + $zinc->bind('divider', '<1>', sub {&selectDivider();}); + + $zinc->bind('selector', '<1>', sub {&clickSelector();}); + + $zinc->bind('move', '<1>', sub {&mobileStart();}); + $zinc->bind('move', '', sub {&mobileMove();}); + $zinc->bind('move', '', sub {&mobileStop();}); +} + + +sub selectDivider { + my ($divname, $numpage) = @_; + if (!defined $divname) { + my @tags = $zinc->itemcget('current', -tags); + $divname = $tags[0]; + $numpage = $tags[1]; + } + + $zinc->itemconfigure("($divname && titre)", -color => '#000099'); + $zinc->itemconfigure("($divname && intercalaire)", -linewidth => 1.4); + $zinc->itemconfigure("($divname && page)", -visible => 0); + + my $divgroup = $zinc->group("($divname && $numpage)"); + $zinc->raise($divgroup); + $curview = "($divname && $numpage && content)"; + $zinc->itemconfigure("($divname && $numpage && titre)", -color => '#000000'); + $zinc->itemconfigure("($divname && $numpage && intercalaire)", -linewidth => 2); + $zinc->itemconfigure("($divname && $numpage && page)", -visible => 1); + + if ($divname eq 'div2') { + my $fontname = $tabtable{$tabanchor}->{'-names'}->[$numpage]; + my $fontimage = $tabtable{$tabanchor}->{'-images'}->[$numpage]; + $zinc->itemconfigure("($divname && fontname)", -text => $fontname); + $zinc->raise("($divname && fontname)"); + $zinc->itemconfigure("($divname && fontimage)", -image => $fontimage); + $zinc->raise("($divname && fontimage)"); + } +} + + +sub clickSelector { + my ($btngroup, $value) = @_; + + if (!defined $btngroup and !defined $value) { + my @tags = $zinc->itemcget('current', -tags); + $btngroup = $tags[0]; + $value = $tags[1]; + } + + $zinc->treset($btngroup); + $zinc->itemconfigure("($btngroup && btntext)", -color => '#444444'); + $zinc->itemconfigure("($btngroup && $value && btntext)", -color => '#2222bb'); + $zinc->translate("($btngroup && $value)", 0, 1); + + if ($value eq 'n' or $value eq 'e' or $value eq 's' or $value eq 'w') { + $tabanchor = $value; + + } elsif ($value eq 'left' or $value eq 'center' or $value eq 'right') { + $tabalign = $value; + } + + my $tabtable = $tabtable{$tabanchor}; + my $numpages = $tabtable->{'-numpages'}; + my %tabparams = (-radius => 8, + -tabwidth => 72, + -tabheight => 28, + -numpages => $numpages, + -anchor => $tabanchor, + -alignment => $tabalign, + -overlap => 3, + ); + + my ($shapes, $tcoords) = &TabBoxCoords([[-240, -140], [240, 120]], %tabparams); + + for (my $index = 7; $index >= 0; $index--) { + my $divgroup = $zinc->group("(div2 && $index && intercalaire)"); + $zinc->itemconfigure($divgroup, -visible => ($index < $numpages)); + + if ($index >= $numpages) { + $zinc->lower($divgroup); + + } else { + $zinc->raise($divgroup); + $zinc->itemconfigure("(div2 && $index)", -visible => 1); + $zinc->coords("(div2 && $index && intercalaire)", $shapes->[$index]); + $zinc->coords("(div2 && $index && titre)", $tcoords->[$index]); + $zinc->itemconfigure("(div2 && $index && titre)", -text => $tabtable->{'-titles'}->[$index]); + } + + } + + &selectDivider('div2', 0); +} + + +#----------------------------------------------------------------------------------- +# Callback CATCH de sélection (début de déplacement) des items tagés 'move' +#----------------------------------------------------------------------------------- +sub mobileStart { + my $ev = $zinc->XEvent; + ($dx, $dy) = (0 - $ev->x, 0 - $ev->y); + + $zinc->raise('current'); + +} + + +#----------------------------------------------------------------------------------- +# Callback MOVE de déplacement des items tagés 'move' +#----------------------------------------------------------------------------------- +sub mobileMove { + my $ev = $zinc->XEvent; + $zinc->translate('current', $ev->x + $dx, $ev->y +$dy); + ($dx, $dy) = (0 - $ev->x, 0 - $ev->y); + +} + + +#----------------------------------------------------------------------------------- +# Callback RELEASE de relaché (fin de déplacement) des items tagés 'move' +#----------------------------------------------------------------------------------- +sub mobileStop { + &mobileMove; +} + + +sub viewTranslate { + my $way = shift; + + my $dx = ($way eq 'left') ? -10 : ($way eq 'right') ? 10 : 0; + my $dy = ($way eq 'up') ? -10 : ($way eq 'down') ? 10 : 0; + + $zinc->translate($curview, $dx, $dy); + +} + +sub viewZoom { + my $key = shift; + my $scaleratio = ($key eq 'up') ? 1+$zoomfactor : 1-$zoomfactor; + + $zinc->scale($curview, $scaleratio, $scaleratio); + +} + +sub viewRotate { + my $way = shift; + my $delta_angle = $rotate_angle; + + $delta_angle *= -1 if ($way eq 'cw'); + + $zinc->rotate($curview, $delta_angle); + +} + + + + +sub buildTabBox { + my ($zinc, $parentgroup, $style, $name) = @_; + my $params = delete $style->{'-params'}; + my @tags = @{$params->{'-tags'}}; + my $coords = delete $style->{'-coords'}; + my $table = $tabtable{$style->{'-anchor'}}; + my $titles = $style->{'-tabtitles'}; + my ($shapes, $tcoords, $invert) = &TabBoxCoords($coords, %{$style}); + my $k = ($invert) ? scalar @{$shapes} : -1; + foreach my $shape (reverse @{$shapes}) { + $k += ($invert) ? -1 : +1; + my $group = $zinc->add('group', $parentgroup); + $params->{'-tags'} = [$tags[0], $k, $tags[1], 'intercalaire']; + $zinc->add('curve', $group, $shape, %{$params}); + + if ($style->{'-page'}) { + &buildZincItem($zinc, $group, $style->{'-page'}); + } + + my $tindex = ($invert) ? $k : $#{$shapes} - $k; + if ($titles) { + my $titltags = [$tags[0], $k, $tags[1], 'titre']; + $zinc->add('text', $group, + -position => $tcoords->[$tindex], + -text => $titles->[$tindex], + -font => $font_9b, + -alignment => 'center', + -anchor => 'center', + -color => '#000099', + -priority => 200, + -tags => $titltags, + ); + + } + + # exemple fonte + if ($tindex == 0) { + $zinc->add('text', $parentgroup, + -position => [-130, -84], + -text => $table->{'-names'}->[0], + -font => $font_9b, + -alignment => 'left', + -anchor => 'w', + -color => '#000000', + -priority => 500, + -tags => [$tags[0], 'fontname'], + ); + + # as I do not want to put lot of images in TkZinc demos, I + # commented out the following lines! +# $zinc->add('icon', $parentgroup, +# -position => [-130, -70], +# -priority => 200, +# -image => $table->{'-images'}->[0], +# -tags => [$tags[0], 'fontimage'], +# ); + } + + } + + &selectDivider($tags[0], $k); +} + + +1; diff --git a/Perl/demos/zinc-demos b/Perl/demos/zinc-demos index 414a0a6..88fb9bd 100644 --- a/Perl/demos/zinc-demos +++ b/Perl/demos/zinc-demos @@ -183,12 +183,13 @@ $T->insert('end', "4. Transformation testbed.\n", [qw/demo demo-transforms/] $T->insert('end', "5. zooming/Rotating icons. (requires openGL)\n", [qw/demo demo-icon_zoom_resize/]); $T->insert('end', "\n", '', "Use of openGL\n", 'title'); -$T->insert('end', "1. The TkZinc Logo (requires openGL).\n", [qw/demo demo-tkZincLogo/]); +$T->insert('end', "1. A zoomable/rotatable TkZinc Logo (better with openGL).\n", [qw/demo demo-tkZincLogo/]); $T->insert('end', "2. Axial color variation on the X axis (requires openGL).\n", [qw/demo demo-color-x/]); $T->insert('end', "3. Axial color variation on the Y axis (requires openGL).\n", [qw/demo demo-color-y/]); $T->insert('end', "4. Circular color variation (requires openGL).\n", [qw/demo demo-color-circular/]); $T->insert('end', "5. Path and Conical color variations (requires openGL).\n", [qw/demo demo-color-path-and-conic/]); $T->insert('end', "6. The triangles item (requires openGL).\n", [qw/demo demo-triangles/]); +$T->insert('end', "7. A set of demos based on Graphics.pm module (really better with openGL).\n", [qw/demo demo-testGraphics/]); @@ -248,7 +249,9 @@ sub AUTOLOAD { { $DEMO_FILE = "$WIDTRIB/${demo}.pl" if -f "$WIDTRIB/${demo}.pl"; $DEMO_FILE = "$zinc_lib/${demo}.pl" if -f "$zinc_lib/${demo}.pl"; - do $DEMO_FILE; + if (defined $DEMO_FILE) { + do $DEMO_FILE ; + } else { warn "No such demo: $demo.pl in either $WIDTRIB/ or $zinc_lib/\n"; } warn $@ if $@; } $T->Unbusy; -- cgit v1.1