From 5bce61c04e589e368d534c4797711ac73c1e1f23 Mon Sep 17 00:00:00 2001 From: Achil Date: Tue, 6 Sep 2022 18:56:51 +0200 Subject: Daniel Etienne pre release for Bullseye --- .../usr/lib/python2.7/dist-packages/Zinc/Zinc.py | 1597 +++++++++++++ .../lib/python2.7/dist-packages/Zinc/__init__.py | 4 + .../lib/python2.7/dist-packages/Zinc/geometry.py | 410 ++++ .../lib/python2.7/dist-packages/Zinc/graphics.py | 2351 ++++++++++++++++++++ .../lib/python2.7/dist-packages/Zinc/pictorial.py | 766 +++++++ 5 files changed, 5128 insertions(+) create mode 100755 debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/Zinc.py create mode 100755 debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/__init__.py create mode 100755 debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/geometry.py create mode 100755 debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/graphics.py create mode 100755 debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/pictorial.py (limited to 'debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc') diff --git a/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/Zinc.py b/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/Zinc.py new file mode 100755 index 0000000..d5a276d --- /dev/null +++ b/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/Zinc.py @@ -0,0 +1,1597 @@ +#!/usr/bin/python +# -*- coding: iso-8859-1 -*- +# +# Zinc.py -- Python interface to the tkzinc widget. +# +# Authors : Frederic Lepied, Patrick Lecoanet +# Created Date : Thu Jul 22 09:36:04 1999 +# +# $Id: Zinc.py 1908 2008-09-15 09:38:54Z lecoanet $ +# +# +# Copyright (c) 1999 CENA -- +# +# See the file "Copyright" for information on usage and redistribution +# of this file, and for a DISCLAIMER OF ALL WARRANTIES. +# +# + +__version__ = "$Revision: 1908 $" +__revision__ = "$Revision: 1908 $" + +from Tkinter import * +import new +import os +import locale, types +import traceback + +ZINC_CURRENT_POSITION = -2 +ZINC_SPEED_VECTOR = -3 +ZINC_LEADER = -4 +ZINC_CONNECTION = -5 +_LIBLOADED = 0 +_VERSION = "" +ZINC_NO_PART = "" + +# current part dictionnary +ZINC_DPART = { 'position' : ZINC_CURRENT_POSITION, + 'speedvector' : ZINC_SPEED_VECTOR , + 'leader' : ZINC_LEADER, + 'connection' : ZINC_CONNECTION} +# notes : 'field' will be return when currentpart is a field + +def havetkzinc( window ): + '''load Zinc dynamic sharable object library , test if everything is ok +if ok :return zinc version +if nok : return 0 ''' + global _LIBLOADED + global _VERSION + if ( _LIBLOADED == 1 ) : + return _VERSION + try: + if os.environ.has_key( 'auto_path' ): + ldir = os.environ['auto_path'].split( ':' ) + ldir.reverse() + for adir in ldir : + window.tk.call( 'eval', + "set auto_path " + + "[linsert $auto_path 0 %s]" % ( adir ) ) + window.tk.call( 'eval', 'package require Tkzinc' ) + # Call a function from the package to autoload it + # and verify that all is OK. + sversion = window.tk.call( 'zinc' ) + " Zinc.py %s" % __version__ + except TclError: + traceback.print_exc() + return 0 + _LIBLOADED = 1 + _VERSION = sversion + return sversion + +class ZincException: + def __call__( self ): + raise self + + def __init__( self, message ): + self.message = message + + def __str__( self ): + return self.message + +class Zinc( Widget ): + def __str__( self ): + return( "Zinc instance" ) + def __init__( self, master = None, cnf = None, **kw ): + if kw.has_key( 'backward_compatibility' ): + self.currentpart = self.__oldcurrentpart + self.configure = self.__oldconfigure + self.scale = self.__oldscale + self.translate = self.__oldtranslate + del kw['backward_compatibility'] + #Pour éviter des effets de bord + #si on met comme valeur par défaut de cnf + #à {} + if cnf is None : + cnf = {} + if master : + self.version = havetkzinc( master ) + else: + master = Frame() + master.pack() + self.version = havetkzinc( master ) + Widget.__init__( self, master, 'zinc', cnf, kw ) + self.items = {} + #BootStrap Root + classe = eval( 'Group' ) + obj = None + kw['id'] = 1 + obj = new.instance( classe, kw ) + self.items[1] = obj + + def mainloop( self ): + """ + Run the events mainloop + """ + self.tk.mainloop() + + def add( self, itemType, *args, **kw ): + """ + listTypes = zinc.add() + id = zinc.add(type, group) + id = zinc.add(type, group, initargs, **options) + type=[arc|curve|rectangle|triangles|tabular|track|waypoint|group|icon|map|reticle|text|window] + """ + args = list( args ) + args = args+list( self._options( kw ) ) + try: + return self.tk.getint( + self.tk.call( self._w, 'add', itemType, *args ) ) + except TclError, excpt : + ZincException( "%s\nType %s\nArgs : %s"%( excpt, itemType, args ) )() + + def addtag( self, *args ): + """ + zinc.addtag(tag, searchSpec) + This command add the given tag to all items matching + the search specification. + If the tag is already present on some item, + nothing is done for that item. + The command has no effect if no item satisfy + the given criteria. The command returns an empty string. + """ + self.tk.call( self._w, 'addtag', *args ) + + def addtag_above( self, newtag, tagOrId ): + """ + zinc.addtag_above(tag, tagOrId) + """ + self.addtag( newtag, 'above', tagOrId ) + + def addtag_all( self, newtag ): + """ + A ne plus utiliser + Utiliser addtag_withtag + """ + self.addtag( newtag, 'all' ) + + def addtag_ancestors( self, newtag, tagOrId, *ltagOrId ): + """ + zinc.addtag_ancestors(tag, tagOrId, *listTagOrId) + """ + self.addtag( newtag, 'ancestors', tagOrId, *ltagOrId ) + + def addtag_atpriority( self, newtag, pri, tagOrId = 1 ): + """ + zinc.addtag_atpriority(tag, priority, tagOrId = 1) + """ + + self.addtag( newtag, 'atpriority', pri, tagOrId ) + + def addtag_below( self, newtag, tagOrId ): + """ + zinc.addtag_below(tag, tagOrId) + """ + self.addtag( newtag, 'below', tagOrId ) + + def addtag_closest( self, newtag, x, y, halo = None, startItem = 1, recursive = 0 ): + """ + zinc.addtag_closest(tag, x, y, halo = None, startItem = 1, recursive = 0) + """ + self.addtag( newtag, 'closest', x, y, halo, startItem, recursive ) + + def addtag_enclosed( self, newtag, x1, y1, x2, y2, inGroup = 1, recursive = 0 ): + """ + zinc.addtag_enclosed(tag, x1, y1, x2, y2, inGroup = 1, recursive = 0) + """ + self.addtag( newtag, 'enclosed', x1, y1, x2, y2, inGroup, recursive ) + + def addtag_overlapping( self, newtag, x1, y1, x2, y2, inGroup = 1, recursive = 0 ): + """ + zinc.addtag_overlapping(tag, x1, y1, x2, y2, inGroup = 1, recursive = 0) + """ + self.addtag( newtag, 'overlapping', x1, y1, x2, y2, inGroup, recursive ) + + def addtag_withtag( self, newtag, tagOrId ): + """ + zinc.addtag_withtag(tag, tagOrId) + """ + self.addtag( newtag, 'withtag', tagOrId ) + + def addtag_withtype( self, newtag, type, tagOrId = 1 ): + """ + zinc.addtag_withtype(tag, type, tagOrId = 1) + """ + self.addtag( newtag, 'withtype', type, tagOrId ) + + def anchorxy( self, *args ): + """ + (x, y) = zinc.anchorxy(tagOrId, anchor) + """ + return self.tk.call( self._w, 'anchorxy', *args ) + + def bbox( self, *args ): + """ + (xo, yo, xc, yc) = zinc.bbox(tagOrId, ?fieldIndex?) + """ + return self.tk.call( self._w, 'bbox', *args ) + + def becomes( self ): + """ + zinc.becomes() + """ + self.tk.call( self._w, 'becomes' ) + + def bind_tag( self, tagOrId, sequence = None, func = None, add = None ): + ''' + return a funcid which can be usefull for unbinding + listBindings = zinc.bind_tag(tagOrId) + listbindings = zinc.bind_tag(tagOrId, sequence) + zinc.bind_tag(tagOrId, sequence, '') + zinc.bind_tag(tagOrId, sequence, command) + ''' + return self._bind( ( self._w, 'bind', tagOrId ), + sequence, func, add ) + + def cget( self, option ): + """ + val = zinc.cget(option) + """ + return self.tk.call( self._w, 'cget', '-' + option ) + + def chggroup( self, *args ): + """ + zinc.chggroup(tagOrId, group, ?adjustTransform?) + """ + self.tk.call( self._w, 'chggroup', *args ) + + def clone( self, *args, **kw): + """ + id = zinc.clone(tagOrId, **attributs) + """ + args = list( args ) + list( self._options( kw ) ) + return self.tk.call( self._w, 'clone', *args) + + def __oldconfigure( self, **kw ): + return Widget.configure( self, **kw ) + + def configure( self, **kw ): + """ + listOptions = zinc.configurez() + listOptions = zinc.configurez(option) + zinc.configurez(**options) + """ + res = Widget.configure( self, **kw ) + dico = {} + if res: + for i, j in res.items(): + dico[i] = j[3:] + return dico + + def contour( self, *args ): + """ + contourNum = zinc.contour(tagOrId) + contourNum = zinc.contour(tagOrId, operatorAndFlag, coordListOrTagOrId) + """ + return self.tk.call( self._w, 'contour', *args ) + + def coords( self, *args ): + """ + zinc.coords(tagOrId, contourIndex) + zinc.coords(tagOrId, contourIndex, coordList) + zinc.coords(tagOrId, contourIndex, coordIndex) + zinc.coords(tagOrId, contourIndex, coordIndex, coordList) + zinc.coords(tagOrId, 'remove', contourIndex, coordIndex) + zinc.coords(tagOrId, 'add', contourIndex, coordList) + zinc.coords(tagOrId, 'add', contourIndex, coordIndex, coordList) + zinc.coords(tagOrId) + zinc.coords(tagOrId, coordList) + zinc.coords(tagOrId, 'remove', coordIndex) + zinc.coords(tagOrId, 'add', coordList) + """ + return self.tk.call( self._w, 'coords', *args ) + + def __buggyoldcurrentpart( self ): + ''' + return a string (result from zinc current part function) and an + integer representing either the number of the field either + the number of the item part either ZINC_NO_PART + ''' + scurrentp = self.tk.call( self._w, 'currentpart' ) + if scurrentp == "": + rvalue = ZINC_NO_PART + else: + try: + rvalue = locale.atoi( scurrentp ) + except: + try: + rvalue = ZINC_DPART[scurrentp] + except: + rvalue = ZINC_NO_PART + else: + # string to integer succeeded + scurrentp = "field" + return( scurrentp, rvalue ) + + def __oldcurrentpart( self ): + '''return a string and an integer ; +the string is among "field", "position", "speedvector", "leader", "connection", "", +the number is the number of the part , or the field number in case of "field"; +ex: +no part return '', ZINC_NO_PART +''' + scurrentp = self.tk.call( self._w, 'currentpart' ) + print "Zinc::__oldcurrentpart scurrentp = [%s]" % scurrentp + # warning : read this first : + # return a string among 'position', 'speedvector', 'leader', 'connection' ,'' + # or an int representing the number of a field label + # + # print "Zinc::currentpart cp=%s ,type(cp)=%s" % (scurrentp,type(scurrentp)) + if scurrentp == "": + rvalue = ZINC_NO_PART + elif type( scurrentp ) == type( 1 ): + # meaning a field + # the subtil thing is here ! warning ! + rvalue = scurrentp + scurrentp = "field" + else: + # scurrentp is a string different from "" + try: + rvalue = ZINC_DPART[scurrentp] + except: + print "Zinc::currentpart unknown item part" + rvalue = ZINC_NO_PART + + return scurrentp, rvalue + + def currentpart( self ): + ''' + num = zinc.currentpart() + ''' + return str( self.tk.call( self._w, 'currentpart' ) ) + + + def cursor( self, *args ): + """ + zinc.cursor(tagOrId, index) + """ + self.tk.call( self._w, 'cursor', *args ) + + def dchars( self, *args ): + """ + zinc.dchars( tagOrId, first ) + zinc.dchars( tagOrId, first,last ) + """ + self.tk.call( self._w, 'dchars', *args ) + + def dtag( self, *args ): + """ + zinc.dtag(tagOrId) + zinc.dtag(tagOrId, tagToDelete) + """ + self.tk.call( self._w, 'dtag', *args ) + + def find( self, *args ): + return self._getints( + self.tk.call( self._w, 'find', *args ) ) or () + + def find_above( self, tagOrId ): + """ + listItems=zinc.find_above(tagOrId)} + """ + return self.find( 'above', tagOrId ) + + def find_all( self ): + return self.find( 'all' ) + + def find_ancestors( self, newtag, tagOrId, *tagOrId2 ): + """ + listItems=zinc.find_ancestor(tag, tagOrId, ?tagOrId2?) + """ + return self.find( newtag, 'ancestors', tagOrId, *tagOrId2 ) + + def find_atpriority( self, pri, *tagOrId ): + """ + listItems=zinc.find_atpriority(pri, ?tagOrId?) + """ + return self.find( 'atpriority', pri, *tagOrId ) + + def find_below( self, tagOrId ): + """ + listItems=zinc.find_below(tagOrId) + """ + return self.find( 'below', tagOrId ) + + def find_closest( self, x, y, *options ): + """ + listItems=zinc.find_closest(x, y, ?halo?, ?startItem?, ?recursive?) + """ + return self.find( 'closest', x, y, *options ) + + def find_enclosed( self, x1, y1, x2, y2 ): + """ + listItems=zinc.find_enclosed(x1, y1, x2, y2, inGroup=1, recursive=0) + """ + return self.find( 'enclosed', x1, y1, x2, y2 ) + + def find_overlapping( self, x1, y1, x2, y2, *options ): + """ + listItems=zinc.find_overlapping( x1, y1, x2, y2, ?inGroup?, ?recursive?) + """ + return self.find( 'overlapping', x1, y1, x2, y2, *options ) + + def find_withtag( self, tagOrId ): + """ + listItems=zinc.find_withtag( tagOrId) + """ + return self.find( 'withtag', tagOrId ) + + def find_withtype( self, type, *tagOrId ): + """ + listItems=zinc.find_withtype( type, ?tagOrId?) + """ + return self.find( 'withtype', type, *tagOrId ) + + + def fit( self, *args ): + """ + listControls=zinc.fit(coordList,error) + """ + return self.tk.call( self._w, 'fit', *args ) + + def focus( self, *args ): + """ + zinc.focus(tagOrId, ?itemPart?) + """ + self.tk.call( self._w, 'focus', *args ) + + def gdelete( self, *args ): + """ + zinc.gdelete(gradientName) + """ + self.tk.call( self._w, 'gdelete', *args ) + + def gettags( self, *args ): + """ + listTags=zinc.gettags(tagorid) + """ + return self.tk.splitlist( self.tk.call( self._w, 'gettags', *args ) ) + + def gname( self, *args ): + """ + zinc.gname(gradientDesc, gradientName) + bExist=zinc.gname(gradientName) + """ + return self.tk.call( self._w, 'gname', *args ) + + def group( self, *args ): + """ + group=zinc.group(tagOrId) + """ + return self.tk.call( self._w, 'group', *args ) + + def hasanchors( self, *args ): + """ + bool=zinc.hasanchors(tagOrId) + """ + return self.tk.call( self._w, 'hasanchors', *args ) + + def hasfields( self, *args ): + """ + bool=zinc.hasfields(tagOrId) + """ + return self.tk.call( self._w, 'hasfield', *args ) + + def hastag( self, *args ): + """ + bool=zinc.hastag(tagOrId, tag) + """ + return self.tk.call( self._w, 'hastag', *args ) + + def index( self, *args ): + """ + num = zinc.index(tagOrId, index) + """ + return self.tk.call( self._w, 'tagOrId', *args ) + + def insert( self, *args ): + """ + zinc.insert(tagOrId, before, string) + """ + self.tk.call( self._w, 'insert', *args ) + + def itemcget( self, tagOrId, option ): + """ + val=zinc.itemcget(tagOrId, attr) + """ + return self.tk.call( self._w, 'itemcget', tagOrId, '-'+option ) + + def itemfieldget( self, tagOrId, field, option ): + """ + val=zinc.itemcget(tagOrId, field, attr) + """ + return self.tk.call( self._w, 'itemcget', tagOrId, field, '-'+option ) + + def itemconfigure( self, tagOrId, field=None, **kw ): + ''' + either get the dictionnary of possible attributes (if kw is None) + either allow to set Items attributes or Field attributes + + listAttribs=zinc.itemconfigure(tagOrId) + listAttribs=zinc.itemconfigure(tagOrId, attrib) + zinc.itemconfigure(tagOrId, **attributs) + listAttribs=zinc.itemconfigure(tagOrId, fieldIs, attrib) + zinc.itemconfigure(TagOrId,fieldId,**attributs) + ''' + if not kw: + cnf = {} + for var_x in self.tk.split( + field != None and self.tk.call( self._w, 'itemconfigure', + ( tagOrId, field ) ) or + self.tk.call( self._w, 'itemconfigure', ( tagOrId, ) ) ): + cnf[var_x[0][1:]] = ( var_x[0][1:], ) + var_x[1:] + return cnf + if field != None: + args = ( tagOrId, str( field ), )+ self._options( {}, kw ) + self.tk.call( self._w, 'itemconfigure', *args ) + else: + args = ( tagOrId, ) + self._options( {}, kw ) + self.tk.call( self._w, 'itemconfigure', *args ) + + # _dp voir si cette instruction est a execute ici + # permet de creer un synonyme de itemconfigure + itemconfig = itemconfigure + + def loweritem( self, *args ): + """ + zinc.loweritem(tagOrId) + zinc.loweritem(tagOrId, belowThis) + Reorder all the items given by tagOrId so that + they will be under the item given by belowThis. + If tagOrId name more than one item, + their relative order will be preserved. + If tagOrId doesn't name an item, an error is raised. + If belowThis name more than one item, the bottom most them is used. + If belowThis doesn't name an item, an error is raised. + If belowThis is omitted the items are put + at the bottom most position of their respective groups. + The command ignore all items named by tagOrId + that are not in the same group than belowThis or, + if not specified, in the same group than the first item + named by tagOrId. The command returns an empty string. + As a side affect of this command, the -priority attribute + of all the reordered items is ajusted to match the priority + of the belowThis item (or the priority of the bottom most item) + """ + self.tk.call( self._w, 'lower', *args ) + + def monitor( self, *args ): + """ + bool = zinc.monitor() + zinc.monitor(bool) + """ + return self.tk.call( self._w, 'monitor', *args ) + + def numparts( self, *args ): + """ + num = zinc.numparts(tagOrId) + """ + return self.tk.call( self._w, 'numparts', *args ) + + def postcript( self, *args ): + """ + Not Yet Implemented + zinc.postscript() + """ + return self.tk.call( self._w, 'postscript', *args ) + + def raiseitem( self, *args ): + """ + Correspond à l'appel raise de la documentation + le mot raise est reservé en python + zinc.raiseitem(tagOrId) + zinc.raiseitem(tagOrId, aboveThis) + """ + self.tk.call( self._w, 'raise', *args ) + + def remove( self, *args ): + """ + zinc.remove(tagOrId, ?tagOrId,...?) + """ + self.tk.call( self._w, 'remove', *args ) + + def rotate( self, *args ): + """ + zinc.rotate(tagOrId, angle) + zinc.rotate(tagOrId, angle, centerX, centerY) + """ + self.tk.call( self._w, 'rotate', *args ) + + def __oldscale( self, xFactor=None, yFactor=None, tagOrId=None ): + if yFactor == None: + return self.tk.getdouble( self.tk.call( 'scale' ) ) + else: + if tagOrId == None: + self.tk.call( self._w, 'scale', xFactor, yFactor ) + else: + self.tk.call( self._w, 'scale', tagOrId, xFactor, yFactor ) + + def scale( self, *args ): + """ + zinc.scale(tagOrIdOrTName, xFactor, yFactor) + zinc.scale(tagOrIdOrTName, xFactor, yFactor, centerX, centerY) + Add a scale factor to the items or the transform described + by tagOrId. + If tagOrId describes a named transform then this transform + is used to do the operation. If tagOrId describes more than + one item then all the items are affected by the operation. + If tagOrId describes neither a named transform nor an item, + an error is raised. + A separate factor is specified for X and Y. + The optional parameters describe the center of scaling, + which defaults to the origin. + """ + if not len( args ): + return self.tk.getdouble( self.tk.call( self._w, 'scale' ) ) + else: + self.tk.call( self._w, 'scale', *args ) + + def select( self, *args ): + """ + zinc.select('adjust', tagOrId, index) + Adjust the end of the selection in tagOrId + that is nearest to the character given by index so + that it is at index. + The other end of the selection is made the anchor + for future select to commands. + If the selection is not currently in tagOrId, + this command behaves as the select to command. + The command returns an empty string. + zinc.select('clear') + Clear the selection if it is in the widget. + If the selection is not in the widget, + the command has no effect. Return an empty string. + zinc.select('from', tagOrId, index) + Set the selection anchor point for the widget + to be just before the character given by index + in the item described by tagOrId. + The command has no effect on the selection, + it sets one end of the selection so that future + select to can actually set the selection. + The command returns an empty string. + (item,part) = zinc.select('item') + Returns a list of two elements. + The first is the id of the selected item + if the selection is in an item on this widget; + Otherwise the first element is an empty string. + The second element is the part of the item + (track, waypoint or tabular item only) or the empty string. + zinc.select('to', tagOrId, index) + Set the selection to be the characters that lies + between the selection anchor and index in the item described + by tagOrId. The selection includes the character given + by index and includes the character given by the anchor point + if index is greater or equal to the anchor point. + The anchor point is set by the most recent select adjust + or select from command issued for this widget. + If the selection anchor point for the widget is not currently + in tagOrId, it is set to the character given by index. + The command returns an empty string. + Manipulates the selection as requested by option. + tagOrId describes the target item. + This item must support text indexing and selection. I + f more than one item is referred to by tagOrId, + the first in display list order that support both text + indexing and selection will be used. + Some forms of the command include an index parameter, + this parameter describes a textual position within the + item and should be a valid index as described in + Text indices. + """ + return self.tk.call( self._w, 'select', *args ) + + def skew( self, *args ): + """ + zinc.skew(tagOrIdOrTName,xSkewAngle, ySkewAngle) + Add a skew (or shear) transform to the to the items + or the transform described by tagOrIdOrTName. + If tagOrId describes a named transform then this transform + is used to do the operation. + If tagOrId describes more than one item then all the + items are affected by the operation. + If tagOrId describes neither a named transform nor an item, + an error is raised. The angles are given in radian. + """ + return self.tk.call( self._w, 'skew', *args ) + + def smooth( self, *args ): + """ + zinc.smooth(coordList) + This command computes a sequence of segments + that will smooth the polygon described by the vertices + in coordList and returns a list of lists describing points + of the generated segments. These segments are approximating + a Bezier curve. coordList should be either a flat list + of an even number of coordinates in x, y order, or a list + of lists of point coordinates X, Y. + The returned list can be used to create or change the contour + of a curve item. + """ + return self.tk.call( self._w, 'smooth', *args ) + + def tapply( self, *args ): + """ + Not Yet Implemented + zinc.tapply() + """ + return self.tk.call( self._w, 'tapply', *args ) + + def tcompose( self, *args ): + """ + zinc.tcompose(tagOrIdOrTName, tName) + zinc.tcompose(tagOrIdOrTName, tName, invert) + """ + return self.tk.call( self._w, 'tapply', *args ) + + def tdelete( self, *args ): + """ + zinc.tdelete(tName) + Destroy a named transform. + If the given name is not found among the named transforms, + an error is raised. + """ + self.tk.call( self._w, 'tdelete', *args ) + + def transform( self, *args ): + """ + listCoords=zinc.transform(tagOrIdTo, coordList) + listCoords=zinc.transform(tagOrIdFrom, tagOrIdTo, coordList) + This command returns a list of coordinates obtained by transforming the coordinates given in coordList + from the coordinate space of the transform or item described by tagOrIdFrom to the coordinate space + of the transform or item described by tagOrIdTo. + If tagOrIdFrom is omitted it defaults to the window coordinate space. + If either tagOrIdFrom or tagOrIdTo describes more than one item, + the topmost in display list order is used. If either tagOrIdFrom or tagOrIdTo + doesn't describe either a transform or an item, an error is raised. + The coordList should either be a flat list containing an even number of coordinates + each point having two coordinates, or a list of lists each sublist of the form [ X Y ?pointtype? ]. + The returned coordinates list will be isomorphic to the list given as argument. + + It is possible to convert from window coordinate space to the coordinate space of any item. + This is done by omitting ?tagOrIdFrom? and specifying in tagOrIdTo, the id of the item. + It can also be done by using the predefined tag 'device' as first argument. + + It is also possible to convert from the coordinate space of an item to the window coordinate + space by using the predefined tag 'device' as second argument. + + """ + return self._getdoubles( self.tk.call( self._w, 'transform', *args ) ) + +#ANCIENNE IMPLEMENTATION + def __oldtranslate( self, dx=None, dy=None, tagOrId=None ): + if dx == None: + return self._getints( self.tk.call( 'translate' ) ) + else: + if tagOrId == None: + self.tk.call( self._w, 'translate', dx, dy ) + else: + self.tk.call( self._w, 'translate', tagOrId, dx, dy ) + + def translate( self, *args ): + """ + zinc.translate(tagOrIdOrTName, xAmount, yAmount) + zinc.translate(tagOrIdOrTName, xAmount, yAmount, absolute) + Add a translation to the items or the transform described by tagOrIdOrTName. + If tagOrIdOrTName describes a named transform then this transform is used + to do the operation. + If tagOrIdOrTName describes more than one item then all the items are affected + by the opration. + If tagOrIdOrTName describes neither a named transform nor an item, + an error is raised. A separate value is specified for X and Y. + If the optionnal ?absolute? parameter is true, + it will set an absolute translation to the tagOrIdOrTName + """ + if ( len( args ) == 1 ): + return self._getints( self.tk.call( self._w, 'translate' ) ) + else: + self.tk.call( self._w, 'translate', *args ) + + def treset( self, *args ): + """ + zinc.treset(tagOrIdOrTName) + Set the named transform or the transform for the items described by tagOrIdOrTName + to identity. If tagOrIdOrTName describes neither a named transform nor an item, + an error is raised. + """ + self.tk.call( self._w, 'treset', *args ) + + def trestore( self, *args ): + """ + zinc.trestore(tagOrId, tName) + Set the transform for the items described by tagOrId to the transform named by tName. + If tagOrId doesn't describe any item or if the transform named tName doesn't exist, + an error is raised. + """ + self.tk.call( self._w, 'trestore', *args ) + + def tsave( self, *args ): + """ + zinc.tsave(tName) + zinc.tsave(tagOrIdOrTName, tName) + zinc.tsave(tagOrIdOrTName, tName, invert) + Create (or reset) a transform associated with the name tName + with initial value the transform associated with the item tagOrIdOrTName. + If tagOrIdOrTName describes more than one item, the topmost in display list order is used. + If tagOrIdOrTName doesn't describe any item or named transformation, an error is raised. + If tName already exists, the transform is set to the new value. + This command is the only way to create a named transform. + If tagOrIdOrTName is not specified, the command returns a boolean telling + if the name is already in use. + The invert boolean, if specified, cause the transform to be inverted prior to be saved. + + It is possible to create a new named transformation from the identity + by using the predefined tag 'identity': $zinc->tsave('identity', 'myTransfo'); + """ + return self.tk.call( self._w, 'tsave', *args ) + + def tget( self, *args ): + """ + zinc.tget(tagOrId) + zinc.tget(tagOrIdOrTName, selector) + selector:={'all'|'translation'|'scale'|'rotation'|'skew'} + With only one argument, get the six elements of the 3x4 matrix + used in affine transformation for tagOrIdOrTName. + The result is compatible with the tset method. + With optional second parameter 'all' returns the transform + decomposed in translation, scale, rotation, skew + and return the list in this order, + With 'translation', 'scale', 'rotation', 'skew' optional + second parameter, returns the corresponding values. + """ + return self.tk.call( self._w, 'tget', *args ) + + def tset( self, *args ): + """ + zinc.tset(tagOrIdOrName, m00, m01, m10, m11, m20, m21) + Set the six elements of the 3x4 matrix used in affine transformation for tagOrIdOrTName. + BEWARE that depending on mij values, + it is possible to define a not inversible matrix which will end up in core dump. + This method must BE USED CAUTIOUSLY. + """ + return self.tk.call( self._w, 'tset', *args ) + + def type( self, tagOrId ): + """ + name=zinc.type(tagOrId) + If more than one item is named by tagOrId, + then the type of the topmost item in display list order is returned. + If no items are named by tagOrId, an error is raised. + """ + return self.tk.call( self._w, 'type', tagOrId ) + + def vertexat( self, *args ): + """ + (contour,vertex,edgevertex)=zinc.vertexat(tagOrId,x,y) + """ + return self.tk.call( self._w, 'vertexat', *args ) + + def xview(self, *args): + """Query and change horizontal position of the view.""" + if not args: + return self._getdoubles(self.tk.call(self._w, 'xview')) + self.tk.call((self._w, 'xview') + args) + def xview_moveto(self, fraction): + """Adjusts the view in the window so that FRACTION of the + total width of the canvas is off-screen to the left.""" + self.tk.call(self._w, 'xview', 'moveto', fraction) + def xview_scroll(self, number, what): + """Shift the x-view according to NUMBER which is measured in "units" or "pages" (WHAT).""" + self.tk.call(self._w, 'xview', 'scroll', number, what) + def yview(self, *args): + """Query and change vertical position of the view.""" + if not args: + return self._getdoubles(self.tk.call(self._w, 'yview')) + self.tk.call((self._w, 'yview') + args) + def yview_moveto(self, fraction): + """Adjusts the view in the window so that FRACTION of the + total height of the canvas is off-screen to the top.""" + self.tk.call(self._w, 'yview', 'moveto', fraction) + def yview_scroll(self, number, what): + """Shift the y-view according to NUMBER which is measured in "units" or "pages" (WHAT).""" + self.tk.call(self._w, 'yview', 'scroll', number, what) + +class ZincItem: + def __init__( self, zinc, itemType, group = 1, *args, **kw ): + self.zinc = zinc + texture = None + fillpatern = None + scale = None + translate = None + if kw.has_key( 'texture' ): + texture = kw['texture'] + del kw['texture'] + + if kw.has_key( 'fillpatern' ): + fillpastern = kw['fillpatern'] + del kw['fillpatern'] + + if kw.has_key( 'scale' ): + scale = kw['scale'] + del kw['scale'] + + if kw.has_key( 'rotate' ): + rotate = kw['rotate'] + del kw['rotate'] + + if kw.has_key( 'translate' ): + translate = kw['translate'] + del kw['translate'] + + if kw.has_key( 'cloneid' ): + cloneid = kw['cloneid'] + del kw['cloneid'] + else: + cloneid = 0 + group = str( group ) + # sys.stdout.flush() + if cloneid == 0 : + self.id = zinc.add( itemType, group, *args, **kw ) + else : + self.id = self.zinc.clone(cloneid, *args, **kw) + + zinc.items[self.id] = self + texture = None + if fillpatern: + self.itemconfigure( fillpatern ) + if scale: + self.scale( scale ) + if translate: + self.translate( translate ) + + + def __str__( self ): + return str( self.id ) + + def __repr__( self ): + return str( self.id ) + + def bbox( self, *args ): + return self.zinc.bbox( self.id, *args ) + + def clone( self, *args, **kw): + '''id = zincitem.clone(*args,**kw) ''' + # print "ZincItem::clone" + # on cherche tagOrId + # nidcloned = self.find_above(tagOrId) + sclonedtype = self.type() + sclonedgroupid = self.zinc.group(self.id) + + # ajout cle 'cloneid' (voir ZincItem::__init__) + kw['cloneid'] = self.id + # on cree un nouveau ZincItem meme type, + return(ZincItem(self.zinc, sclonedtype, sclonedgroupid, **kw )) + + def delete( self ): + del self.zinc.items[self.id] + try: + self.zinc.remove( self.id ) + except: + pass + def __getitem__( self, key ): + '''allow to get attribute by self["key"] ''' + if ( key == "coords" ): + return self.zinc.coords( self.id ) + return self.zinc.itemcget( self.id, key ) + + def __setitem__( self, key, value ): + '''allow to set item attrbutes, eg. for a track position attributes + just writing : + a = ZincItem(myzinc, ...) + a["position"] = (x,y) + Notes : when setting multiple attributes + using itemconfigure is more efficient ''' + if ( key is "coords" ): + self.zinc.coords( self.id, value ) + else: + self.zinc.itemconfigure( self.id, **{key:value} ) + + def getGroup( self ): + groupid = self.zinc.group( self.id ) + return self.zinc.items[groupid] + + def keys( self ): + if not hasattr( self, '_keys' ): + self._keys = {} + config = self.zinc.itemconfig( self.id ) + for x in config.keys(): + self._keys[x] = config[x][1] + return self._keys + + def has_key( self, key ): + return key in self.keys() + + def bind( self, sequence=None, command=None, add=None ): + '''return a funcid which can be used to unbind +notes: unbinding can be done by bind("","") or using native tkinter +unbind method ''' + return( self.zinc.bind_tag( self.id, sequence, command, add ) ) + + def cget( self, attr ): + return self.zinc.itemcget( self.id, attr ) + + def coords( self, *args, **kw ): + return self.zinc.coords( self.id, *args, **kw ) + + def fieldcget( self, field, attr ): + return self.zinc.itemfieldcget( self.id, field, attr ) + + def itemconfigure( self, field=None, **kw ): + self.zinc.itemconfigure( self.id, field, **kw ) + + def rotate( self, *args ): + return self.zinc.rotate( self.id, *args ) + + def scale( self, *args ): + return self.zinc.scale( self.id, *args ) + + def transforms( self, *args ): + """ + zincitem.transform(tozincitem, coordList) + This command returns a list of coordinates obtained by transforming the coordinates given in coordList + from the coordinate space of item to the coordinate space + of the tozincitem item. + The coordList should either be a flat list containing an even number of coordinates + each point having two coordinates, or a list of lists each sublist of the form [ X Y ?pointtype? ]. + The returned coordinates list will be isomorphic to the list given as argument. + """ + return self.zinc.transforms( self.id, *args ) + + def translate( self, *args ): + """ + zincitem.translate( xAmount, yAmount) + zincitem.translate( xAmount, yAmount, absolute) + Add a translation to the item. + A separate value is specified for X and Y. + If the optionnal ?absolute? parameter is true, + it will set an absolute translation to the item + """ + self.zinc.translate( self.id, *args ) + + def tset( self, *args ): + """ + zincitemtset(m00, m01, m10, m11, m20, m21) + Set the six elements of the 3x4 matrix used in affine transformation. + BEWARE that depending on mij values, + it is possible to define a not inversible matrix which will end up in core dump. + This method must BE USED CAUTIOUSLY. + """ + self.zinc.tset( self.id, *args ) + + def type( self ): + """ + name=zincitemtype() + This command returns the type of the item. + """ + return self.zinc.type( self.id ) + + def tsave( self, *args ): + """ + zincitemtsave( tName) + zincitemtsave( tName, invert) + Create a transform associated with the name tName + with initial value the transform associated with the item. + If tName already exists, the transform is set to the new value. + This command is the only way to create a named transform. + The invert boolean, if specified, cause the transform to be inverted prior to be saved. + """ + return self.zinc.tsave( self.id, *args ) + + def treset( self, *args ): + """ + zincitemtreset() + Set the named transform or the transform for the item + to identity. If there are no named transform, + an error is raised. + """ + self.zinc.treset( self.id, *args ) + + def trestore( self, *args ): + """ + zincitemtrestore( tName) + Set the transform for the item to the transform named by tName. + If the transform named tName doesn't exist, an error is raised. + """ + self.zinc.trestore( self.id, *args ) + + def tget( self, *args ): + """ + zincitemtget() + zincitemtget(selector) + selector:={'all'|'translation'|'scale'|'rotation'|'skew'} + With only one argument, get the six elements of the 3x4 matrix + used in affine transformation. + The result is compatible with the tset method. + With optional second parameter 'all' returns the transform + decomposed in translation, scale, rotation, skew + and return the list in this order, + With 'translation', 'scale', 'rotation', 'skew' optional + second parameter, returns the corresponding values. + """ + return self.zinc.tget( self.id, *args ) + + +class Arc( ZincItem ): + def __init__( self, zinc, *args, **kw ): + """ + The arc type expects a list of four floating point numbers xo yo xc yc, + giving the coordinates of the origin and the corner of the enclosing rectangle. + The origin should be the top left vertex of the enclosing rectangle and the corner + the bottom right vertex of the rectangle. + """ + ZincItem.__init__( self, zinc, 'arc', *args, **kw ) + +class Group( ZincItem ): + def __init__( self, zinc, *args, **kw ): + """ + These type do not expect type specific arguments. + """ + ZincItem.__init__( self, zinc, 'group', *args, **kw ) + + def getGroup( self ): + """Retourne l'objet de type Group + auquel est attache l'item""" + ###Gestion du boostrap + if self.id == 1: + return self.zinc.items[1] + else: + return ZincItem.getGroup( self ) + + #TODO: Extension. Renvoie les références aux ZincItems contenus dans le Groupe + def getNode( self ): + """ + """ + pass + +class Icon( ZincItem ): + def __init__( self, zinc, *args, **kw ): + """ + These type do not expect type specific arguments. + """ + ZincItem.__init__( self, zinc, 'icon', *args, **kw ) + +class Map( ZincItem ): + def __init__( self, zinc, *args, **kw ): + """ + These type do not expect type specific arguments. + """ + ZincItem.__init__( self, zinc, 'map', *args, **kw ) + +class Curve( ZincItem ): + def __init__( self, zinc, *args, **kw ): + """ + The curve type expects either a flat list or a list of lists. + In the first case, the flat list must be a list of floating point numbers + x0 y0 x1 y1 ... xn yn, giving the coordinates of the curve vertices. + The number of values should be even (or the last value will be discarded) + but the list can be empty to build an empty invisible curve. + In the second case,thelist must contain lists of 2 or 3 elements: + xi, yi and and an optionnal point type. Currently, + the only available point type is 'c' for a cubic bezier control point. + For example, the following list is an example of 2 beziers segments + with a straight segment in-between: + ( [x0, y0], [x1, y1, 'c'], [x2, y2, 'c'], [x3, y3], [x4, y4, 'c'], [x5, y5] ) + + As there is only on control point, [x4, y4, 'c'] , + for the second cubic bezier, + the omitted second control point will be defaulted to the same point. + a named tuple contours can give to define new contours in curve. + contours=(,...) + =(,...) + A curve can be defined later with the contour or coords commands. + As a side effect of the curve behavior, + a one vertex curve is essentially the same as an empty curve, + it only waste some more memory. + + """ + contours = [] + if kw.has_key( 'contours' ): + contours = kw['contours'] + del kw['contours'] + ZincItem.__init__( self, zinc, 'curve', *args, **kw ) + for contour in contours: + self.zinc.contour( self.id, *contour ) + + +class Rectangle( ZincItem ): + def __init__( self, zinc, *args, **kw ): + """ + The rectangle type expects a list of four floating point numbers xo yo xc yc, + giving the coordinates of the origin and the corner of the rectangle. + """ + ZincItem.__init__( self, zinc, 'rectangle', *args, **kw ) + +class Reticle( ZincItem ): + def __init__( self, zinc, *args, **kw ): + """ + These type do not expect type specific arguments. + """ + ZincItem.__init__( self, zinc, 'reticle', *args, **kw ) + +class Tabular( ZincItem ): + def __init__( self, zinc, *args, **kw ): + ZincItem.__init__( self, zinc, 'tabular', *args, **kw ) + +class Text( ZincItem ): + def __init__( self, zinc, *args, **kw ): + """ + These type do not expect type specific arguments. + """ + ZincItem.__init__( self, zinc, 'text', *args, **kw ) + +class Track( ZincItem ): + def __init__( self, zinc, *args, **kw ): + ZincItem.__init__( self, zinc, 'track', *args, **kw ) + +class WayPoint( ZincItem ): + def __init__( self, zinc, *args, **kw ): + ZincItem.__init__( self, zinc, 'waypoint', *args, **kw ) + + +# Class to hold mapinfos used by the Map Item class +class Mapinfo: + def __init__( self, interp, name = None ): + """ + @type name: string + @param name: Name of mapinfo. Must be used carrefully ! + Create a new empty map description. + The new mapinfo object named name or internal id if name is omitted + """ + if name : + self.name = name + else: + self.name = `id( self )` + self.interp = interp.tk + apply( self.interp.call, ( 'mapinfo', self.name, 'create' ) ) + + def __repr__( self ): + return self.name + + def __del__( self ): + self.delete() + + def delete( self ): + """ + Delete the mapinfo object. + All maps that refer to the deleted mapinfo are updated to reflect the change. + """ + self.interp.call( 'mapinfo', self.name, 'delete' ) + + + def duplicate( self, *args ): + """ + B{Optional} + @type name: Name of the new mapinfo + @param name: Must be use carrefully !! + Create a new mapinfo that is a exact copy of this mapinfo Object. + """ + classe = Mapinfo + obj = new.instance( classe ) + if len( args ): + new_name = args[0] + else: + new_name = str( obj ) + self.interp.call( 'mapinfo', self.name, 'duplicate', new_name ) + return obj + + def add_text( self, text_style, line_style, x, y, text ): + """ + Add a new graphical element to the mapinfo object text. + This element describes a line of text. + @type text_style: {normal|underlined} + @param text_style: text style + @type line_style: string + @param line_style: a line style (simple, dashed, dotted, mixed, marked) to be used for the underline + @type X: int + @param X: Coord on X axe + @type Y: int + @param Y: Coord on Y axe + @type text: string + @param : a string describing the text. + + """ + self.interp.call( 'mapinfo', self.name, 'add', 'text', text_style, + line_style, x, y, text ) + + def add_line( self, line_style, width, x1, y1, x2, y2 ): + """ + Add a new graphical element to the mapinfo object line. + This element describes a line segment. + @type line_style: {simple|dashed|dotted|mixed|marked} + @param line_style: a line style + @type width: int + @param width: the line width in pixels + @type x1: int + @param x1: coords on X axe + @type x2: int + @param x2: coords on Y axe + @type x3: int + @param x3: end vertices on X axe + @type x4: int + @param x4: end vertices on Y axe + four integer values setting the X and Y coordinates of the two end vertices. + """ + self.interp.call( 'mapinfo', self.name, 'add', 'line', line_style, + width, x1, y1, x2, y2 ) + + def add_arc( self, line_style, width, cx, cy, radius, start, extent ): + """ + Add a new graphical element to the mapinfo object arc. + + @type line_style: {simple|dashed|dotted|mixed|marked} + @param line_style: a line style + @type width: int + @param width: the line width in pixels + @type cx: int + @param cx: X of arc center + @type cy: int + @param cy: Y of arc center + @type radius: int + @param radius: the arc radius + @type start: int + @param start: the start angle (in degree) + @type extent: int + @param extent: the angular extent of the arc (in degree). + + """ + self.interp.call( 'mapinfo', self.name, 'add', 'arc', line_style, + width, cx, cy, radius, start, extent ) + + def add_symbol( self, x, y, index ): + """ + Add a new graphical element to the mapinfo object symbol. + @type x: int + @param x: position on X + @type y: int + @param y: position on Y + + @type index: int + @param : an integer setting the symbol index in the -symbols list of the map item + + """ + self.interp.call( 'mapinfo', self.name, 'add', 'symbol', x, y, index ) + + def count( self, type ): + """ + @type type: {text|arc|line|symbol} + @param type: + Return an integer value that is the number of elements matching type in the mapinfo. + type may be one the legal element types + """ + return self.interp.call( 'mapinfo', self.name, 'count', type ) + + def get( self, type, index ): + """ + Return the parameters of the element at index with type type in the mapinfo. + The returned value is a list. + The exact number of parameters in the list and their meaning depend on type and is accurately described in mapinfo add. + type may be one the legal element types as described in the mapinfo add command. + Indices are zero based and elements are listed by type. + """ + return self.interp.call( 'mapinfo', self.name, 'remove', type, index ) + + def replace( self, type, index, *args ): + """ + Replace all parameters for the element at index with type type in the mapinfo. + The exact number and content for args depend on type and is accurately described in mapinfo add. + type may be one the legal element types as described in the mapinfo add command. + Indices are zero based and elements are listed by type. + """ + return self.interp.call( 'mapinfo', self.name, 'replace', + type, index, args ) + + def remove( self, type, index ): + """ + Remove the element at index with type type in the mapinfo. + type may be one the legal element types as described in the mapinfo add command. Indices are zero based and elements are listed by type. + """ + return self.interp.call( 'mapinfo', self.name, 'remove', type, index ) + + def scale( self, factor ): + """ + """ + self.interp.call( 'mapinfo', self.name, 'scale', factor ) + + def translate( self, xAmount, yAmount ): + """ + """ + self.interp.call( 'mapinfo', self.name, 'translate', xAmount, yAmount ) + +class Videomap ( Mapinfo ): + """ + create a mapinfo from a proprietary + file format for simple maps, in use in french Air Traffic Control Centres. The format is the + binary cautra4 (with x and y in 1/8nm units) + """ + def __init__( self, tk, *args ): + """ + @type filename: + @param filename: + @type mapinfoname: + @param mapinfoname: + Load the videomap sub-map located at position index in the file named fileName into a mapinfo object named mapInfoName. It is possible, if needed, to use the videomap ids command to help translate a sub-map id into a sub-map file index. + """ + self.tk = tk.tk + args = args + ( self, ) + self.tk.call( 'videomap', 'load', *args ) + + + def ids( self, filename ): + """ + @type filename: string + @param filename: filename where to search syb-map + B{Class Method} + Return all sub-map ids that are described in the videomap file described by fileName. + The ids are listed in file order. This command makes possible to iterate through a videomap file + one sub-map at a time, to know how much sub-maps are there and to sort them according to their ids. + """ + return self.tk.call( 'videomap', 'ids', filename ) + +class Colors: + """ + Classe abstraite utilitaire permettant de gérer sous forme d'objet + les couleurs aux formats Zinc + """ + def __init__( self ): + self.lColors = [] + + #TODO: + def getColorsIter( self ): + """ + Renvoie un itérateur sur les couleurs + """ + return self.lColors.__iter__() + + def addColor( self, color, alpha = 100, + colorposition = 0, mid_span_position = 50 ): + self.lColors.append( ( color, alpha, colorposition, mid_span_position ) ) + + def __repr__( self ): + res = "" + for i in self.lColors: + res = "%s%s;%s %s %s|" % ( res, i[0], i[1], i[2], i[3] ) + return res[:-1] + +class AxialGradientColor( Colors ): + def __init__( self, *params ): + """ + params : degre or x1, y1, x2, y2 which define angle and extension of the axe + =axial degre | gradient_step1 | ... | gradient_stepn or + =axial x1 y1 x2 y2 | gradient_step1 | ... | gradient_stepn + """ + Colors.__init__( self ) + count = 0 + self.params = "" + for i in params: + self.params = "%s %s" % ( self.params, str( i ) ) + count += 1 + if ( count != 1 ) and ( count != 4 ): + raise Exception( "Bad Format of params %s" % count ) + + def __repr__( self ): + res = "=axial %s" % self.params + if not ( len( self.lColors ) ): + raise Exception( "Bad Format, must have one color less" ) + res = "%s | %s" % ( res, Colors.__repr__( self ) ) + return res + +class RadialGradientColor( Colors ): + def __init__( self, *params ): + """ + =radial x y | gradient_step1 | ... | gradient_stepn or + =radial x1 y1 x2 y2 | gradient_step1 | ... | gradient_stepn + The x y parameters define the center of the radial. + The x1 y1 x2 y2 parameters define both the center and the extension of the radial. + """ + Colors.__init__( self ) + count = 0 + self.params = "" + for i in params: + self.params = "%s %s" % ( self.params, str( i ) ) + count += 1 + if ( ( count!= 2 ) and ( count != 4 ) ): + raise Exception( "Bad Format of params %s"%count ) + + def __repr__( self ): + res = "=radial %s " % self.params + if not ( len( self.lColors ) ): + raise Exception( "Bad Format, must have one color less" ) + res = "%s | %s" % ( res, Colors.__repr__( self ) ) + return res + +class PathGradientColor( Colors ): + def __init__( self, *params ): + """ + =path x y | gradient_step1 | ... | gradient_stepn + The x y parameters define the center of the gradient. + """ + Colors.__init__( self ) + count = 0 + self.params = "" + for i in params: + self.params = "%s %s" % ( self.params, str( i ) ) + count += 1 + if ( count != 2 ): + raise Exception( "Bad Format of params %s" % count ) + + def __repr__( self ): + res = "=path %s " % self.params + if not ( len( self.lColors ) ): + raise Exception( "Bad Format, must have one color less" ) + res = "%s | %s" % ( res, Colors.__repr__( self ) ) + return res + +class ConicalGradientColor( Colors ): + def __init__( self, *params ): + """ + =conical degre | gradient_step1 | ... | gradient_stepn or + =conical degre x y | gradient_step1 | ... | gradient_stepn or + =conical x1 y1 x2 y2 | gradient_step1 | ... | gradient_stepn + + The degre parameter defines the angle of the cone in the usual trigonometric sense. + The optional x y parameters define the center of the cone. + By default, it is the center of the bounding-box. + The x1 y1 x2 y2 parameters define the center and the angle of the cone. + + All x and y coordinates are expressed in percentage of the bounding box, + relatively to the center of the bounding box. + So 0 0 means the center while -50 -50 means the lower left corner of the bounding box. + + If none of the above gradient type specification is given, + the gradient will be drawn as an axial gradient with a null angle. + """ + Colors.__init__( self ) + count = 0 + self.params = "" + for i in params: + self.params = "%s %s" % ( self.params, str( i ) ) + count += 1 + if ( count != 1 ) and ( count != 3 ) and ( count != 4 ): + raise Exception( "Bad Format of params %s" % count ) + + def __repr__( self ): + res = "=conical %s " % self.params + if not ( len( self.lColors ) ): + raise Exception( "Bad Format, must have one color less" ) + res = "%s | %s" % ( res, Colors.__repr__( self ) ) + return res + + +# ---- self-test ---------------------------------------------------------- +if __name__ == '__main__': + from Tkinter import * + import Zinc + def createItem( zinc, group, ev ): + print >> sys.stdout, "CreateIHM" + sys.stdout.flush() + Zinc.Rectangle( zinc, group, + ( 100, 100, 150, 150 ), + linewidth = "10", linecolor = '#FFFF00', + relief = "roundgroove", filled = 1, + fillcolor = "red", tags = ( "hello", "test" ) ) + sys.stdout.write( "hello_clic" + str( ev ) ) + + z = Zinc.Zinc( master = None, render = 1, height = 200, width = 400 ) + g1 = Zinc.Group( z, 1 ) + r = Zinc.Rectangle( z, g1, ( 0, 0, 400, 200 ), + linewidth = "10", + linecolor = '#FFFF00', + relief = "roundgroove", + filled = 1, + fillcolor = "#FFFFFF", + tags = ( "hello", "test" ) ) + t = Zinc.Text( z, g1, position = ( 40, 100 ), text = z.version ) +# z.bind_tag("hello","<1>",lambda ev,z=z,g=g1 : createItem(z,g,ev)) + z.configure( backcolor = 'black' ) + z.pack() + z.mainloop() + +# Zinc.py ends here + diff --git a/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/__init__.py b/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/__init__.py new file mode 100755 index 0000000..d8e4f37 --- /dev/null +++ b/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/__init__.py @@ -0,0 +1,4 @@ +from Zinc import * +import graphics +import geometry +import pictorial diff --git a/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/geometry.py b/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/geometry.py new file mode 100755 index 0000000..4063b61 --- /dev/null +++ b/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/geometry.py @@ -0,0 +1,410 @@ +# -*- coding: iso-8859-1 -*- +""" +# Geometrical basic Functions : +# ----------------------------- +# perpendicular_point +# line_angle +# linenormal +# vertex_angle +# arc_pts +# rad_point +# bezier_compute +# bezier_segment +# bezier_point +""" + +from math import pi, radians, atan2, sin, cos + +# limite globale d'approximation courbe bezier +bezierClosenessThreshold = .2 +def perpendicular_point (point, line): + """ + #--------------------------------------------------------------------------- + # Graphics::perpendicular_point + # retourne les coordonnées du point perpendiculaire abaissé d'un point + # sur une ligne + #--------------------------------------------------------------------------- + # paramètres : + # point : coordonnées du point de référence + # line : coordonnées des 2 points de la ligne de référence + #--------------------------------------------------------------------------- + """ + (p1, p2) = line + + # cas partiuculier de lignes ortho. + min_dist = .01 + if (abs(p2[1] - p1[1]) < min_dist) : + # la ligne de référence est horizontale + return (point[0], p1[1]) + + elif (abs(p2[0] - p1[0]) < min_dist) : + # la ligne de référence est verticale + return (p1[0], point[1]) + + a1 = float(p2[1] - p1[1]) / float(p2[0] - p1[0]) + b1 = p1[1] - (a1 * p1[0]) + + a2 = -1.0 / a1 + b2 = point[1] - (a2 * point[0]) + + x = (b2 - b1) / (a1 - a2) + y = (a1 * x) + b1 + + return (x, y) + +def line_angle(startpoint, endpoint): + """ + #--------------------------------------------------------------------------- + # Graphics::line_angle + # retourne l'angle d'un point par rapport à un centre de référence + #--------------------------------------------------------------------------- + # paramètres : + # startpoint : coordonnées du point de départ du segment + # endpoint : coordonnées du point d'extremité du segment + #--------------------------------------------------------------------------- + """ + angle = atan2(endpoint[1] - startpoint[1], endpoint[0] - startpoint[0]) + + angle += pi/2 + angle *= float(180)/pi + if (angle < 0): + angle += 360 + + return angle + +def linenormal(startpoint, endpoint): + """ + #--------------------------------------------------------------------------- + # Graphics::linenormal + # retourne la valeur d'angle perpendiculaire à une ligne + #--------------------------------------------------------------------------- + # paramètres : + # startpoint : coordonnées du point de départ du segment + # endpoint : coordonnées du point d'extremité du segment + #--------------------------------------------------------------------------- + """ + angle = line_angle(startpoint, endpoint) + 90 + + if (angle > 360): + angle -= 360 + return angle + +def vertex_angle(pt0, pt1, pt2): + """ + #--------------------------------------------------------------------------- + # Graphics::vertex_angle + # retourne la valeur de l'angle formée par 3 points + # ainsi que l'angle de la bisectrice + #--------------------------------------------------------------------------- + # paramètres : + # pt0 : coordonnées du premier point de définition de l'angle + # pt1 : coordonnées du deuxième point de définition de l'angle + # pt2 : coordonnées du troisième point de définition de l'angle + #--------------------------------------------------------------------------- + """ + angle1 = line_angle(pt0, pt1) + angle2 = line_angle(pt2, pt1) + + if angle2 < angle1 : + angle2 += 360 + alpha = angle2 - angle1 + bisectrice = angle1 + (float(alpha)/2) + + return (alpha, bisectrice) + + +def arc_pts(center, radius, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::arc_pts + # calcul des points constitutif d'un arc + #--------------------------------------------------------------------------- + # paramètres : + # center : centre de l'arc, + # radius : rayon de l'arc, + # options : + # -angle : angle de départ en degré de l'arc (par défaut 0) + # -extent : delta angulaire en degré de l'arc (par défaut 360), + # -step : pas de progresion en degré (par défaut 10) + #--------------------------------------------------------------------------- + """ + if center is None : + center = [0, 0] + if (options.has_key('angle')) : + angle = options['angle'] + else: + angle = 0 + if (options.has_key('extent')) : + extent = options['extent'] + else: + extent = 360 + if (options.has_key('step')) : + step = options['step'] + else: + step = 10 + pts = [] + + if (extent > 0 and step > 0) : + #A Verifier ! + alpha = angle + while(alpha <= angle+extent): + (x_n, y_n) = rad_point(center, radius, alpha) + pts.append((x_n, y_n)) + angle += step + + elif (extent < 0 and step < 0) : + #Ca me semble buggue !! + #Si extent négatif, il faut aussi que step le soit + #Si ca boucle ! + alpha = angle + while(alpha >= angle+extent): + pts.append(rad_point(center, radius, alpha)) + alpha += step + else: + raise ValueError("Step and Extent havent the same sign") + return tuple(pts) + +def rad_point(center, radius, angle): + """ + #--------------------------------------------------------------------------- + # Graphics::rad_point + # retourne le point circulaire défini par centre-rayon-angle + #--------------------------------------------------------------------------- + # paramètres : + # center : coordonnée [x,y] du centre de l'arc, + # radius : rayon de l'arc, + # angle : angle du point de circonférence avec le centre du cercle + #--------------------------------------------------------------------------- + """ + alpha = radians(angle) + + xpt = center[0] + (radius * cos(alpha)) + ypt = center[1] + (radius * sin(alpha)) + + return (xpt, ypt) + +def bezier_segment(coords, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::bezier_segment + # Calcul d'une approximation de segment (Quadratique ou Cubique) de bezier + #--------------------------------------------------------------------------- + # paramètres : + # points : <[P1, C1, , P2]> liste des points définissant + # le segment de bezier + # + # options : + # -tunits : nombre pas de division des segments bezier + # (par défaut 20) + # -skipend : : ne pas retourner le dernier point du + # segment (chainage) + #--------------------------------------------------------------------------- + """ + if (options.has_key('tunits')) : + tunits = options['tunits'] + else: + tunits = 20 + + + if options.has_key('skipend'): + skipendpt = options['skipend'] + else: + skipendpt = None + + pts = [] + + if (skipendpt) : + lastpt = tunits-1 + else: + lastpt = tunits + for i in xrange(0, lastpt+1): + if (i) : + t = (i/tunits) + else: + t = i + pts.append(bezier_point(t, coords)) + + return pts + + +def bezier_point(t, coords): + """ + #--------------------------------------------------------------------------- + # Graphics::bezier_point + # calcul d'un point du segment (Quadratique ou Cubique) de bezier + # params : + # t = (représentation du temps : de 0 à 1) + # coords = (P1, C1, , P2) liste des points définissant le segment + # de bezier P1 et P2 : extémités du segment et pts situés sur la courbe + # C1 : point(s) de contrôle du segment + #--------------------------------------------------------------------------- + # courbe bezier niveau 2 sur (P1, P2, P3) + # P(t) = (1-t)²P1 + 2t(1-t)P2 + t²P3 + # + # courbe bezier niveau 3 sur (P1, P2, P3, P4) + # P(t) = (1-t)³P1 + 3t(1-t)²P2 + 3t²(1-t)P3 + t³P4 + #--------------------------------------------------------------------------- + """ + ncoords = len(coords) + if ncoords == 3: + (p1, c1, p2) = coords + c2 = None + elif ncoords == 4: + (p1, c1, c2, p2) = coords + + # extrémités : points sur la courbe + #A VERIFIER + #Pas compris + if (not t): + return tuple(p1) + if (t >= 1.0): + return p2 + + + t2 = t * t + t3 = t2 * t + pt = [] + + # calcul pour x et y + for i in (0, 1) : + + if (c2) : + r1 = (1 - (3*t) + (3*t2) - t3) * p1[i] + r2 = ((3*t) - (6*t2) + (3*t3)) * c1[i] + r3 = ((3*t2) - (3*t3)) * c2[i] + r4 = (t3) * p2[i] + + pt[i] = (r1 + r2 + r3 + r4) + + else : + r1 = (1 - (2*t) + t2) * p1[i] + r2 = ((2*t) - (2*t2)) * c1[i] + r3 = (t2) * p2[i] + + pt[i] = (r1 + r2 + r3) + + return tuple(pt) + +def bezier_compute(coords, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::bezier_compute + # Retourne une liste de coordonnées décrivant un segment de bezier + #--------------------------------------------------------------------------- + # paramètres : + # coords : liste des points définissant le segment + # de bezier + # + # options : + # -precision : seuil limite du calcul d'approche de la courbe + # -skipend : : ne pas retourner le dernier point du segment + # (chaînage bezier) + #--------------------------------------------------------------------------- + """ + if (options.has_key('precision')) : + precision = options['precision'] + else: + precision = bezierClosenessThreshold + lastit = [] + + subdivide_bezier(coords, lastit, precision) + + if (not options.has_key('skipend') or not options['skipend']): + lastit.append(coords[3]) + + return lastit + +def smallenough_bezier(bezier, precision): + """ + #--------------------------------------------------------------------------- + # Graphics::smallEnought + # intégration code Stéphane Conversy : calcul points bezier + # (précision auto ajustée) + #--------------------------------------------------------------------------- + # distance is something like num/den with den=sqrt(something) + # what we want is to test that distance is smaller than precision, + # so we have distance < precision ? eq. to distance^2 < precision^2 ? + # eq. to (num^2/something) < precision^2 ? + # eq. to num^2 < precision^2*something + # be careful with huge values though (hence 'long long') + # with common values: 9add 9mul + #--------------------------------------------------------------------------- + """ + (pt_x, pt_y) = (0, 1) + (a, b) = (bezier[0], bezier[3]) + + den = ((a[pt_y]-b[pt_y])*(a[pt_y]-b[pt_y])) + ((b[pt_x]-a[pt_x])*(b[pt_x]-a[pt_x])) + p = precision*precision + + # compute distance between P1|P2 and P0|P3 + mat = bezier[1] + num1 = ((mat[pt_x]-a[pt_x])*(a[pt_y]-b[pt_y])) + ((mat[pt_y]-a[pt_y])*(b[pt_x]-a[pt_x])) + + mat = bezier[2] + num2 = ((mat[pt_x]-a[pt_x])*(a[pt_y]-b[pt_y])) + ((mat[pt_y]-a[pt_y])*(b[pt_x]-a[pt_x])) + + # take the max + num1 = max(num1, num2) + + if (p*den > (num1*num1)): + return 1 + else: + return 0 + +def subdivide_bezier(bezier, it, precision, integeropt): + """ + #--------------------------------------------------------------------------- + # Graphics::subdivide_bezier + # subdivision d'une courbe de bezier + #--------------------------------------------------------------------------- + """ + (b0, b1, b2, b3) = bezier + + if (smallenough_bezier(bezier, precision)) : + it.append((b0[0], b0[1])) + + else : + (left, right) = (None, None) + + for i in (0, 1) : + + if (integeropt) : + # int optimized (6+3=9)add + (5+3=8)shift + + left[0][i] = b0[i] + left[1][i] = (b0[i] + b1[i]) >> 1 + # keep precision + left[2][i] = (b0[i] + b2[i] + (b1[i] << 1)) >> 2 + + tmp = (b1[i] + b2[i]) + left[3][i] = (b0[i] + b3[i] + (tmp << 1) + tmp) >> 3 + + right[3][i] = b3[i] + right[2][i] = (b3[i] + b2[i]) >> 1 + # keep precision + right[1][i] = (b3[i] + b1[i] + (b2[i] << 1) ) >> 2 + right[0][i] = left[3][i] + + else : + # float + + left[0][i] = b0[i] + left[1][i] = float(b0[i] + b1[i]) / 2 + left[2][i] = float(b0[i] + (2*b1[i]) + b2[i]) / 4 + left[3][i] = float(b0[i] + (3*b1[i]) + (3*b2[i]) + b3[i]) / 8 + + right[3][i] = b3[i] + right[2][i] = float(b3[i] + b2[i]) / 2 + right[1][i] = float(b3[i] + (2*b2[i]) + b1[i]) / 4 + right[0][i] = float(b3[i] + (3*b2[i]) + (3*b1[i]) + b0[i]) / 8 + + + + subdivide_bezier(left, it, precision, integeropt) + subdivide_bezier(right, it, precision, integeropt) + + +#Local Variables: +#mode : python +#tab-width: 4 +#end: diff --git a/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/graphics.py b/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/graphics.py new file mode 100755 index 0000000..5277e5c --- /dev/null +++ b/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/graphics.py @@ -0,0 +1,2351 @@ +# -*- coding: iso-8859-1 -*- +""" +#------------------------------------------------------------------------------- +# +# Graphics.py +# some graphic design functions +# +#------------------------------------------------------------------------------- +# Functions to create complexe graphic component : +# ------------------------------------------------ +# build_zinc_item (realize a zinc item from description hash table +# management of enhanced graphics functions) +# +# repeat_zinc_item (duplication of given zinc item) +# +# Function to compute complexe geometrical forms : +# (text header of functions explain options for each form, +# function return curve coords using control points of cubic curve) +# ----------------------------------------------------------------- +# rounded_rectangle_coords (return curve coords of rounded rectangle) +# hippodrome_coords (return curve coords of circus form) +# ellipse_coords (return curve coords of ellipse form) +# polygon_coords (return curve coords of regular polygon) +# roundedcurve_coords (return curve coords of rounded curve) +# polyline_coords (return curve coords of polyline) +# shiftpath_coords (return curve coords of shifting path) +# tabbox_coords (return curve coords of tabbox's pages) +# pathline_coords (return triangles coords of pathline) +# +# Function to compute 2D 1/2 relief and shadow : +# function build zinc items (triangles and curve) to simulate this +# ----------------------------------------------------------------- +# graphicitem_relief (return triangle items simulate relief of given item) +# polyline_relief_params (return triangle coords +# and lighting triangles color list) +# graphicitem_shadow (return triangles and curve items +# simulate shadow of given item)) +# polyline_shadow_params (return triangle and curve coords +# and shadow triangles color list)) +# +# +#------------------------------------------------------------------------------- +# Authors: Jean-Luc Vinot +# PM2PY: Guillaume Vidon +# +# $Id: graphics.py 1697 2005-06-13 00:25:58Z vidon $ +#------------------------------------------------------------------------------- +""" +VERSION = "1.0" +__revision__ = "0.1" + +import logging +import types +import re +from geometry import * +from pictorial import * +from math import pi, radians, atan2, sqrt, sin, cos + +graphiclogger = logging.getLogger('Graphics') +debug = graphiclogger.debug +error = graphiclogger.error +exception = graphiclogger.exception +log = lambda msg : graphiclogger.log(logging.DEBUG, msg) + +# constante facteur point directeur (conique -> quadratique) +const_ptd_factor = .5523 + +def transdic(**dict): + newdic={} + for key, val in dict.items(): + if (type(val) is types.ListType): + newdic[key] = tuple(val) + else: + newdic[key] = val + return newdic + +def is_flat_list(apts): + if reduce(lambda x, y : x and (type(y) in ( types.FloatType, types.IntType)), + apts): + if len(apts) % 2: + raise ValueError("Not a valid Coords list") + else : + return True + else : + return False + +def is_point(apoint): + if (type(apoint) in ( types.TupleType, types.ListType)): + if len(apoint) == 2 : + if reduce(lambda x, y : x and (type(y) in ( types.FloatType, types.IntType)), + apts): + return True + else : + return False + elif reduce(lambda x, y : x and (type(y) in ( types.FloatType, types.IntType)), + apts[:-1])\ + and type(apts[-1]) in ('c', 'n'): + return True + else : + return False + else : + return False + +# def is_tuple_list(apts): +# if reduce(lambda x, y : x \ +# and is_point(x)), +# apts): + + +def lpts2coords(lpts): + coords = [] + if (type(lpts) in ( types.TupleType, types.ListType )): + for point in lpts : + coords.append(tuple(point)) + return tuple(coords) + +def coords2lpts(coords): + lpts = [] + if (type(coords) in ( types.TupleType, types.ListType )): + for point in coords : + lpts.append(list(point)) + else : + raise ValueError("Invalid Coords %s "%coords) + return lpts + +def build_zinc_item(widget, pgroup = 1, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::build_zinc_item + # Création d'un objet Zinc de représentation + #--------------------------------------------------------------------------- + # types d'items valides : + # 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 + # -ellipse : ellipse un centre 2 rayons + # -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) + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget Zinc + # parentgroup : identifiant du group parent + # + # options : + # -itemtype : type de l'item à construire (type zinc ou metatype) + # -coords : coordonnées de l'item + # -metacoords : calcul de coordonnées par type + # d'item différent de itemtype + # -contours : paramètres multi-contours + # -params : arguments spécifiques de l'item à passer + # au widget + # -addtags : [list of specific tags] to add to params -tags + # -texture : ajout d'une texture à l'item + # -pattern : ajout d'un pattern à l'item + # -relief : création d'un relief à l'item invoque la fonction + # graphicitem_relief() + # -shadow : création d'une ombre portée à l'item invoque + # la fonction graphicitem_shadow() + # -scale : application + # d'une transformation zinc->scale à l'item + # -translate : <[delta_x,delta_y]> application d'un transformation zinc->translate + # à l'item. + # -rotate : application d'une transformation zinc->rotate + # (en degré) à l'item + # -name : nom de l'item + # spécifiques item group : + # -clip : paramètres de clipping d'un item group + # (coords ou item) + # -items : appel récursif de la fonction permettant + # d'inclure des items au groupe + #--------------------------------------------------------------------------- + # + #--------------------------------------------------------------------------- + """ + + if options.has_key('parentgroup'): + parentgroup = options['parentgroup'] + else : + parentgroup = pgroup + try: + itemtype = options['itemtype'] + except KeyError: + raise ValueError("Must have itemtype option") + try: + coords = options['coords'] + except KeyError: + try: + coords = options['metacoords'] + except KeyError : + raise ValueError("Must have coords or metacoords option") + + if options.has_key('params'): + params = options['params'] + else: + params = {} + + #return unless($widget and $itemtype + #and ($coords or $options{'-metacoords'})) + + try: + name = options['name'] + except KeyError: + name = None + + item = None + metatype = None + items = [] + reliefs = [] + shadows = [] + tags = [] + + #-------------------- + # GEOMETRIE DES ITEMS + + # gestion des types d'items particuliers et à raccords circulaires + if (itemtype in ( 'roundedrectangle', + 'hippodrome', + 'polygone', + 'ellipse', + 'roundedcurve', + 'polyline', + 'curveline')): + + # par défaut la curve sera fermée -closed = 1 + if not params.has_key('closed'): + params['closed'] = 1 + metatype = itemtype + itemtype = 'curve' + + # possibilité de définir les coordonnées initiales par metatype + if (options.has_key('metacoords')) : + options['coords'] = meta_coords( **options['metacoords']) + + # création d'une pathline à partir d'item zinc triangles + elif (itemtype == 'pathline') : + itemtype = 'triangles' + if (options.has_key('metacoords')) : + coords = meta_coords( **options['metacoords']) + + if (options.has_key('graduate')) : + numcolors = len(coords) + lcolors = path_graduate(widget, + numcolors, + options['graduate']) + params['colors'] = tuple(lcolors) + + if options.has_key('coords'): + coords = pathline_coords(**options) + else: + coords = pathline_coords(coords, **options) + + # création d'une boite à onglet + elif (itemtype == 'tabbox') : + return build_tabboxitem(widget, parentgroup, **options) + + # calcul des coordonnées finales de la curve + if (metatype is not None): + coords = meta_coords(type = metatype, **options) + + + # gestion du multi-contours (accessible pour tous les types + # d'items géometriques) + if (options.has_key('contours') and (metatype is not None)) : + lcontours = options['contours'] + contours=[] + numcontours = len(contours) + for contour in lcontours: + # radius et corners peuvent être défini + # spécifiquement pour chaque contour + (atype, way, addcoords,) = contour[:3] + if len(contour) >= 4: + radius = contour[3] + else : + radius = None + if len(contour) >= 5: + corners = contour[4] + else: + corners = None + if len(contour) >= 6: + corners_radius = contour[5] + else : + corners_radius = None + if (radius is None): + if options.has_key('radius'): + radius = options['radius'] + else : + raise ValueError("radius option requiered") + + newcoords = meta_coords(type = metatype, + coords = addcoords, + radius = radius, + corners = corners, + corners_radius = corners_radius + ) + contours.append((atype, way, newcoords)) + + options['contours'] = contours + + #---------------------- + # REALISATION DES ITEMS + + # ITEM GROUP + # gestion des coordonnées et du clipping + if (itemtype == 'group') : + item = widget.add(itemtype, + parentgroup, + **params) + widget.addtag_withtag(name, item) + if coords: + widget.coords(item, tuple(coords)) + + # clipping du groupe par item ou par géometrie + if (options.has_key('clip')) : + clipbuilder = options['clip'] + clip = None + + # création d'un item de clipping + if (type(clipbuilder) is types.DictType + and clipbuilder.has_key('itemtype')): + clip = build_zinc_item(widget, item, **clipbuilder) + + elif (type(clipbuilder) in (types.TupleType, types.ListType) + or widget.type(clipbuilder)) : + clip = clipbuilder + + if (clip): + widget.itemconfigure(item, clip = clip) + + # créations si besoin des items contenus dans le groupe + if (options.has_key('items') + and type(options['items']) is types.DictType) : + for (itemname, itemstyle) in options['items'].items() : + if not itemstyle.has_key('name'): + itemstyle['name'] = itemname + build_zinc_item(widget, item, **itemstyle) + + + # ITEM TEXT ou ICON + elif (itemtype in ('text', 'icon')) : + imagefile = None + if (itemtype == 'icon') : + imagefile = params['image'] + image = get_image(widget, imagefile) + if (image) : + params['image'] = image + else: + params['image'] = "" + + + item = widget.add(itemtype, + parentgroup, + position = coords, + **params + ) + if imagefile: + params['image'] = imagefile + + + # ITEMS GEOMETRIQUES -> CURVE + else : + nparams=params + item = widget.add(itemtype, + parentgroup, + lpts2coords(coords), + **params + ) + + if (itemtype == 'curve' and options.has_key('contours')) : + for contour in options['contours'] : + contour = list(contour) + contour[2] = tuple(contour[2]) + widget.contour(item, *contour) + + # gestion du mode norender + if (options.has_key('texture')) : + texture = get_texture(widget, options['texture']) + if texture: + widget.itemconfigure(item, tile = texture) + + if (options.has_key('pattern')) : + bitmap = get_pattern(**options['pattern']) + if bitmap: + widget.itemconfigure(item, fillpattern = bitmap) + + # gestion des tags spécifiques + if (options.has_key('addtags')) : + tags = options['addtags'] + + params_tags = params['tags'] + if params_tags: + tags.extend(params_tags) + + widget.itemconfigure(item, tags = tags) + + #------------------------------- + # TRANSFORMATIONS ZINC DE L'ITEM + + # transformation scale de l'item si nécessaire + if (options.has_key('scale')) : + scale = options['scale'] + if (type(scale) is not types.TupleType) : + scale = (scale, scale) + widget.scale(item, scale) + + + # transformation rotate de l'item si nécessaire + if (options.has_key('rotate')): + widget.rotate(item, radians(options['rotate'])) + + # transformation translate de l'item si nécessaire + if (options.has_key('translate')): + widget.translate(item, options['translate']) + + + # répétition de l'item + if (options.has_key('repeat')) : + items.extend((item, + repeat_zinc_item(widget, item, **options['repeat']))) + + #----------------------- + # RELIEF ET OMBRE PORTEE + + # gestion du relief + if (options.has_key('relief')) : + if (len(items)) : + target = items + else: + target = item + reliefs.extend(graphicitem_relief(widget, + target, **options['relief'])) + + # gestion de l'ombre portée + if (options.has_key('shadow')) : + if (len(items)) : + target = items + else: + target = item + shadows.extend(graphicitem_shadow(widget, + target, **options['shadow'])) + + + if len(reliefs): + items.extend(reliefs) + if len(shadows): + items.extend(shadows) + + if len(items): + return items + else: + return item + +def repeat_zinc_item(widget, + item, + num = 2, + dxy = (0,0), + angle = None, + params = None, + copytag = None) : + """ + #--------------------------------------------------------------------------- + # Graphics::repeat_zinc_item + # Duplication (clonage) d'un objet Zinc de représentation + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget zinc + # item : identifiant de l'item source + # options : + # -num : nombre d'item total (par defaut 2) + # -dxy : <[delta_x, delta_y]> translation entre 2 duplications (par defaut [0,0]) + # -angle : rotation entre 2 duplications + # -copytag : ajout d'un tag indexé pour chaque copie + # -params : {clef => [value list]}> valeur de paramètre + # de chaque copie + #--------------------------------------------------------------------------- + """ + clones = [] + delta_x, delta_y = dxy + # duplication d'une liste d'items -> appel récursif + if (type(item) in (types.TupleType, types.ListType)) : + for part in item : + clones.append(repeat_zinc_item(widget, + part, + dxy, + angle, + params, + copytag)) + + return clones + + tags = [] + + if (copytag) : + tags = widget.itemcget(item, 'tags') + widget.itemconfigure(item, tags = tags + ("%s0"%copytag,)) + + for i in xrange(1, num) : + clone = None + + if (copytag) : + clone = widget.clone(item, tags = tags + ("%s%s"%(copytag, i),)) + else : + clone = widget.clone(item) + + clones.append(clone) + widget.translate(clone, delta_x*i, delta_y*i) + if angle : + widget.rotate(clone, radians(angle*i)) + + if (params is not None ) : + widget.itemconfigure(clone, **params ) + return clones + + +#MUST BE TESTED +def meta_coords( type, + coords, + **options ): + """ + #--------------------------------------------------------------------------- + # FONCTIONS GEOMETRIQUES + #--------------------------------------------------------------------------- + + #--------------------------------------------------------------------------- + # Graphics::meta_coords + # retourne une liste de coordonnées en utilisant la fonction du type + # d'item spécifié + #--------------------------------------------------------------------------- + # paramètres : (passés par %options) + # -type : type de primitive utilisée + # -coords : coordonnées nécessitée par la fonction [type]_coords + # + # les autres options spécialisées au type seront passés + # à la fonction [type]coords + #--------------------------------------------------------------------------- + """ + pts = None + + if (type == 'roundedrectangle'): + log('Coords for roundedrectangle') + pts = rounded_rectangle_coords(coords, **options) + + elif (type == 'hippodrome') : + log('Coords for hippodrome') + pts = hippodrome_coords(coords, **options) + + elif (type == 'ellipse') : + log('Coords for ellipse') + pts = ellipse_coords(coords, **options) + + elif (type == 'roundedcurve') : + log('Coords for roundedcurve') + pts = roundedcurve_coords(coords, **options) + + elif (type == 'polygone') : + log('Coords for polygone') + pts = polygon_coords(coords, **options) + + elif (type == 'polyline') : + log('Coords for polyline') + pts = polyline_coords(coords, **options) + + elif (type == 'curveline') : + log('Coords for curveline') + pts = curveline_coords(coords, **options) + + return pts + + +def zincitem_2_curvecoords( widget, item, + linear = 0, + realcoords = 0, + adjust = 1, + ): + """ + #-------------------------------------------------------------------------- + # Graphics::zincitem_2_curvecoords + # retourne une liste des coordonnées 'Curve' d'un l'item Zinc + # rectangle, arc ou curve + #-------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget zinc + # item : identifiant de l'item source + # options : + # -linear : réduction à des segments non curviligne + # (par défaut 0) + # -realcoords : coordonnées à transformer dans le groupe père + # (par défaut 0) + # -adjust : ajustement de la courbe de bezier (par défaut 1) + #-------------------------------------------------------------------------- + """ + itemtype = widget.type(item) + + if not itemtype : + raise ValueError("Not a Valid Item %s" % item) + + itemcoords = widget.coords(item) + coords = None + multi = [] + + if (itemtype == 'rectangle') : + coords = rounded_rectangle_coords(itemcoords, radius = 0) + + elif (itemtype == 'arc') : + coords = ellipse_coords(itemcoords) + if linear : + coords = curve2polyline_coords(coords, adjust) + + elif (itemtype == 'curve') : + numcontours = widget.contour(item) + + if (numcontours < 2) : + if linear: + coords = curve2polyline_coords(itemcoords, adjust) + else : + if (linear) : + multi = curveitem2polyline_coords(widget, item) + + else : + for contour in xrange(0, numcontours): + points = widget.coords(item, contour) + multi.extend(points) + coords = multi + + if (realcoords) : + parentgroup = widget.group(item) + if (len(multi)) : + newcoords = [] + for points in multi : + transcoords = widget.transform(item, parentgroup, points) + newcoords.extend(transcoords) + coords = newcoords + else : + transcoords = widget.transform(item, parentgroup, coords) + coords = transcoords + + return coords + +def rounded_rectangle_coords( coords, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::rounded_rectangle_coords + # calcul des coords du rectangle à coins arrondis + #--------------------------------------------------------------------------- + # paramètres : + # coords : coordonnées bbox (haut-gauche et bas-droite) + # du rectangle + # options : + # -radius : rayon de raccord d'angle + # -corners : liste des raccords de sommets + # [0 (aucun raccord)|1] par défaut [1,1,1,1] + #--------------------------------------------------------------------------- + """ + (x_0, y_0, x_n, y_n) = (coords[0][0], coords[0][1], + coords[1][0], coords[1][1]) + + if (options.has_key('radius')): + radius = options['radius'] + else: + radius = None + + if (options.has_key('corners')): + corners = options['corners'] + else: + corners = [1, 1, 1, 1] + + # attention aux formes 'négatives' + if (x_n < x_0) : + (x_0, x_n) = (x_n, x_0) + + if (y_n < y_0) : + (y_0, y_n) = (y_n, y_0) + + height = min(x_n -x_0, y_n - y_0) + #radius non defini dans les parametres + if (radius is None) : + radius = int(height/10) + radius = max(radius, 3) + + #radius defini mais trop petit + if ( radius < 2) : + return ((x_0, y_0), (x_0, y_n), (x_n, y_n), (x_n, y_0)) + + # correction de radius si necessaire + max_rad = height + #CODE BIZARRE + #Comment corners ne peut être non défini + #a ce niveau ? + # max_rad /= 2 if (!defined corners) + if (corners is None): + max_rad /= 2 + radius = min(max_rad, radius) + + # points remarquables + ptd_delta = radius * const_ptd_factor + (x_2, x_3) = (x_0 + radius, x_n - radius) + (x_1, x_4) = (x_2 - ptd_delta, x_3 + ptd_delta) + (y_2, y_3) = (y_0 + radius, y_n - radius) + (y_1, y_4) = (y_2 - ptd_delta, y_3 + ptd_delta) + + # liste des 4 points sommet du rectangle : angles sans raccord circulaire + angle_pts = ((x_0, y_0), (x_0, y_n), (x_n, y_n), (x_n, y_0)) + + # liste des 4 segments quadratique : raccord d'angle = radius + roundeds = [[(x_2, y_0), (x_1, y_0, 'c'), (x_0, y_1, 'c'), (x_0, y_2),], + [(x_0, y_3), (x_0, y_4, 'c'), (x_1, y_n, 'c'), (x_2, y_n),], + [(x_3, y_n), (x_4, y_n, 'c'), (x_n, y_4, 'c'), (x_n, y_3),], + [(x_n, y_2), (x_n, y_1, 'c'), (x_4, y_0, 'c'), (x_3, y_0),]] + + pts = [] + previous = None + for i in xrange(0, 4): + #BUGS ?? + if (corners[i]): + if (previous is not None) : + # on teste si non duplication de point + (nx, ny) = roundeds[i][0] + if (previous[0] == nx and previous[1] == ny) : + pts.pop() + pts.extend(roundeds[i]) + previous = roundeds[i][3] + else : + pts.append(angle_pts[i]) + + return pts + +def ellipse_coords(coords, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::ellipse_coords + # calcul des coords d'une ellipse + #--------------------------------------------------------------------------- + # paramètres : + # coords : coordonnées bbox du rectangle exinscrit + # options : + # -corners : liste des raccords de sommets + # [0 (aucun raccord)|1] par défaut [1,1,1,1] + #--------------------------------------------------------------------------- + """ + (x_0, y_0, x_n, y_n) = (coords[0][0], coords[0][1], + coords[1][0], coords[1][1]) + + if options.has_key('corners') : + corners = options.has_key('corners') + else: + corners = [1, 1, 1, 1] + + # attention aux formes 'négatives' + if (x_n < x_0) : + xs = x_0 + (x_0, x_n) = (x_n, xs) + if (y_n < y_0) : + ys = y_0 + (y_0, y_n) = (y_n, ys) + + # points remarquables + delta_x = (x_n - x_0)/2 * const_ptd_factor + delta_y = (y_n - y_0)/2 * const_ptd_factor + (x_2, y_2) = ((x_0+x_n)/2, (y_0+y_n)/2) + (x_1, x_3) = (x_2 - delta_x, x_2 + delta_x) + (y_1, y_3) = (y_2 - delta_y, y_2 + delta_y) + + # liste des 4 points sommet de l'ellipse : angles sans raccord circulaire + angle_pts = ((x_0, y_0), (x_0, y_n), (x_n, y_n), (x_n, y_0)) + + # liste des 4 segments quadratique : raccord d'angle = arc d'ellipse + roundeds = (((x_2, y_0), (x_1, y_0, 'c'), (x_0, y_1, 'c'), (x_0, y_2), ), + ((x_0, y_2), (x_0, y_3, 'c'), (x_1, y_n, 'c'), (x_2, y_n), ), + ((x_2, y_n), (x_3, y_n, 'c'), (x_n, y_3, 'c'), (x_n, y_2), ), + ((x_n, y_2), (x_n, y_1, 'c'), (x_3, y_0, 'c'), (x_2, y_0), )) + + pts = [] + previous = None + for i in xrange(0, 4): + if (corners[i]) : + if (previous) : + # on teste si non duplication de point + (nx, ny) = roundeds[i][0] + if (previous[0] == nx and previous[1] == ny) : + pts.pop() + + + pts.extend(roundeds[i]) + previous = roundeds[i][3] + + else : + pts.append(angle_pts[i]) + + return pts + + +def hippodrome_coords(coords, **options) : + """ + #--------------------------------------------------------------------------- + # Graphics::hippodrome_coords + # calcul des coords d'un hippodrome + #--------------------------------------------------------------------------- + # paramètres : + # coords : coordonnées bbox du rectangle exinscrit + # options : + # -orientation : orientation forcée de l'hippodrome [horizontal|vertical] + # -corners : liste des raccords de sommets [0|1] par défaut [1,1,1,1] + # -trunc : troncatures [left|right|top|bottom|both] + #--------------------------------------------------------------------------- + """ + (x_0, y_0, x_n, y_n) = (coords[0][0], + coords[0][1], + coords[1][0], + coords[1][1]) + + if (options.has_key('orientation')) : + orientation = options['orientation'] + else: + orientation = 'none' + + # orientation forcée de l'hippodrome + # (sinon hippodrome sur le plus petit coté) + if (orientation == 'horizontal') : + height = abs(y_n - y_0) + elif (orientation == 'vertical') : + height = abs(x_n - x_0) + else: + height = min(abs(x_n - x_0), abs(y_n - y_0)) + radius = height/2 + corners = (1, 1, 1, 1) + + if (options.has_key('corners')) : + corners = options['corners'] + + elif (options.has_key('trunc')) : + trunc = options['trunc'] + if (trunc == 'both') : + return ((x_0, y_0), (x_0, y_n), (x_n, y_n), (x_n, y_0)) + else : + if (trunc == 'left'): + corners = (0, 0, 1, 1) + elif (trunc == 'right'): + corners = (1, 1, 0, 0) + elif (trunc == 'top'): + corners = (0, 1, 1, 0) + elif (trunc == 'bottom') : + corners = (1, 0, 0, 1) + else : + corners = (1, 1, 1, 1) + + # l'hippodrome est un cas particulier de roundedRectangle + # on retourne en passant la 'configuration' à la fonction + # générique rounded_rectangle_coords + return rounded_rectangle_coords(coords, + radius = radius, + corners = corners) + +def polygon_coords(coords, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::polygon_coords + # 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 en degré du polygone + #--------------------------------------------------------------------------- + """ + if options.has_key('numsides'): + numsides = options['numsides'] + else : + numsides = 0 + if options.has_key('radius'): + radius = options['radius'] + else: + radius = None + if (numsides < 3 or not radius) : + raise ValueError("Vous devez au moins spécifier " + +"un nombre de cotés >= 3 et un rayon...\n") + + if (coords is None): + coords = (0, 0) + if (options.has_key('startangle')) : + startangle = options['startangle'] + else: + startangle = 0 + anglestep = 360/numsides + if options.has_key('inner_radius'): + inner_radius = options['inner_radius'] + else: + inner_radius = None + pts = [] + + # points du polygone + for i in xrange(0, numsides): + (xp, yp) = rad_point(coords, radius, startangle + (anglestep*i)) + pts.append((xp, yp)) + + # polygones 'étoiles' + if (inner_radius) : + (xp, yp) = rad_point(coords, inner_radius, + startangle + (anglestep*(i+ 0.5))) + pts.append((xp, yp)) + + pts.reverse() + + if (options.has_key('corner_radius')) : + if options.has_key('corners'): + corners = options['corners'] + else: + corners = None + return roundedcurve_coords(pts, + radius = options['corner_radius'], + corners = corners) + else : + return pts + + +def rounded_angle(widget, parentgroup, coords, radius) : + """ + #--------------------------------------------------------------------------- + # Graphics::rounded_angle + # THIS FUNCTION IS NO MORE USED, NEITHER EXPORTED + # curve d'angle avec raccord circulaire + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget Zinc + # parentgroup : identifiant de l'item group parent + # coords : les 3 points de l'angle + # radius : rayon de raccord + #--------------------------------------------------------------------------- + """ + (pt0, pt1, pt2) = coords + + (corner_pts, center_pts) = rounded_angle_coords(coords, radius) + (cx_0, cy_0) = center_pts + + if (parentgroup is None) : + parentgroup = 1 + + pts = [pt0] + pts.extend(corner_pts) + pts.append(pt2) + + widget.add('curve', + parentgroup, + lpts2coords(pts), + closed = 0, + linewidth = 1, + priority = 20, + ) + + +def rounded_angle_coords (coords, radius) : + """ + #--------------------------------------------------------------------------- + # Graphics::rounded_angle_coords + # 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 + #--------------------------------------------------------------------------- + # coords : les 3 points de l'angle + # radius : rayon de raccord + #--------------------------------------------------------------------------- + """ + (pt0, pt1, pt2) = coords + + # valeur d'angle et angle formé par la bisectrice + (angle, bisecangle) = vertex_angle(pt0, pt1, pt2) + + # distance au centre du cercle inscrit : rayon/sinus demi-angle + asin = sin(radians(angle/2)) + + if (asin) : + delta = abs(radius / asin) + else: + delta = radius + + # point centre du cercle inscrit de rayon $radius + if (angle < 180) : + refangle = bisecangle + 90 + else : + refangle = bisecangle - 90 + + (cx_0, cy_0) = rad_point(pt1, delta, refangle) + + # points de tangeance : pts perpendiculaires du centre aux 2 droites + (px_1, py_1) = perpendicular_point((cx_0, cy_0), (pt0, pt1)) + (px_2, py_2) = perpendicular_point((cx_0, cy_0), (pt1, pt2)) + + # point de controle de la quadratique + # facteur de positionnement sur le vecteur pt.tangence, sommet + ptd_factor = const_ptd_factor + if (angle < 90 or angle > 270) : + if (angle < 90) : + diffangle = angle + else: + diffangle = 360 - angle + if (diffangle > 15) : + ptd_factor -= (((90 - diffangle)/90) * (ptd_factor/4)) + ptd_factor = (diffangle/90) * (ptd_factor + + ((1 - ptd_factor) + * (90 - diffangle)/90)) + else : + diffangle = abs(180 - angle) + if (diffangle > 15) : + ptd_factor += (((90 - diffangle)/90) * (ptd_factor/3)) + + # delta xy aux pts de tangence + (d1x, d1y) = ((pt1[0] - px_1) * ptd_factor, (pt1[1] - py_1) * ptd_factor) + (d2x, d2y) = ((pt1[0] - px_2) * ptd_factor, (pt1[1] - py_2) * ptd_factor) + + # les 4 points de l'arc 'quadratique' + corner_pts = [(px_1, py_1), (px_1+d1x, py_1+d1y, 'c'), + (px_2+d2x, py_2+d2y, 'c'), (px_2, py_2)] + + + # retourne le segment de quadratique et le centre du cercle inscrit + return (corner_pts, (cx_0, cy_0)) + + +def roundedcurve_coords(coords, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::roundedcurve_coords + # retourne les coordonnées d'une curve à coins arrondis + #--------------------------------------------------------------------------- + # paramètres : + # coords : liste de coordonnées des 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] + #--------------------------------------------------------------------------- + """ + numfaces = len(coords) + curve_pts = [] + + if (options.has_key('radius')) : + radius = options['radius'] + else: + radius = 0 + corners = None + if options.has_key('corners') : + corners = options['corners'] + + for index in xrange(numfaces): + if (corners is not None) : + if (index+1 > len(corners)) or not corners[index] : + curve_pts.append(coords[index]) + continue + + if (index) : + prev = index - 1 + else : + prev = numfaces - 1 + if (index > numfaces - 2) : + next = 0 + else : + next = index + 1 + anglecoords = (coords[prev], coords[index], coords[next]) + + quad_pts = rounded_angle_coords(anglecoords, radius)[0] + curve_pts.extend(quad_pts) + return curve_pts + + +def polyline_coords(coords, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::polyline_coords + # retourne les coordonnées d'une polyline + #--------------------------------------------------------------------------- + # paramètres : + # coords : liste de coordonnées des 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 + #--------------------------------------------------------------------------- + """ + numfaces = len(coords) + curve_pts = [] + + if (options.has_key('radius')) : + radius = options['radius'] + else: + radius = 0 + if options.has_key('corners_radius'): + corners_radius = options['corners_radius'] + corners = corners_radius + else: + corners_radius = None + if options.has_key('corners'): + corners = options['corners'] + else: + corners = None + + for index in xrange(0, numfaces): + if (corners is not None + and (len(corners) - 1 < index + or not corners[index])): + curve_pts.append(coords[index]) + else : + if (index) : + prev = index - 1 + else: + prev = numfaces - 1 + if (index > numfaces - 2) : + next = 0 + else: + next = index + 1 + anglecoords = (coords[prev], coords[index], coords[next]) + + if (corners_radius) : + rad = corners_radius[index] + else: + rad = radius + quad_pts = rounded_angle_coords(anglecoords, rad)[0] + curve_pts.extend(quad_pts) + + return curve_pts + +def pathline_coords (coords, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::pathline_coords + # retourne les coordonnées d'une pathline + #--------------------------------------------------------------------------- + # paramètres : + # coords : liste de coordonnées des points du path + # options : + # -closed : ligne fermée + # -shifting : sens de décalage du path (par défaut center) + # -linewidth : epaisseur de la ligne + #--------------------------------------------------------------------------- + """ + numfaces = len(coords) + pts = [] + + if options.has_key('closed'): + closed = options['closed'] + else: + closed = None + if (options.has_key('linewidth')) : + linewidth = options['linewidth'] + else: + linewidth = 2 + + if (options.has_key('shifting')) : + shifting = options['shifting'] + else: + shifting = 'center' + + if ( not numfaces or linewidth < 2): + raise ValueError("Invalid PathLine_coords") + + if (closed) : + previous = coords[numfaces - 1] + else: + previous = None + + next = coords[1] + if (shifting == 'center'): + linewidth /= 2 + + for i in xrange(0, numfaces): + pt = coords[i] + + if (previous is None) : + # extrémité de curve sans raccord -> angle plat + previous = (pt[0] + (pt[0] - next[0]), pt[1] + (pt[1] - next[1])) + + (angle, bisecangle) = vertex_angle(previous, pt, next) + + # distance au centre du cercle inscrit : rayon/sinus demi-angle + asin = sin(radians(angle/2)) + if (asin) : + delta = abs(linewidth / asin) + else: + delta = linewidth + + if (shifting == 'out' or shifting == 'in') : + if (shifting == 'out') : + adding = -90 + else: + adding = 90 + pts.append(rad_point(pt, delta, bisecangle + adding)) + pts.append(pt) + + else : + pts.append(rad_point(pt, delta, bisecangle-90)) + pts.append(rad_point(pt, delta, bisecangle+90)) + + if (i == numfaces - 2) : + if (closed) : + next = coords[0] + else: + next = (coords[i+1][0] + (coords[i+1][0] - pt[0]), + coords[i+1][1] + (coords[i+1][1] - pt[1])) + elif (i == numfaces - 1): + next = None + else : + next = coords[i+2] + + previous = coords[i] + + if (closed) : + pts.extend((pts[0], pts[1], pts[2], pts[3])) + + return pts + + +def curveline_coords(coords, **options) : + """ + #--------------------------------------------------------------------------- + # Graphics::curveline_coords + # retourne les coordonnées d'une curveLine + #--------------------------------------------------------------------------- + # paramètres : + # coords : liste de coordonnées des points de la ligne + # options : + # -closed : ligne fermée + # -shifting : sens de décalage du contour + # (par défaut center) + # -linewidth : epaisseur de la ligne + #--------------------------------------------------------------------------- + """ + numfaces = len(coords) + gopts = [] + backpts = [] + pts = [] + + if options.has_key('closed'): + closed = options['closed'] + else: + closed = None + if (options.has_key('linewidth')) : + linewidth = options['linewidth'] + else: + linewidth = 2 + if (options.has_key('shifting')) : + shifting = options['shifting'] + else: + shifting = 'center' + + if( not numfaces or linewidth < 2): + raise ValueError("Bad coords %s or linewidth %s"%(numfaces, linewidth)) + + if (closed) : + previous = coords[numfaces - 1] + else: + previous = None + + next = coords[1] + if (shifting == 'center'): + linewidth /= 2 + + for i in xrange(0, numfaces): + pt = coords[i] + + if ( previous is None ) : + # extrémité de curve sans raccord -> angle plat + previous = (pt[0] + (pt[0] - next[0]), pt[1] + (pt[1] - next[1])) + + + (angle, bisecangle) = vertex_angle(previous, pt, next) + + # distance au centre du cercle inscrit : rayon/sinus demi-angle + asin = sin(radians(angle/2)) + if (asin) : + delta = abs(linewidth / asin) + else: + delta = linewidth + + if (shifting == 'out' or shifting == 'in') : + if (shifting == 'out') : + adding = -90 + else: + adding = 90 + pts.append(rad_point(pt, delta, bisecangle + adding)) + pts.append(pt) + + else : + pts = rad_point(pt, delta, bisecangle+90) + gopts.append(pts) + pts = rad_point(pt, delta, bisecangle-90) + backpts.insert(0, pts) + + if (i == numfaces - 2) : + if (closed) : + next = coords[0] + else: + next = (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] + + gopts.extend(backpts) + + if (closed) : + gopts.extend ((gopts[0], gopts[1])) + + return gopts + + +def shiftpath_coords(coords, **options) : + """ + #--------------------------------------------------------------------------- + # Graphics::shiftpath_coords + # retourne les coordonnées d'un décalage de path + #--------------------------------------------------------------------------- + # paramètres : + # coords : liste de coordonnées des points du path + # options : + # -closed : ligne fermée + # -shifting : <'out'|'in'> sens de décalage du path (par défaut out) + # -width : largeur de décalage (par défaut 1) + #--------------------------------------------------------------------------- + """ + numfaces = len(coords) + + if options.has_key('closed'): + closed = options['closed'] + else: + closed = None + if (options.has_key('width')) : + width = options['width'] + else: + width = 1 + if (options.has_key('shifting')) : + shifting = options['shifting'] + else: + shifting = 'out' + + if (not numfaces or not width): + return coords + + pts = [] + + if (closed) : + previous = coords[numfaces - 1] + else: + previous = None + next = coords[1] + + for i in xrange(0, numfaces): + pt = coords[i] + + if ( previous is None ) : + # extrémité de curve sans raccord -> angle plat + previous = (pt[0] + (pt[0] - next[0]), pt[1] + (pt[1] - next[1])) + + + (angle, bisecangle) = vertex_angle(previous, pt, next) + + # distance au centre du cercle inscrit : rayon/sinus demi-angle + asin = sin(radians(angle/2)) + if (asin) : + delta = abs(width / asin) + else: + delta = width + + if (shifting == 'out') : + adding = -90 + else: + adding = 90 + (x, y) = rad_point(pt, delta, bisecangle + adding) + pts.append((x, y)) + + + if (i > numfaces - 3) : + if (closed) : + next = coords[0] + else: + next = (pt[0] + (pt[0] - previous[0]), + pt[1] + (pt[1] - previous[1])) + + else : + next = coords[i+2] + + previous = coords[i] + + return pts + + + + +def curveitem2polyline_coords(widget, item, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::curveitem2polyline_coords + # Conversion des coordonnées Znitem curve (multicontours) + # en coordonnées polyline(s) + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget zinc + # item : identifiant de l'item source + # options : + # -tunits : nombre pas de division des segments bezier + # (par défaut 20) + # -adjust : ajustement de la courbe de bezier (par défaut 1) + #--------------------------------------------------------------------------- + """ + if (not widget.type(item)): + raise ValueError("Item Not Found") + coords = [] + numcontours = widget.contour(item) + #parentgroup = widget.group(item) + + for contour in xrange(0, numcontours): + points = widget.coords(item, contour) + contourcoords = curve2polyline_coords(points, **options) + + coords.append(contourcoords) + + return coords + +def curve2polyline_coords(points, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::curve2polyline_coords + # Conversion curve -> polygone + #--------------------------------------------------------------------------- + # paramètres : + # points : liste des coordonnées curve à transformer + # options : + # -tunits : nombre pas de division des segments bezier + # (par défaut 20) + # -adjust : ajustement de la courbe de bezier (par défaut 1) + #--------------------------------------------------------------------------- + """ + if (options.has_key('tunits')) : + tunits = options['tunits'] + else: + tunits = 20 + if (options.has_key('adjust')) : + adjust = options['adjust'] + else: + adjust = 1 + + poly = [] + previous = None + bseg = [] + numseg = 0 + #prevtype = None + + for point in points: + if len(point) == 3: + (x, y, c) = point + elif len(point) == 2: + (x, y, c) = (point, None) + else: + ValueError("Bad point") + if (c == 'c') : + if not len(bseg) and previous: + bseg.append(previous) + bseg.append(point) + + else : + if (len (bseg)) : + bseg.append(point) + if (adjust) : + pts = bezier_compute(bseg, skipend = 1) + del pts[0] + del pts[0] + poly.extend(pts) + + else : + pts = bezier_segment(bseg, tunits = tunits, skipend = 1) + del pts[0] + del pts[0] + poly.extend(pts) + + bseg = [] + numseg += 1 + #prevtype = 'bseg' + + else : + poly.append((x, y)) + #prevtype = 'line' + + previous = point + + + return poly + + +def build_tabboxitem(widget, parentgroup, **options): + """ + #------------------------------------------------------------------------------- + # Graphics::build_tabboxitem + # construit les items de représentations Zinc d'une boite à onglets + #------------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget zinc + # parentgroup : identifiant de l'item group parent + # + # options : + # -coords : coordonnées haut-gauche et bas-droite + # du rectangle + # englobant du Tabbox + # -params : arguments spécifiques des items curve + # à passer au widget + # -texture : ajout d'une texture aux items curve + # -tabtitles : table de hash de définition des titres onglets + # -pageitems : table de hash de définition des pages internes + # -relief : table de hash de définition du relief de forme + # + # (options de construction géometrique passées à tabbox_coords) + # -numpages : nombre de pages (onglets) de la boite + # -anchor : <'n'|'e'|'s'|'w'> ancrage (positionnement) de la ligne + # d'onglets + # -alignment : <'left'|'center'|'right'> alignement des onglets sur le coté + # d'ancrage + # -tabwidth : <'auto'>|| : largeur des onglets + # 'auto' largeur répartie, les largeurs sont auto-ajustée + # si besoin. + # -tabheight : <'auto'>| : hauteur des onglets + # -tabshift : <'auto'>| offset de 'biseau' entre base et haut de + # l'onglet (défaut auto) + # -radius : rayon des arrondis d'angle + # -overlap : <'auto'>| offset de recouvrement/séparation entre + # onglets + # -corners : liste 'spécifique' des raccords de sommets [0|1] + #--------------------------------------------------------------------------- + """ + if options.has_key('coords') : + coords = options['coords'] + else: + raise ValueError("Coords needed") + if options.has_key('params'): + params = options['params'] + else: + params = {} + if params.has_key('tags'): + tags = params['tags'] + else : + tags = [] + texture = None + + if (options.has_key('texture')) : + texture = get_texture(widget, + options['texture']) + + + if options.has_key('tabtitles'): + titlestyle = options['tabtitles'] + else : + titlestyle = None + if (titlestyle) : + titles = titlestyle['text'] + else: + titles = None + + tabs = [] + (shapes, tcoords, invert) = tabbox_coords(**options) + if (invert) : + k = len(shapes) + else: + k = -1 + shapes.reverse() + for shape in shapes : + if (invert) : + k -= 1 + else : + k += +1 + group = widget.add('group', parentgroup) + params['tags'] = tags + params['tags'] += (k, 'intercalaire') + form = widget.add('curve', + group, + lpts2coords(shape), + **params) + if texture : + widget.itemconfigure(form, tile = texture) + + if (options.has_key('relief')) : + graphicitem_relief(widget, form, **options['relief']) + + + if (options.has_key('page')) : + build_zinc_item(widget, group, **options['page']) + + if (titles) : + if (invert) : + tindex = k + else: + tindex = len(shapes) - k + titlestyle['itemtype'] = 'text' + titlestyle['coords'] = tcoords[tindex] + titlestyle['params']['text'] = titles[tindex] + ltags = list(tags) + ltags.append(tindex) + ltags.append('titre') + titlestyle['params']['tags'] = tuple(ltags) + build_zinc_item(widget, group, **titlestyle) + + return tabs + + +def tabbox_coords(coords, **options): + """ + #--------------------------------------------------------------------------- + # tabbox_coords + # Calcul des shapes de boites à onglets + #--------------------------------------------------------------------------- + # paramètres : + # coords : coordonnées haut-gauche bas-droite du rectangle + # englobant de la tabbox + # options + # -numpages : nombre de pages (onglets) de la boite + # -anchor : <'n'|'e'|'s'|'w'> ancrage (positionnement) de la + # ligne d'onglets + # -alignment : <'left'|'center'|'right'> alignement des onglets + # sur le coté d'ancrage + # -tabwidth : <'auto'>|| : largeur des onglets + # 'auto' largeur répartie, les largeurs sont auto-ajustée + # si besoin. + # -tabheight : <'auto'>| : hauteur des onglets + # -tabshift : <'auto'>| offset de 'biseau' entre base et haut + # de l'onglet (défaut auto) + # -radius : rayon des arrondis d'angle + # -overlap : <'auto'>| offset de recouvrement/séparation + # entre onglets + # -corners : liste 'spécifique' des raccords + # de sommets [0|1] + #--------------------------------------------------------------------------- + """ + (x_0, y_0) = coords[0] + (x_n, y_n) = coords[1] + shapes, titles_coords = [], [] + inverse = None + + #loptions = options.keys() + if options.has_key('numpages'): + numpages = options['numpages'] + else: + numpages = 0 + + if (not x_0 or not y_0 or not x_n or not y_n or not numpages) : + raise ValueError("Vous devez au minimum spécifier\ + le rectangle englobant et le nombre de pages") + + if (options.has_key('anchor')) : + anchor = options['anchor'] + else: + anchor = 'n' + if (options.has_key('alignment')) : + alignment = options['alignment'] + else: + alignment ='left' + + + if (options.has_key('tabwidth')) : + nlen = options['tabwidth'] + else: + nlen ='auto' + if (options.has_key('tabheight')) : + thick = options['tabheight'] + else: + thick ='auto' + if (options.has_key('tabshift')) : + biso = options['tabshift'] + else: + biso = 'auto' + if (options.has_key('radius')) : + radius = options['radius'] + else: + radius = 0 + if (options.has_key('overlap')) : + overlap = options['overlap'] + else: + overlap = 0 + if (options.has_key('corners')): + corners = options['corners'] + else: + corners = None + if (anchor in ( 'n', 's')) : + orientation = 'horizontal' + else: + orientation = 'vertical' + if (orientation == 'horizontal') : + maxwidth = (x_n - x_0) + else: + maxwidth = (y_n - y_0) + tabswidth = 0 + align = 1 + + if (nlen == 'auto') : + tabswidth = maxwidth + nlen = float(tabswidth + (overlap * (numpages - 1)))/numpages + else : + if (type(nlen) in (types.TupleType, types.ListType )) : + for w in nlen : + tabswidth += (w - overlap) + + tabswidth += overlap + else : + tabswidth = (nlen * numpages) - (overlap * (numpages - 1)) + + + if (tabswidth > maxwidth) : + tabswidth = maxwidth + nlen = float(tabswidth + (overlap * (numpages - 1)))/numpages + + if (alignment == 'center' and ((maxwidth - tabswidth) > radius)): + align = 0 + + + if (thick == 'auto') : + if (orientation == 'horizontal') : + thick = int((y_n - y_0)/10) + else: + thick = int((x_n - y_0)/10) + thick = max(10, thick) + thick = min(40, thick) + + if (biso == 'auto') : + biso = int(thick/2) + + if ((alignment == 'right' and anchor != 'w') or + (anchor == 'w' and alignment != 'right')) : + + if (type(nlen) in (types.TupleType, types.ListType)) : + for p in xrange(0, numpages): + nlen[p] *= -1 + else : + nlen *= -1 + biso *= -1 + overlap *= -1 + + if (alignment == 'center') : + (biso1, biso2) = (biso/2, biso/2) + else: + (biso1, biso2) = (0, biso) + + cadre, tabdxy = [], [] + xref, yref = 0, 0 + if (orientation == 'vertical') : + if (anchor == 'w'): + thick *= -1 + if (anchor == 'w') : + (startx, endx) = (x_0, x_n) + else: + (startx, endx) = (x_n, x_0) + if ((anchor == 'w' and alignment != 'right') or + (anchor == 'e' and alignment == 'right')) : + (starty, endy) = (y_n, y_0) + else: + (starty, endy) = (y_0, y_n) + + xref = startx - thick + yref = starty + if (alignment == 'center') : + if (anchor == 'w') : + ratio = -2 + else: + ratio = 2 + yref += (float(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 == 'right') + + else : + if (anchor == 's'): + thick *= -1 + (starty, endy) = (y_n, y_0) + else : + (starty, endy) = (y_0, y_n) + + if (alignment == 'right') : + (startx, endx) = (x_n, x_0) + else: + (startx, endx) = (x_0, x_n) + + + yref = starty + thick + if (alignment == 'center') : + xref = x_0 + (float(maxwidth - tabswidth)/2) + else : + xref = 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 == 'n' and alignment != 'right') + or (anchor == 's' and alignment == 'right')) + + + for i in xrange(0, numpages): + pts = [] + + # décrochage onglet + #push (pts, ([xref, yref])) if i > 0 + + # cadre + pts.extend(cadre) + + # points onglets + if (i > 0 or not align) : + pts.append((xref, yref)) + + if (type(nlen) in (types.TupleType, types.ListType)) : + tw = nlen[i] + else: + tw = nlen + + if (type(nlen) in (types.TupleType, types.ListType)) : + slen = len(nlen) + else: + slen = nlen + + if (orientation == 'vertical') : + tabdxy = ((thick, biso1), (thick, tw - biso2), (0, tw)) + else: + tabdxy = ((biso1, -thick), (tw - biso2, -thick), (tw, 0)) + for delta_xy in tabdxy : + pts.append((xref + delta_xy[0], yref + delta_xy[1])) + + + if (radius) : + if (not options.has_key('corners')) : + if (i > 0 or not align) : + corners = (0, 1, 1, 0, 0, 1, 1, 0) + else : + corners = (0, 1, 1, 0, 1, 1, 0, 0, 0) + + curvepts = roundedcurve_coords(pts, + radius = radius, + corners = corners) + lcurvepts = list(curvepts) + if (inverse): + lcurvepts.reverse() + shapes.append(lcurvepts) + else : + if (inverse): + pts.reverse() + shapes.append(pts) + + if (orientation == 'horizontal') : + titles_coords.append((float(xref) + (tw - (biso2 - biso1))/2, + float(yref) - (thick/2))) + xref += (tw - overlap) + + else : + titles_coords.append( (float(xref) + (thick/2), + yref + (slen - ((biso2 - biso1)/2))/2)) + yref += (slen - overlap) + + return (shapes, titles_coords, inverse) + + +def graphicitem_relief(widget, item, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::graphicitem_relief + # construit un relief à l'item Zinc en utilisant des items Triangles + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget zinc + # item : identifiant de l'item zinc + # options : table d'options + # -closed : le relief assure la fermeture de forme (défaut 1) + # -profil : <'rounded'|'flat'> type de profil (defaut 'rounded') + # -relief : <'raised'|'sunken'> (défaut 'raised') + # -side : <'inside'|'outside'> relief interne ou externe à la forme + # (défaut 'inside') + # -color : couleur du relief (défaut couleur de la forme) + # -smoothed : facettes relief lissées ou non (défaut 1) + # -lightangle : angle d'éclairage (défaut valeur générale widget) + # -width : 'épaisseur' du relief en pixel + # -fine : mode précision courbe de bezier + # (défaut 0 : auto-ajustée) + #------------------------------------------------------------------------------- + """ + items = [] + + # relief d'une liste d'items -> appel récursif + if (type(item) in (types.TupleType, types.ListType)) : + for part in item : + items.extend(graphicitem_relief(widget, part, **options)) + else : + itemtype = widget.type(item) + if not itemtype: + raise ValueError("Bad Item") + + parentgroup = widget.group(item) + if (options.has_key('priority')) : + priority = options['priority'] + else : + priority = widget.itemcget(item, 'priority')+1 + + # coords transformés (polyline) de l'item + adjust = not options['fine'] + for coords in zincitem_2_curvecoords(widget, + item, linear = 1, + realcoords = 1, + adjust = adjust) : + (pts, colors) = polyline_relief_params(widget, + item, + coords, + **options) + + items.append(widget.add('triangles', + parentgroup, + pts, + priority = priority, + colors = colors)) + + + # renforcement du contour + if (widget.itemcget(item, 'linewidth')) : + items.append(widget.clone(item, + filled = 0, + priority = priority+1)) + + return items + + +def polyline_relief_params(widget, item, coords, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::polyline_relief_params + # retourne la liste des points et des couleurs nécessaires à la construction + # de l'item Triangles du relief + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant widget Zinc + # item : identifiant item Zinc + # options : table d'options + # -closed : le relief assure la fermeture de forme (défaut 1) + # -profil : <'rounded'|'flat'> type de profil (defaut 'rounded') + # -relief : <'raised'|'sunken'> (défaut 'raised') + # -side : <'inside'|'outside'> relief interne ou externe à la forme + # (défaut 'inside') + # -color : couleur du relief (défaut couleur de la forme) + # -smoothed : facettes relief lissées ou non (défaut 1) + # -lightangle : angle d'éclairage (défaut valeur générale widget) + # -width : 'épaisseur' du relief en pixel + #--------------------------------------------------------------------------- + """ + + if (options.has_key('closed')) : + closed = options['closed'] + else: + closed = 1 + if (options.has_key('profil')) : + profil = options['profil'] + else: + profil = 'rounded' + if (options.has_key('relief')) : + relief = options['relief'] + else : + relief = 'raised' + if (options.has_key('side')) : + side = options['side'] + else: + side = 'inside' + if (options.has_key('color')) : + basiccolor = options['color'] + else: + basiccolor = zincitem_predominantcolor(widget, item) + if (options.has_key('smooth')) : + smoothed = options['smooth'] + else: + smoothed = 1 + if (options.has_key('lightangle')) : + lightangle = options['lightangle'] + else: + lightangle = widget.cget('lightangle') + + if options.has_key('width'): + width = options['width'] + else: + raise ValueError('Options must have width field') + if ( width < 1) : + (x_0, y_0, x_1, y_1) = widget.bbox(item) + width = min(x_1 -x_0, y_1 - y_0)/10 + if (width < 2) : + width = 2 + + numfaces = len(coords) + if (closed): + previous = coords[numfaces - 1] + else: + previous = None + next = coords[1] + + pts = [] + colors = [] + alpha = 100 + m = re.compile("^(?P#[0-9a-fA-F]{6});(?P\d{1,2})$") + res = m.match(basiccolor) + if (res is not None) : + (basiccolor, alpha) = res.group('color'), res.group('alpha') + + if ( options.has_key('color')): + color = options['color'] + res = m.match(color) + if ((res is None) and (profil == 'flat')): + alpha /= 2 + + if (profil == 'rounded') : + reliefalphas = [0, alpha] + else: + reliefalphas = [alpha, alpha] + + for i in xrange(0, numfaces): + 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])) + + + (angle, bisecangle) = vertex_angle(previous, pt, next) + + # distance au centre du cercle inscrit : rayon/sinus demi-angle + asin = sin(radians(angle/2)) + if (asin) : + delta = abs(width / asin) + else: + delta = width + if (side == 'outside') : + decal = -90 + else: + decal = 90 + + shift_pt = rad_point(pt, delta, bisecangle+decal) + pts.append(shift_pt) + pts.append(pt) + + if (smoothed and i) : + pts.append(shift_pt) + pts.append(pt) + + + faceangle = 360 -(linenormal(previous, next)+90) + + light = abs(lightangle - faceangle) + if (light > 180): + light = 360 - light + if light < 1: + light = 1 + + if (relief == 'sunken') : + lumratio = (180-light)/180 + else: + lumratio = light/180 + + if ( not smoothed and i) : + #A VOIR + #OBSCURE + colors.extend((colors[-2], colors[-1])) + + if (basiccolor) : + # création des couleurs dérivées + shade = lightingcolor(basiccolor, lumratio) + color0 = "%s;%s"% (shade, reliefalphas[0]) + color1 = "%s;%s"% (shade, reliefalphas[1]) + colors.extend((color0, color1)) + + else : + c = (255*lumratio) + color0 = hexargbcolor(c, c, c, reliefalphas[0]) + color1 = hexargbcolor(c, c, c, reliefalphas[1]) + colors.extend((color0, color1)) + + + if (i == (numfaces - 2)) : + if (closed) : + next = coords[0] + else: + next = (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) : + pts.extend((pts[0], pts[1], pts[2], pts[3])) + colors.extend((colors[0], colors[1])) + + if (not smoothed) : + pts.extend((pts[0], pts[1], pts[2], pts[3])) + colors.extend((colors[0], colors[1])) + + return (pts, colors) + + +def graphicitem_shadow(widget, item, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::graphicitem_shadow + # Création d'une ombre portée à l'item + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant widget Zinc + # item : identifiant item Zinc + # options : table d'options + # -opacity : opacité de l'ombre (défaut 50) + # -filled : remplissage totale de l'ombre (hors bordure) (defaut 1) + # -lightangle : angle d'éclairage (défaut valeur générale widget) + # -distance : distance de projection de l'ombre en pixel + # -enlarging : grossi de l'ombre portée en pixels (defaut 0) + # -width : taille de diffusion/diffraction (défaut 4) + # -color : couleur de l'ombre portée (défaut black) + #--------------------------------------------------------------------------- + """ + items = [] + + # relief d'une liste d'items -> appel récursif + if (type(item) in (types.TupleType, types.ListType)) : + for part in item : + items.append(graphicitem_shadow(widget, part, **options)) + return items + + else : + + itemtype = widget.type(item) + + if not itemtype : + raise ValueError("Not a valid Item Id %s"%item) + + # création d'un groupe à l'ombre portée + if (options.has_key('parentgroup')) : + parentgroup = options['parentgroup'] + else: + parentgroup = widget.group(item) + if (options.has_key('priority')) : + priority = options['priority'] + else: + priority = widget.itemcget(item, 'priority')-1 + priority = max(0, priority) + + shadow = widget.add('group', parentgroup, priority = priority) + + if (itemtype == 'text') : + if (options.has_key('opacity')) : + opacity = options['opacity'] + else: + opacity = 50 + if (options['color']) : + color = options['color'] + else: + color = '#000000' + + clone = widget.clone(item, color = "%s;%s"% (color, opacity)) + widget.chggroup(clone, shadow) + + else : + + # création des items (de dessin) de l'ombre + if ( options.has_key('filled')) : + filled = options['filled'] + else: + filled = 1 + + # coords transformés (polyline) de l'item + for coords in zincitem_2_curvecoords(widget, + item, + linear = 1, + realcoords = 1) : + (t_pts, i_pts, colors) = polyline_shadow_params( coords, + **options) + + # option filled : remplissage hors bordure + # de l'ombre portée (item curve) + if (filled) : + if (len(items)) : + widget.contour(items[0], 'add', 0, i_pts) + + else : + items.append( widget.add('curve', shadow, i_pts, + linewidth = 0, + filled = 1, + fillcolor = colors[0], + )) + + # bordure de diffusion de l'ombre (item triangles) + items.append( widget.add('triangles', shadow, t_pts, + colors = colors)) + + + # positionnement de l'ombre portée + if (options.has_key('distance')) : + distance = options['distance'] + else: + distance = 10 + if (options.has_key('lightangle')) : + lightangle = options['lightangle'] + else: + lightangle = widget.cget('lightangle') + + (delta_x, delta_y) = rad_point((0, 0), + distance, + lightangle+180) + widget.translate(shadow, delta_x, -delta_y) + + return shadow + + +def polyline_shadow_params(coords, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::polyline_shadow_params + # retourne les listes des points et de couleurs nécessaires à la + # construction des items triangles (bordure externe) et curve + # (remplissage interne) de l'ombre portée + #--------------------------------------------------------------------------- + # paramètres : + # coords : coordonnées + # options : table d'options + # -opacity : opacité de l'ombre (défaut 50) + # -lightangle : angle d'éclairage (défaut valeur générale widget) + # -distance : distance de projection de l'ombre en pixel + # (défaut 10) + # -enlarging : grossi de l'ombre portée en pixels (defaut 2) + # -width : taille de diffusion/diffraction + # (défaut distance -2) + # -color : couleur de l'ombre portée (défaut black) + #--------------------------------------------------------------------------- + """ + if (options.has_key('distance')) : + distance = options['distance'] + else: + distance = 10 + if (options.has_key('width')) : + width = options['width'] + else: + width = distance-2 + if (options.has_key('opacity')) : + opacity = options['opacity'] + else: + opacity = 50 + if (options.has_key('color')) : + color = options['color'] + else: + color ='#000000' + if (options.has_key('enlarging')) : + enlarging = options['enlarging'] + else : + enlarging = 2 + + if (enlarging) : + coords = shiftpath_coords(coords, + width = enlarging, + closed = 1, + shifting = 'out') + + numfaces = len(coords) + previous = coords[numfaces - 1] + next = coords[1] + + t_pts = [] + i_pts = [] + colors = [] + (color0, color1) = ("%s;%s"% (color, opacity), "%s;0"% color) + + for i in xrange(0, numfaces): + pt = coords[i] + + #A VOIR + #Je ne vois pas quand cela peut arriver + if (not previous) : + # extrémité de curve sans raccord -> angle plat + previous = (pt[0] + (pt[0] - next[0]), pt[1] + (pt[1] - next[1])) + + (angle, bisecangle) = vertex_angle(previous, pt, next) + + # distance au centre du cercle inscrit : rayon/sinus demi-angle + asin = sin(radians(angle/2)) + if (asin) : + delta = abs(width / asin) + else : + delta = width + decal = 90 + + shift_pt = rad_point(pt, delta, bisecangle+decal) + i_pts.append(shift_pt) + t_pts.append(shift_pt) + t_pts.append(pt) + + colors.append(color0) + colors.append(color1) + if (i == numfaces - 2) : + next = coords[0] + else : + next = coords[i+2] + + previous = coords[i] + + # fermeture + t_pts.extend((t_pts[0], t_pts[1], t_pts[2], t_pts[3])) + i_pts.extend((t_pts[0], t_pts[1])) + colors.extend((color0, color1, color0, color1)) + + return (t_pts, i_pts, colors) + + + + + +#Local Variables: +#mode : python +#tab-width: 4 +#end: diff --git a/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/pictorial.py b/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/pictorial.py new file mode 100755 index 0000000..1599935 --- /dev/null +++ b/debian/zinc-python/usr/lib/python2.7/dist-packages/Zinc/pictorial.py @@ -0,0 +1,766 @@ +# -*- coding: iso-8859-1 -*- +# Pictorial Functions : +# ---------------------- +# set_gradients +# get_pattern +# get_texture +# get_image +# init_pixmaps +# zincitem_predominantcolor +# zncolor_to_rgb +# hexargbcolor +# create_graduate +# path_graduate +# mediancolor +# lightingcolor +# rgb_to_lch +# lch_to_rgb +# rgb_to_hls +# hls_to_rgb + +import PIL.Image, PIL.ImageTk +import re +from math import pi, radians, atan2, sqrt, sin, cos + +# initialisation et partage de ressources couleurs et images +textures = {} +IMAGES = {} +bitmaps = {} +AVERAGE_COLOR = '#777777' + + +_GRADIENTS = [] + +# constante white point (conversion couleur espace CIE XYZ) +(Xw, Yw, Zw) = (95.047, 100.0, 108.883) + +def set_gradients(zinc, **grads): + """ + #--------------------------------------------------------------------------- + # Graphics::set_gradients + # création de gradient nommés Zinc + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget zinc + # **grads : de définition de couleurs zinc + #--------------------------------------------------------------------------- + """ + global _GRADIENTS + if (not _GRADIENTS): + _GRADIENTS = [] + for (name, gradient) in grads.items(): + zinc.gname(gradient, name) + _GRADIENTS.append(name) + +def rgb_dec2hex(rgb): + """ + #--------------------------------------------------------------------------- + # Graphics::rgb_dec2hex + # conversion d'une couleur RGB (255,255,255) au format Zinc '#ffffff' + #--------------------------------------------------------------------------- + # paramètres : + # rgb : liste de couleurs au format RGB + #--------------------------------------------------------------------------- + """ + return "#%04x%04x%04x"% rgb + +def path_graduate(zinc, numcolors, style): + """ + #--------------------------------------------------------------------------- + # Graphics::path_graduate + # création d'un jeu de couleurs dégradées pour item pathline + #--------------------------------------------------------------------------- + """ + typ = style['type'] + if (typ == 'linear'): + return create_graduate(numcolors, style['colors'], 2) + elif (typ == 'double'): + colors1 = create_graduate(numcolors/2+1, + style['colors'][0]) + colors2 = create_graduate(numcolors/2+1, + style['colors'][1]) + colors = [] + for i in xrange(numcolors+1): + colors.extend([colors1[i], colors2[i]]) + return colors + elif (typ == 'transversal'): + (c1, c2) = style['colors'] + colors = [c1, c2] + for i in xrange(numcolors): + colors.extend([c1, c2]) + + return colors + +def create_graduate(totalsteps, refcolors, repeat = 1): + """ + #--------------------------------------------------------------------------- + # Graphics::create_graduate + # création d'un jeu de couleurs intermédiaires (dégradé) entre n couleurs + #--------------------------------------------------------------------------- + """ + colors = [] + + numgraduates = len(refcolors) - 1 + if (numgraduates < 1): + raise ValueError("Le degradé necessite\ + au moins 2 couleurs de référence...") + steps = None + if (numgraduates > 1): + steps = totalsteps/(numgraduates - 1) + else: + steps = totalsteps + + for c in xrange(numgraduates): + (c1, c2) = (refcolors[c], refcolors[c + 1]) + + for i in xrange(steps): + color = mediancolor(c1, c2, i / (steps - 1)) + for it in xrange(repeat): + colors.append(color) + + if (c < numgraduates - 1): + for k in xrange(repeat): + colors.pop() + + return colors + +def lightingcolor (color, new_l) : + """ + #--------------------------------------------------------------------------- + # Graphics::lightingcolor + # modification d'une couleur par sa composante luminosité + #--------------------------------------------------------------------------- + # paramètres : + # color : couleur au format zinc + # new_l : (de 0 à 1) nouvelle valeur de luminosité + #--------------------------------------------------------------------------- + """ + (h, l, s) = 0, 0, 0 + rgb = hexa2rgb(color) + h, l, s = rgb_to_hls(rgb) + new_l = min(new_l, 1) + (n_r, n_g, n_b) = hls_to_rgb(h, new_l, s) + return hexargbcolor(n_r*255, n_g*255, n_b*255) + + +def get_predominantcolor(colors): + """ + #--------------------------------------------------------------------------- + # Graphics::get_predominantcolor + # donne la couleur dominante + #--------------------------------------------------------------------------- + # paramètres : + # colors : * liste de couleurs au format zinc + #--------------------------------------------------------------------------- + """ + (rs, gs, bs, as_, numcolors) = (0, 0, 0, 0, 0) + for color in colors : + (r, g, b, a) = zncolor_to_rgb(color) + rs += r + gs += g + bs += b + as_ += a + numcolors += 1 + + new_r = int(rs/numcolors) + new_g = int(gs/numcolors) + new_b = int(bs/numcolors) + new_a = int(as_/numcolors) + + newcolor = hexargbcolor(new_r, new_g, new_b, new_a) + return newcolor + +def zincitem_predominantcolor(widget, item): + """ + #--------------------------------------------------------------------------- + # Graphics::zincitem_predominantcolor + # retourne la couleur dominante d'un item ('barycentre' gradiant fillcolor) + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget zinc + # item : identifiant de l'item zinc + #--------------------------------------------------------------------------- + """ + typ = widget.type(item) + if not typ : + raise ValueError("Not a Valid Item %s" % item) + if (typ == 'text' or typ == 'icon') : + return widget.itemcget(item, 'color') + + elif (typ == 'triangles' or + typ == 'rectangle' or + typ == 'arc' or + typ == 'curve') : + + colors = [] + + if (typ == 'triangles') : + colors = widget.itemcget(item, 'colors') + else : + grad = widget.itemcget(item, 'fillcolor') + regexp = re.compile( + "^=(?P\w+)(?P[^|]+)\|(?P.*)$") + res = regexp.match(grad) + if (res is None): + #couleur simple + return grad + else: + #Gradient + colorspart = res.group('colorparts').split("|") + regexp_color = re.compile("^(?P^\S+).*") + for colorpart in colorspart: + res = regexp_color.match(colorpart) + if res: + colors.append(res.group('color')) + else : + raise ValueError("Impossible case!!") + return get_predominantcolor(colors) + else : + return AVERAGE_COLOR + +def mediancolor (color1, color2, rate) : + """ + #--------------------------------------------------------------------------- + # Graphics::mediancolor + # calcul d'une couleur intermédiaire défini par un ratio ($rate) + # entre 2 couleurs + #--------------------------------------------------------------------------- + # paramètres : + # color1 : première couleur zinc + # color2 : seconde couleur zinc + # rate : (de 0 à 1) position de la couleur intermédiaire + #--------------------------------------------------------------------------- + """ + if (rate > 1): + rate = 1 + if (rate < 0): + rate = 0 + + (r0, g0, b0, a0) = zncolor_to_rgb(color1) + (r1, g1, b1, a1) = zncolor_to_rgb(color2) + + r = r0 + int((r1 - r0) * rate) + g = g0 + int((g1 - g0) * rate) + b = b0 + int((b1 - b0) * rate) + a = a0 + int((a1 - a0) * rate) + + return hexargbcolor(r, g, b, a) + + +def zncolor_to_rgb (zncolor): + """ + #--------------------------------------------------------------------------- + # Graphics::zncolor_to_rgb + # conversion d'une couleur Zinc au format RGBA (255,255,255,100) + #--------------------------------------------------------------------------- + # paramètres : + # zncolor : couleur au format hexa zinc (#ffffff ou #ffffffffffff) + #--------------------------------------------------------------------------- + """ + #Recherche du format d'entrée + # ffffff ou ffffffffffff avec ou sans alpha + #test présence alpha + res = [] + res.append( + re.match( + "^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2});(?P\d{1,3})$" + ,zncolor)) + res.append( + re.match( + "^#([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4});(?P\d{1,3})$" + ,zncolor)) + #Pas de alpha + res.append(re.match("^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$" + ,zncolor)) + res.append(re.match("^#([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})$" + ,zncolor)) + res.sort() + resultat = res.pop() + if res is None: + raise ValueError("Not a valid zinc color") + alpha = 100 + res = resultat.groupdict() + if res.has_key('alpha'): + alpha = int(res['alpha']) + else: + alpha = 100 + + R = int(resultat.group(1), 16) + G = int(resultat.group(2), 16) + B = int(resultat.group(3), 16) + + return (R, G, B, alpha) + +def rgb_to_lch(r, g, b) : + """ + #--------------------------------------------------------------------------- + # ALGORYTHMES DE CONVERSION ENTRE ESPACES DE COULEURS + #--------------------------------------------------------------------------- + #--------------------------------------------------------------------------- + # Graphics::rgb_to_lch + # Algorythme de conversion RGB -> CIE LCH° + #--------------------------------------------------------------------------- + # paramètres : + # r : (de 0 à 1) valeur de la composante rouge de la couleur RGB + # g : (de 0 à 1) valeur de la composante verte de la couleur RGB + # b : (de 0 à 1) valeur de la composante bleue de la couleur RGB + #--------------------------------------------------------------------------- + """ + # Conversion RGBtoXYZ + gamma = 2.4 + rgblimit = 0.03928 + + if (r > rgblimit): + r = ((r + 0.055)/1.055)**gamma + else : + r = r / 12.92 + + if (g > rgblimit) : + g = ((g + 0.055)/1.055)**gamma + else: + g = g / 12.92 + + if (b > rgblimit) : + b = ((b + 0.055)/1.055)**gamma + else: + b = b / 12.92 + + r *= 100 + g *= 100 + b *= 100 + + X = (0.4124 * r) + (0.3576 * g) + (0.1805 * b) + Y = (0.2126 * r) + (0.7152 * g) + (0.0722 * b) + Z = (0.0193 * r) + (0.1192 * g) + (0.9505 * b) + + # Conversion XYZtoLab + gamma = 1/3 + (L, A, B) = 0, 0, 0 + + if (Y == 0) : + (L, A, B) = (0, 0, 0) + else : + #Utilisation des constantes white point (variables globale) + (Xs, Ys, Zs) = (X/Xw, Y/Yw, Z/Zw) + + + if (Xs > 0.008856) : + Xs = Xs**gamma + else : + Xs = (7.787 * Xs) + (16/116) + + if (Ys > 0.008856) : + Ys = Ys**gamma + else : + Ys = (7.787 * Ys) + (16/116) + + if (Zs > 0.008856) : + Zs = Zs**gamma + else : + Zs = (7.787 * Zs) + (16/116) + + L = (116.0 * Ys) - 16.0 + + A = 500 * (Xs - Ys) + B = 200 * (Ys - Zs) + + # conversion LabtoLCH + (C, H) = 0, 0 + + + if (A == 0) : + H = 0 + else : + H = atan2(B, A) + + if (H > 0) : + H = (H / pi) * 180 + + else : + H = 360 - ( abs(H) / pi) * 180 + + + + C = sqrt(A**2 + B**2) + + return (L, C, H) + +def lch_to_rgb (L, C, H) : + """ + #--------------------------------------------------------------------------- + # Graphics::lch_to_rgb + # Algorythme de conversion CIE L*CH -> RGB + #--------------------------------------------------------------------------- + # paramètres : + # L : (de 0 à 1) valeur de la composante luminosité + # de la couleur CIE LCH + # C : (de 0 à 1) valeur de la composante saturation + # de la couleur CIE LCH + # H : (de 0 à 1) valeur de la composante teinte + # de la couleur CIE LCH + #--------------------------------------------------------------------------- + """ + (a, b) = 0, 0 + + # Conversion LCHtoLab + a = cos( radians(H)) * C + b = sin( radians(H)) * C + + # Conversion LabtoXYZ + gamma = 3 + (X, Y, Z) = 0, 0, 0 + + Ys = (L + 16.0) / 116.0 + Xs = (a / 500) + Ys + Zs = Ys - (b / 200) + + if ((Ys**gamma) > 0.008856) : + Ys = Ys**gamma + else : + Ys = (Ys - 16 / 116) / 7.787 + + if ((Xs**gamma) > 0.008856) : + Xs = Xs**gamma + else : + Xs = (Xs - 16 / 116) / 7.787 + + if ((Zs**gamma) > 0.008856) : + Zs = Zs**gamma + else : + Zs = (Zs - 16 / 116) / 7.787 + + + X = Xw * Xs + Y = Yw * Ys + Z = Zw * Zs + + # Conversion XYZtoRGB + gamma = 1/2.4 + rgblimit = 0.00304 + (R, G, B) = (0, 0, 0) + + X /= 100 + Y /= 100 + Z /= 100 + + R = (3.2410 * X) + (-1.5374 * Y) + (-0.4986 * Z) + G = (-0.9692 * X) + (1.8760 * Y) + (0.0416 * Z) + B = (0.0556 * X) + (-0.2040 * Y) + (1.0570 * Z) + + if (R > rgblimit) : + R = (1.055 * (R**gamma)) - 0.055 + else : + R = (12.92 * R) + + if (G > rgblimit) : + G = (1.055 * (G**gamma)) - 0.055 + else : + G = (12.92 * G) + + if (B > rgblimit) : + B = (1.055 * (B**gamma)) - 0.055 + else : + B = (12.92 * B) + + if (R < 0) : + R = 0 + elif (R > 1.0) : + R = 1.0 + else : + R = _trunc(R, 5) + + if (G < 0) : + G = 0 + elif (G > 1.0) : + G = 1.0 + else : + G = _trunc(G, 5) + + if (B < 0) : + B = 0 + elif (B > 1.0) : + B = 1.0 + else : + B = _trunc(B, 5) + + return (R, G, B) + +def rgb_to_hls(r, g, b): + """ + #--------------------------------------------------------------------------- + # Graphics::rgb_to_hls + # Algorythme de conversion RGB -> HLS + #--------------------------------------------------------------------------- + # r : (de 0 à 1) valeur de la composante rouge de la couleur RGB + # g : (de 0 à 1) valeur de la composante verte de la couleur RGB + # b : (de 0 à 1) valeur de la composante bleue de la couleur RGB + #--------------------------------------------------------------------------- + """ + H, L, S = 0, 0, 0 + minv, maxv, diffv = 0, 0, 0 + maxv = max(r, g, b) + minv = min(r, g, b) + + # calcul de la luminosité + L = (maxv + minv) / 2 + + # calcul de la saturation + if (maxv == minv) : + # couleur a-chromatique (gris) r = g = b + S = 0 + H = None + return [H, L, S] + + # couleurs "Chromatiques" -------------------- + + # calcul de la saturation + if (L <= 0.5) : + S = (maxv - minv) / (maxv + minv) + + else : + S = (maxv - minv) / (2 - maxv - minv) + + # calcul de la teinte + diffv = maxv - minv + + if (r == maxv) : + # couleur entre jaune et magenta + H = (g - b) / diffv + + elif (g == maxv) : + # couleur entre cyan et jaune + H = 2 + (b - r) / diffv + + elif (b == maxv) : + # couleur entre magenta et cyan + H = 4 + (r - g) / diffv + + # Conversion en degrés + H *= 60 + + # pour éviter une valeur négative + if (H < 0) : + H += 360 + + return [H, L, S] + +def hls_to_rgb (H, L, S): + """ + #--------------------------------------------------------------------------- + # Graphics::hls_to_rgb + # Algorythme de conversion HLS -> RGB + #--------------------------------------------------------------------------- + # paramètres : + # H : (de 0 à 1) valeur de la composante teinte de la couleur HLS + # L : (de 0 à 1) valeur de la composante luminosité de la + # couleur HLS + # S : (de 0 à 1) valeur de la composante saturation + # de la couleur HLS + #--------------------------------------------------------------------------- + """ + (R, G, B) = 0, 0, 0 + (p1, p2) = 0, 0 + + + if (L <= 0.5) : + p2 = L + (L * S) + + else : + p2 = L + S - (L * S) + + p1 = 2.0 * L - p2 + + if (S == 0) : + # couleur a-chromatique (gris) + # R = G = B = L + R = L + G = L + B = L + + else : + # couleurs "Chromatiques" + R = hls_value(p1, p2, H + 120) + G = hls_value(p1, p2, H) + B = hls_value(p1, p2, H - 120) + + return [R, G, B] + +def hls_value(q1, q2, hue): + """ + #--------------------------------------------------------------------------- + # Graphics::hls_value (sous fonction interne hls_to_rgb) + #--------------------------------------------------------------------------- + """ + value = None + + hue = hue % 360 + + if (hue < 60) : + value = q1 + (q2 - q1) * hue / 60 + + elif (hue < 180) : + value = q2 + + elif (hue < 240) : + value = q1 + (q2 - q1) * (240 - hue) / 60 + + else : + value = q1 + + return value + +def hexargbcolor(r, g, b, a = None): + """ + #--------------------------------------------------------------------------- + # Graphics::hexargbcolor + # conversion d'une couleur RGB (255,255,255) au format Zinc '#ffffff' + #--------------------------------------------------------------------------- + """ + hexacolor = "#%02x%02x%02x"% (r, g, b) + if ( a is not None ): + hexacolor = "%s;%d"% (hexacolor, a) + return hexacolor + + + +def hexa2rgb(hexastr): + """ + #--------------------------------------------------------------------------- + # Graphics::hexa2rgb + # conversion d'une couleur au format Zinc '#ffffff' en RGB (255,255,255) + #--------------------------------------------------------------------------- + """ + r, g, b = 0, 0, 0 + regex = re.compile("^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$") + res = regex.match(hexastr) + if res is not None : + r = int(res.group(1), 16) + g = int(res.group(2), 16) + b = int(res.group(3), 16) + return (r/255, g/255, b/255) + else : + raise ValueError("Not a hexa color") + +def get_pattern (filename, **options): + """ + #--------------------------------------------------------------------------- + # RESOURCES GRAPHIQUES PATTERNS, TEXTURES, IMAGES, GRADIENTS, COULEURS... + #--------------------------------------------------------------------------- + #--------------------------------------------------------------------------- + # Graphics::get_pattern + # retourne la ressource bitmap en l'initialisant si première utilisation + #--------------------------------------------------------------------------- + # paramètres : + # filename : nom du fichier bitmap pattern + # options + # -storage : référence de la table de stockage de patterns + #--------------------------------------------------------------------------- + """ + if (options.has_key('storage')): + table = options['storage'] + else : + table = bitmaps + if (not table.has_key(filename)) : + bitmap = "@%s"% (find_inc(filename)) + table[filename] = bitmap + return table[filename] + +def get_texture(widget, filename, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::get_texture + # retourne l'image de texture en l'initialisant si première utilisation + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget zinc + # filename : nom du fichier texture + # options + # -storage : référence de la table de stockage de textures + #--------------------------------------------------------------------------- + """ + if (options.has_key('storage')): + table = options['storage'] + else : + table = textures + return get_image(widget, filename, storage = table) + +class FileNotFound (Exception): + """ + #--------------------------------------------------------------------------- + # Graphics::FileNotFound + # Classe d'exception levée lorsqu'un fichier n'est pas trouvé + # paramètres : + # filename : nom du fichier + #--------------------------------------------------------------------------- + """ + def __init__(self, filename): + Exception.__init__(self, "File %s not Found"%(filename)) + +def find_inc(name): + """ + #--------------------------------------------------------------------------- + # Graphics::find_inc + # recherche le fichier dans les répertoires de PYTHONPATH + #--------------------------------------------------------------------------- + """ + import sys + import os.path + for path in sys.path: + tfile = os.path.join(path, name) + if (os.path.isfile(tfile)): + return tfile + raise FileNotFound(name) + + +def get_image(zinc, filename, storage = {}): + """ + #--------------------------------------------------------------------------- + # Graphics::get_image + # retourne la ressource image en l'initialisant si première utilisation + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget zinc + # filename : nom du fichier image + # options + # storage : référence de la table de stockage d'images + #--------------------------------------------------------------------------- + """ + if (not storage.has_key(filename)): + im = PIL.Image.open(find_inc(filename)) + #Cela marche uniquement si Tkinter.Tk a une instance + image = PIL.ImageTk.PhotoImage(im) + storage[filename] = image + return storage[filename] + +def init_pixmaps(widget, *pixfiles, **options): + """ + #--------------------------------------------------------------------------- + # Graphics::init_pixmaps + # initialise une liste de fichier image + #--------------------------------------------------------------------------- + # paramètres : + # widget : identifiant du widget zinc + # filenames : list des noms des fichier image + # options + # storage : référence de la table de stockage d'images + #--------------------------------------------------------------------------- + """ + imgs = [] + for pixfile in pixfiles: + imgs.append(get_image(widget, pixfile, **options)) + return imgs + +def _trunc(f, n): + """ + #--------------------------------------------------------------------------- + # Graphics::_trunc + # fonction interne de troncature des nombres: n = position décimale + #--------------------------------------------------------------------------- + """ + import fpformat + return fpformat.fix(f, n) + +#Local Variables: +#mode : python +#tab-width: 4 +#end: -- cgit v1.1