changeset 7:1b0266dd233a

picking and dragging works pretty well (no ctrl yet)
author drewp
date Sun, 07 Jul 2002 04:52:48 +0000
parents 119369e60da1
children 6faae180d1c5
files light8/stage.py
diffstat 1 files changed, 79 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/light8/stage.py	Sun Jul 07 03:47:18 2002 +0000
+++ b/light8/stage.py	Sun Jul 07 04:52:48 2002 +0000
@@ -30,19 +30,8 @@
 
     """
     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("<ButtonPress-1>", self.leftpress)
         self.bind("<B1-Motion>", self.leftmotion)
         self.bind("<ButtonRelease-1>", self.leftrelease)
@@ -53,46 +42,50 @@
 
         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 @@
 
         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 @@
                 # 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 @@
         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 @@
 
             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 @@
             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()