diff --git a/bin/tracker b/bin/tracker --- a/bin/tracker +++ b/bin/tracker @@ -1,272 +1,311 @@ #!/usr/bin/python -from __future__ import division,nested_scopes +from __future__ import division, nested_scopes import sys sys.path.append("../../editor/pour") sys.path.append("../light8") from Submaster import Submaster -from skim.zooming import Zooming,Pair -from math import sqrt,sin,cos +from skim.zooming import Zooming, Pair +from math import sqrt, sin, cos from pygame.rect import Rect -from xmlnodebase import xmlnodeclass,collectiveelement,xmldocfile +from xmlnodebase import xmlnodeclass, collectiveelement, xmldocfile from dispatch import dispatcher import dmxclient import Tkinter as tk -defaultfont="arial 8" +defaultfont = "arial 8" -def pairdist(pair1,pair2): + +def pairdist(pair1, pair2): return pair1.dist(pair2) -def canvashighlighter(canvas,obj,attribute,normalval,highlightval): + +def canvashighlighter(canvas, obj, attribute, normalval, highlightval): """creates bindings on a canvas obj that make attribute go from normal to highlight when the mouse is over the obj""" - canvas.tag_bind(obj,"", - lambda ev: canvas.itemconfig(obj,**{attribute:highlightval})) - canvas.tag_bind(obj,"", - lambda ev: canvas.itemconfig(obj,**{attribute:normalval})) + canvas.tag_bind( + obj, "", lambda ev: canvas.itemconfig( + obj, **{attribute: highlightval})) + canvas.tag_bind( + obj, + "", lambda ev: canvas.itemconfig(obj, **{attribute: normalval})) + class Field(xmlnodeclass): - """one light has a field of influence. for any point on the canvas, you can ask this field how strong it is. """ - def name(self,newval=None): + def name(self, newval=None): """light/sub name""" - return self._getorsetattr("name",newval) - def center(self,x=None,y=None): + return self._getorsetattr("name", newval) + + def center(self, x=None, y=None): """x,y float coords for the center of this light in the field. returns a Pair, although it accepts x,y""" - return Pair(self._getorsettypedattr("x",float,x), - self._getorsettypedattr("y",float,y)) + return Pair(self._getorsettypedattr("x", float, x), + self._getorsettypedattr("y", float, y)) - def falloff(self,dist=None): - + def falloff(self, dist=None): """linear falloff from 1 at center, to 0 at dist pixels away from center""" - return self._getorsettypedattr("falloff",float,dist) + return self._getorsettypedattr("falloff", float, dist) - def getdistforintensity(self,intens): + def getdistforintensity(self, intens): """returns the distance you'd have to be for the given intensity (0..1)""" - return (1-intens)*self.falloff() + return (1 - intens) * self.falloff() - def calc(self,x,y): + def calc(self, x, y): """returns field strength at point x,y""" - dist=pairdist(Pair(x,y),self.center()) - return max(0,(self.falloff()-dist)/self.falloff()) + dist = pairdist(Pair(x, y), self.center()) + return max(0, (self.falloff() - dist) / self.falloff()) + class Fieldset(collectiveelement): """group of fields. persistent.""" - def childtype(self): return Field + + def childtype(self): + return Field def version(self): """read-only version attribute on fieldset tag""" - return self._getorsetattr("version",None) + return self._getorsetattr("version", None) - def report(self,x,y): + def report(self, x, y): """reports active fields and their intensities""" - active=0 + active = 0 for f in self.getall(): - name=f.name() - intens=f.calc(x,y) - if intens>0: - print name,intens, - active+=1 - if active>0: + name = f.name() + intens = f.calc(x, y) + if intens > 0: + print name, intens, + active += 1 + if active > 0: print - self.dmxsend(x,y) - def dmxsend(self,x,y): + self.dmxsend(x, y) + + def dmxsend(self, x, y): """output lights to dmx""" - levels=dict([(f.name(),f.calc(x,y)) for f in self.getall()]) - dmxlist=Submaster(None,levels).get_dmx_list() + levels = dict([(f.name(), f.calc(x, y)) for f in self.getall()]) + dmxlist = Submaster(None, levels).get_dmx_list() dmxclient.outputlevels(dmxlist) - - + def getbounds(self): """returns xmin,xmax,ymin,ymax for the non-zero areas of this field""" - r=None + r = None for f in self.getall(): - rad=f.getdistforintensity(0) - fx,fy=f.center() - fieldrect=Rect(fx-rad,fy-rad,rad*2,rad*2) + rad = f.getdistforintensity(0) + fx, fy = f.center() + fieldrect = Rect(fx - rad, fy - rad, rad * 2, rad * 2) if r is None: - r=fieldrect + r = fieldrect else: - r=r.union(fieldrect) - return r.left,r.right,r.top,r.bottom + r = r.union(fieldrect) + return r.left, r.right, r.top, r.bottom + class Fieldsetfile(xmldocfile): - def __init__(self,filename): - self._openornew(filename,topleveltype=Fieldset) + + def __init__(self, filename): + self._openornew(filename, topleveltype=Fieldset) + def fieldset(self): return self._gettoplevel() + ######################################################################## ######################################################################## + class FieldDisplay: """the view for a Field.""" - def __init__(self,canvas,field): - self.canvas=canvas - self.field=field - self.tags=[str(id(self))] # canvas tag to id our objects - + + def __init__(self, canvas, field): + self.canvas = canvas + self.field = field + self.tags = [str(id(self))] # canvas tag to id our objects + def setcoords(self): """adjust canvas obj coords to match the field""" # this uses the canvas object ids saved by makeobjs - f=self.field - c=self.canvas - w2c=self.canvas.world2canvas + f = self.field + c = self.canvas + w2c = self.canvas.world2canvas # rings - for intens,ring in self.rings.items(): - rad=f.getdistforintensity(intens) - p1=w2c(*(f.center()-Pair(rad,rad))) - p2=w2c(*(f.center()+Pair(rad,rad))) - c.coords(ring,p1[0],p1[1],p2[0],p2[1]) + for intens, ring in self.rings.items(): + rad = f.getdistforintensity(intens) + p1 = w2c(*(f.center() - Pair(rad, rad))) + p2 = w2c(*(f.center() + Pair(rad, rad))) + c.coords(ring, p1[0], p1[1], p2[0], p2[1]) # text - p1=w2c(*f.center()) - c.coords(self.txt,*p1) + p1 = w2c(*f.center()) + c.coords(self.txt, *p1) def makeobjs(self): """(re)create the canvas objs (null coords) and make their bindings""" - c=self.canvas - f=self.field + c = self.canvas + f = self.field c.delete(self.tags) - w2c=self.canvas.world2canvas + w2c = self.canvas.world2canvas # make rings - self.rings={} # rad,canvasobj - for intens,color in (#(1,'white'), - (.8,'gray90'),(.6,'gray80'),(.4,'gray60'),(.2,'gray50'), - (0,'#000080')): - self.rings[intens]=c.create_oval(0,0,0,0, - outline=color,width=2,tags=self.tags, - outlinestipple='gray50') + self.rings = {} # rad,canvasobj + for intens, color in ( #(1,'white'), + (.8, 'gray90'), (.6, 'gray80'), (.4, 'gray60'), (.2, 'gray50'), + (0, '#000080')): + self.rings[intens] = c.create_oval(0, + 0, + 0, + 0, + outline=color, + width=2, + tags=self.tags, + outlinestipple='gray50') # make text - self.txt=c.create_text(0,0,text=f.name(),font=defaultfont+" bold", - fill='white',anchor='c', - tags=self.tags) + self.txt = c.create_text(0, + 0, + text=f.name(), + font=defaultfont + " bold", + fill='white', + anchor='c', + tags=self.tags) # highlight text bindings - canvashighlighter(c,self.txt,'fill',normalval='white',highlightval='red') + canvashighlighter(c, + self.txt, + 'fill', + normalval='white', + highlightval='red') # position drag bindings def press(ev): - self._lastmouse=ev.x,ev.y + self._lastmouse = ev.x, ev.y + def motion(ev): - dcan=Pair(*[a-b for a,b in zip((ev.x,ev.y),self._lastmouse)]) - dworld=c.canvas2world_vector(*dcan) - self.field.center(*(self.field.center()+dworld)) - self._lastmouse=ev.x,ev.y - self.setcoords() # redraw + dcan = Pair(*[a - b for a, b in zip((ev.x, ev.y), self._lastmouse)]) + dworld = c.canvas2world_vector(*dcan) + self.field.center(*(self.field.center() + dworld)) + self._lastmouse = ev.x, ev.y + self.setcoords() # redraw + def release(ev): - if hasattr(self,'_lastmouse'): + if hasattr(self, '_lastmouse'): del self._lastmouse - dispatcher.send("field coord changed") # updates bounds - - c.tag_bind(self.txt,"",press) - c.tag_bind(self.txt,"",motion) - c.tag_bind(self.txt,"",release) + dispatcher.send("field coord changed") # updates bounds + + c.tag_bind(self.txt, "", press) + c.tag_bind(self.txt, "", motion) + c.tag_bind(self.txt, "", release) # radius drag bindings - outerring=self.rings[0] - canvashighlighter(c,outerring, - 'outline',normalval='#000080',highlightval='#4040ff') + outerring = self.rings[0] + canvashighlighter(c, + outerring, + 'outline', + normalval='#000080', + highlightval='#4040ff') + def motion(ev): - worldmouse=self.canvas.canvas2world(ev.x,ev.y) - currentdist=pairdist(worldmouse,self.field.center()) + worldmouse = self.canvas.canvas2world(ev.x, ev.y) + currentdist = pairdist(worldmouse, self.field.center()) self.field.falloff(currentdist) self.setcoords() - c.tag_bind(outerring,"",motion) - c.tag_bind(outerring,"",release) # from above + + c.tag_bind(outerring, "", motion) + c.tag_bind(outerring, "", release) # from above self.setcoords() - + + class Tracker(tk.Frame): - """whole tracker widget, which is mostly a view for a Fieldset. tracker makes its own fieldset""" # world coords of the visible canvas (preserved even in window resizes) - xmin=0 - xmax=100 - ymin=0 - ymax=100 + xmin = 0 + xmax = 100 + ymin = 0 + ymax = 100 + + fieldsetfile = None + displays = None # Field : FieldDisplay. we keep these in sync with the fieldset - fieldsetfile=None - displays=None # Field : FieldDisplay. we keep these in sync with the fieldset - - def __init__(self,master): - tk.Frame.__init__(self,master) + def __init__(self, master): + tk.Frame.__init__(self, master) - self.displays={} - - c=self.canvas=Zooming(self,bg='black',closeenough=5) - c.pack(fill='both',exp=1) + self.displays = {} + + c = self.canvas = Zooming(self, bg='black', closeenough=5) + c.pack(fill='both', exp=1) # preserve edge coords over window resize - c.bind("",self.configcoords) - - c.bind("", - lambda ev: self._fieldset().report(*c.canvas2world(ev.x,ev.y))) + c.bind("", self.configcoords) + + c.bind("", lambda ev: self._fieldset().report(*c.canvas2world( + ev.x, ev.y))) + def save(ev): print "saving" self.fieldsetfile.save() - master.bind("",save) - dispatcher.connect(self.autobounds,"field coord changed") + + master.bind("", save) + dispatcher.connect(self.autobounds, "field coord changed") def _fieldset(self): return self.fieldsetfile.fieldset() - def load(self,filename): - self.fieldsetfile=Fieldsetfile(filename) + def load(self, filename): + self.fieldsetfile = Fieldsetfile(filename) self.displays.clear() for f in self.fieldsetfile.fieldset().getall(): - self.displays[f]=FieldDisplay(self.canvas,f) + self.displays[f] = FieldDisplay(self.canvas, f) self.displays[f].makeobjs() self.autobounds() - def configcoords(self,*args): + def configcoords(self, *args): # force our canvas coords to stay at the edges of the window - c=self.canvas - cornerx,cornery=c.canvas2world(0,0) - c.move(cornerx-self.xmin, - cornery-self.ymin) - c.setscale(0,0, - c.winfo_width()/(self.xmax-self.xmin), - c.winfo_height()/(self.ymax-self.ymin)) + c = self.canvas + cornerx, cornery = c.canvas2world(0, 0) + c.move(cornerx - self.xmin, cornery - self.ymin) + c.setscale(0, 0, + c.winfo_width() / (self.xmax - self.xmin), + c.winfo_height() / (self.ymax - self.ymin)) def autobounds(self): """figure out our bounds from the fieldset, and adjust the display zooms. writes the corner coords onto the canvas.""" - self.xmin,self.xmax,self.ymin,self.ymax=self._fieldset().getbounds() + self.xmin, self.xmax, self.ymin, self.ymax = self._fieldset().getbounds( + ) self.configcoords() - - c=self.canvas + + c = self.canvas c.delete('cornercoords') - for x,anc2 in ((self.xmin,'w'),(self.xmax,'e')): - for y,anc1 in ((self.ymin,'n'),(self.ymax,'s')): - pos=c.world2canvas(x,y) - c.create_text(pos[0],pos[1],text="%s,%s"%(x,y), - fill='white',anchor=anc1+anc2, + for x, anc2 in ((self.xmin, 'w'), (self.xmax, 'e')): + for y, anc1 in ((self.ymin, 'n'), (self.ymax, 's')): + pos = c.world2canvas(x, y) + c.create_text(pos[0], + pos[1], + text="%s,%s" % (x, y), + fill='white', + anchor=anc1 + anc2, tags='cornercoords') [d.setcoords() for d in self.displays.values()] + ######################################################################## ######################################################################## - -root=tk.Tk() + +root = tk.Tk() root.wm_geometry('700x350') -tra=Tracker(root) -tra.pack(fill='both',exp=1) +tra = Tracker(root) +tra.pack(fill='both', exp=1) tra.load("fieldsets/demo")