# HG changeset patch # User drewp # Date 2002-07-07 04:52:48 # Node ID 1b0266dd233a6fdf27802aa5d84ad2a05fc5b32f # Parent 119369e60da1d77b7f8feb951f2a09fc811fb99f picking and dragging works pretty well (no ctrl yet) diff --git a/light8/stage.py b/light8/stage.py --- a/light8/stage.py +++ b/light8/stage.py @@ -30,19 +30,8 @@ class Stage(Canvas): """ def __init__(self,parent,**kw): - if 'stageimage' in kw: - stageimage=kw['stageimage'] - del kw['stageimage'] - else: - stageimage=None - Canvas.__init__(self,parent,**kw) - if stageimage: - img = Image('photo',stageimage) - self.create_image(0,0,anchor='nw',image=img) - self.create_rectangle(5,5,50,50) - self.bind("", self.leftpress) self.bind("", self.leftmotion) self.bind("", self.leftrelease) @@ -53,46 +42,50 @@ class Stage(Canvas): self.alllights=[] self.selectedlights=[] + self.alllighttags={} # tag: name lookup + + def setimage(self,stageimage): + img = Image('photo',file=stageimage) + self.img=img # can't lose this! + print img.width() + self.create_image(0,0,anchor='nw',image=img) + self.config(width=img.width(),height=img.height()) + # # selection management # + def updateselectionboxes(self): + "make selection boxes that match self.selectedlights" + self.delete("selectbox") + for l in self.selectedlights: + for c in self.getlightbboxes(l): + self.create_rectangle(c[0]-2,c[1]-2,c[2]+2,c[3]+2,outline='red',tag="selectbox") + def clearselection(self,dyn=0): - if dyn: - seltag="dynselection" - else: - seltag="selection" - for o in self.find_withtag(seltag): - self.select(o,0,dyn) + self.selectedlights=[] + self.updateselectionboxes() + + def markfordynselection(self): + """call this before calls to replacedynselection""" + self.origselection = self.selectedlights def replacedynselection(self,newlightnames): - for o in self.find_withtag('dynselection'): - self.select(o,0,1) - for o in newlightnames: - self.select(o,1,1) + """as a dynamic selection changes, keep calling this function with the + names of the lights in the dynamic selection. the original selection (at the time + of markfordynselection) will be shown along with any new lights""" + self.selectedlights = self.origselection + [l for l in newlightnames if l not in self.origselection] + self.updateselectionboxes() - def select(self,obj,select=1,dyn=0): # select=0 for deselect - if dyn: - seltag="dynselection" - else: - seltag="selection" + def select(self,lightname,select=1,dyn=0): # select=0 for deselect if select: - print obj,"into selection" - self.addtag_withtag(seltag,obj) - for c in self.getlightbboxes(obj): - self.create_rectangle(c[0]-2,c[1]-2,c[2]+2,c[3]+2,outline='red',tag="selectbox_%s"%obj) - else: - print obj,"out of select" - self.dtag(obj,seltag) - if 'selection' not in self.gettags(obj) and 'dynselection' not in self.gettags(obj): - self.delete("selectbox_%s"%obj) + if lightname not in self.selectedlights: + self.selectedlights.append(lightname) + elif lightname in self.selectedlights: + self.selectedlights.remove(lightname) + + self.updateselectionboxes() - def incorporatedynselection(self): - "put all dynselected objects in the regular selection" - for o in self.find_withtag('dynselection'): - self.dtag(o,'dynselection') - self.addtag_withtag('selection',o) - # no change for the graphics # # LMB click or drag @@ -109,18 +102,17 @@ class Stage(Canvas): if not istouching: # clicked in space - if not shifted and not control: + if not shifted and not control and len(self.selectedlights)>0: # either a deselect (if no motion) or a level change (if motion) - self.clearselection() - self.lmbstate='rectangle' - if shifted or control: + self.lmbstate = 'deselect-or-level' + if shifted or control or len(self.selectedlights)==0: # with shift/control, add/subtract lights to selection self.lmbstate='rectangle' else: # clicked a selectable object # toggle selection - if 'selection' in self.gettags(touching[0]): + if touching[0] in self.selectedlights: if shifted: # deselect self.select(touching[0],0) @@ -140,7 +132,8 @@ class Stage(Canvas): # and adjust levels now self.lmbstate='levelchange' - + if self.lmbstate=='rectangle': + self.markfordynselection() def leftmotion(self,ev): coords=(ev.x,ev.y) @@ -148,6 +141,11 @@ class Stage(Canvas): shifted=ev.state & 1 control=ev.state & 4 + if self.lmbstate=='deselect-or-level': + if (coords[0]-self.lmbstart[0])**2+(coords[1]-self.lmbstart[1])**2>self.halo**2: + # they moved enough, it's a level change + self.lmbstate='levelchange' + if self.lmbstate=='levelchange': delta = self.lmbstart[1]-ev.y print "change by",delta @@ -170,31 +168,51 @@ class Stage(Canvas): if self.lmbstate=='rectangle': self.delete('selectrect') + + if self.lmbstate=='deselect-or-level': + # they didn't move enough to promote the mode to level, so it's a deselect click + self.clearselection() # all items that were in dynselection join the selection - self.incorporatedynselection() +# self.incorporatedynselection() self.lmbstate=None + # + # light names vs. canvas object tags + # def nametag(self,name): "returns a safe version of the name that won't match other names" return name.replace(" ","__") + def tagtoname(self,tag): + "finds the real light name for a tag written by nametag()" + return self.alllighttags[tag] + + # + # light methods + # def addlight(self,name,location,aim=None): - tags='light selectable name_%s' % self.nametag(name) self.create_oval(location[0]-2,location[1]-2, location[0]+2,location[1]+2, fill='red',tag=tags+" hotspot") + if aim: + self.create_oval(aim[0]-2,aim[1]-2, + aim[0]+2,aim[1]+2, + fill='red',tag=tags+" hotspot") + self.create_line(location[0],location[1],aim[0],aim[1],stipple='gray50', + arrow='last',arrowshape="9 15 6",tag='light') self.create_text(location[0],location[1]+5,anchor='n',text=name,tag=tags) self.alllights.append(name) + self.alllighttags[self.nametag(name)]=name def getlightbboxes(self,tag): """returns a list of bboxes for a light with a given name_ tag. the selection mechanism draws around these bboxes to show that a light is selected""" bboxes=[] - for o in self.find_withtag(tag): + for o in self.find_withtag("name_%s" % self.nametag(tag)): if 'hotspot' in self.gettags(o): bboxes.append(self.bbox(o)) return bboxes @@ -206,17 +224,22 @@ class Stage(Canvas): candidates = self.find_enclosed(*box) else: candidates = self.find_overlapping(*box) + for o in candidates: for t in self.gettags(o): - if t.startswith("name_") and t not in lights: - lights.append(t) + if t.startswith("name_"): + n = self.tagtoname(t[5:]) + if n and (n not in lights): + lights.append(n) return lights root=Tk() -s=Stage(root,stageimage='guysanddolls.ppm') -s.addlight('drew',(80,80)) -s.addlight('house',(150,80)) -s.addlight('barn',(200,80)) +root.wm_geometry("+376+330") +s=Stage(root) +s.setimage('guysanddolls.ppm') s.pack() +s.addlight('drew',(330,640),(90,20)) +s.addlight('house',(360,640)) +s.addlight('barn',(390,640)) root.mainloop()