Package teamwork :: Package widgets :: Package PsychGUI :: Module TurnDialog
[hide private]
[frames] | no frames]

Source Code for Module teamwork.widgets.PsychGUI.TurnDialog

  1  import threading 
  2  from Tkinter import * 
  3  import Pmw 
  4  from teamwork.widgets.images import getImage 
  5   
6 -class TurnDialog(Pmw.Dialog):
7 """A dialog for editing the ordering of a sequence"""
8 - def __init__(self,parent,**kw):
9 optiondefs = ( 10 ('serial',False,Pmw.INITOPT), 11 ) 12 self.defineoptions(kw, optiondefs) 13 Pmw.Dialog.__init__(self,parent) 14 if self['serial']: 15 self.createcomponent('editor',(),None,OldTurnEditor,(self.interior(),), 16 vertflex='expand',horizflex='expand') 17 else: 18 self.createcomponent('editor',(),None,TurnEditor,(self.interior(),), 19 vertflex='expand',horizflex='expand') 20 self.component('editor').pack(side='top',fill='both',expand='yes') 21 self.initialiseoptions()
22
23 -class TurnEditor(Pmw.ScrolledFrame):
24 - def __init__(self,parent,**kw):
25 self.lock = threading.Lock() 26 optiondefs = ( 27 ('order',[],self.setOrder), 28 ('elements',[],self.setOrder), 29 ('editable',True,self.setOrder), 30 ) 31 self.defineoptions(kw, optiondefs) 32 self.variables = {} 33 Pmw.ScrolledFrame.__init__(self,parent) 34 self.interior().grid_columnconfigure(1,weight=1) 35 self.createcomponent('serial',(),None,Pmw.OptionMenu,(self.interior(),), 36 items=('serial','parallel','mixed'), 37 command=self.serialize).grid(row=0,column=0, 38 sticky='w') 39 Button(self.interior(),text='Preview',command=self.setOrder, 40 justify='center').grid(row=0,column=1,sticky='w')
41
42 - def setOrder(self):
43 """Redraws the control elements based on the new order""" 44 for name in self.components(): 45 if self.componentgroup(name) == 'active': 46 if not name[:-7] in self['elements']: 47 self.destroycomponent(name) 48 elif self.componentgroup(name) == 'scale': 49 if not name[:-6] in self['elements']: 50 self.destroycomponent(name) 51 if isinstance(self['order'][0],str): 52 # Sequential order 53 self.component('serial').setvalue('serial') 54 elif len(self['order']) == 1: 55 # Parallel order 56 self.component('serial').setvalue('parallel') 57 else: 58 # Mixed 59 self.component('serial').setvalue('mixed') 60 inactive = self['elements'][:] 61 # Check whether any previously relevant agents are now gone 62 leftover = {} 63 leftover.update(self.variables) 64 # Draw new control elements 65 row = 2 66 for pos in range(len(self['order'])): 67 names = self['order'][pos] 68 if isinstance(names,str): 69 # Pretend we're being parallel, even if we're not 70 names = [names] 71 for name in names: 72 self.drawControl(name,row,pos,True) 73 row += 1 74 inactive.remove(name) 75 if leftover.has_key(name): 76 del leftover[name] 77 # Draw the unselected checkbuttons 78 for name in inactive: 79 self.drawControl(name,row,len(self['order']),False) 80 row += 1 81 if leftover.has_key(name): 82 del leftover[name] 83 # Delete unused checkbutton variables 84 for name in leftover.keys(): 85 del self.variables[name]
86
87 - def drawControl(self,name,row,pos,active):
88 """Draws the control for an individual agent's position in order 89 @param name: the name of the agent 90 @type name: str 91 @param row: the position of the agent's widget 92 @type row: int 93 @param pos: the turn of the agent in the execution order 94 @type pos: int 95 @param active: if C{True}, the agent gets a turn 96 @type active: bool 97 """ 98 try: 99 widget = self.component('%s-active' % (name)) 100 except KeyError: 101 self.variables[name] = StringVar() 102 widget = self.createcomponent('%s-active' % (name),(),'active', 103 Checkbutton,(self.interior(),), 104 text=name,variable=self.variables[name], 105 command=lambda n=name,s=self:s.toggle(n)) 106 widget.grid(row=row,column=0,sticky='w') 107 # Update checkbuttons indicating active/inactive 108 if self.lock.acquire(0): 109 if active: 110 widget.select() 111 else: 112 widget.deselect() 113 self.lock.release() 114 # Create scale widget 115 try: 116 widget = self.component('%s-scale' % (name)) 117 except KeyError: 118 widget = self.createcomponent('%s-scale' % (name),(),'scale', 119 Scale,(self.interior(),), 120 command=lambda v,n=name,s=self: 121 s.update(n,v), 122 orient='horizontal',from_=1, 123 to=len(self['elements'])) 124 # Update scale's setting 125 if self.lock.acquire(0): 126 widget.set(pos+1) 127 self.lock.release() 128 widget.grid(row=row,column=1,sticky='ew')
129
130 - def update(self,name,new):
131 """Slider callback 132 """ 133 if self.lock.acquire(0): 134 new = int(new) 135 serial = self.component('serial').getvalue() 136 active = int(self.variables[name].get()) 137 if serial == 'serial': 138 if active and new > len(self['order']): 139 # Simply add to end of order 140 self['order'].append(name) 141 if len(self['order']) != new: 142 # It's a few steps beyond the end 143 self.component('%s-scale' % (name)).set(len(self['order'])) 144 elif active and self['order'][new-1] != name: 145 # Move guy out of new spot 146 old = self['order'].index(name)+1 147 other = self['order'][new-1] 148 self['order'][old-1] = other 149 self['order'][new-1] = name 150 self.component('%s-scale' % (other)).set(old) 151 elif serial == 'mixed': 152 for names in self['order']: 153 try: 154 names.remove(name) 155 break 156 except ValueError: 157 pass 158 if int(self.variables[name].get()): 159 # Add name in new list 160 self['order'][new-1].append(name) 161 self.lock.release()
162
163 - def toggle(self,name):
164 """Activation checkbutton callback 165 """ 166 widget = self.component('%s-scale' % (name)) 167 position = int(widget.get()) 168 serial = self.component('serial').getvalue() 169 active = int(self.variables[name].get()) 170 if active: 171 # Activated previously inactive agent 172 widget.configure(state='normal') 173 self.update(name,position) 174 elif serial == 'serial': 175 # Remove agent from sequence 176 widget.set(len(self['order'])) 177 assert self['order'][position-1] == name 178 del self['order'][position-1] 179 widget.configure(state='disabled') 180 else: 181 # Remove agent from parallel grouping 182 self['order'][position-1].remove(name)
183
184 - def serialize(self,serial):
185 if serial == 'serial': 186 if isinstance(self['order'][0],list): 187 # Going from parallel to serial (order is lists of strings) 188 new = [] 189 for index in range(len(self['order'])): 190 names = self['order'][0] 191 del self['order'][0] 192 for name in names: 193 if int(self.variables[name].get()): 194 self['order'].append(name) 195 self.setOrder() 196 elif serial == 'parallel': 197 if isinstance(self['order'][0],str): 198 self['order'][0] = self['order'][:] 199 else: 200 self['order'][0] += sum(self['order'][1:],[]) 201 del self['order'][1:] 202 self.setOrder() 203 else: 204 if isinstance(self['order'],str): 205 # Going from serial to parallel (order is list of lists of strings) 206 for index in range(len(self['order'])): 207 self['order'][index] = [self['order'][index]]
208
209 -class OldTurnEditor(Pmw.ScrolledFrame):
210 - def __init__(self,parent,**kw):
211 optiondefs = ( 212 ('order',[],self.setOrder), 213 ('elements',[],self.setElements), 214 ('editable',True,self.setEditable), 215 ) 216 self.defineoptions(kw, optiondefs) 217 Pmw.ScrolledFrame.__init__(self,parent) 218 self.up = PhotoImage(file=getImage('up.gif')) 219 self.down = PhotoImage(file=getImage('down.gif')) 220 self.createcomponent('active',(),None,Pmw.Group,(self.interior(),), 221 tag_text='Active') 222 self.component('active').interior().grid_columnconfigure(1,weight=1) 223 self.createcomponent('inactive',(),None,Pmw.Group,(self.interior(),), 224 tag_text='Inactive').pack(side='top',fill='both', 225 expand='yes') 226 self.component('inactive').interior().grid_columnconfigure(1,weight=1) 227 self.initialiseoptions()
228
229 - def setOrder(self):
230 """Redraws the control elements based on the new order""" 231 # Remove any existing control elements 232 for name in self.components(): 233 if self.componentgroup(name) == 'active': 234 self.destroycomponent(name) 235 frame = self.component('active') 236 # Draw new control elements 237 for index in range(len(self['order'])): 238 self.drawControl(index,self['order'][index],True) 239 if len(self['order']) > 0: 240 frame.pack(side='top',fill='both',expand='yes', 241 before=self.component('inactive'))
242
243 - def setElements(self):
244 """Redraws the control elements for the inactive elements""" 245 # Remove any existing control elements 246 for name in self.components(): 247 if self.componentgroup(name) == 'inactive': 248 self.destroycomponent(name) 249 frame = self.component('inactive') 250 index = len(self['order']) 251 for element in self['elements']: 252 if not element in self['order']: 253 self.drawControl(index,element,False) 254 index += 1
255
256 - def drawControl(self,index,label,active):
257 """Draws a new text box with up/down arrows 258 @param index: the row in which to create this widget 259 @type index: int 260 @param label: the text label for this element 261 @type label: str 262 @param active: C{True} iff this element is currently active 263 @type active: bool 264 """ 265 if active: 266 group = 'active' 267 offset = 0 268 else: 269 group = 'inactive' 270 offset = len(self['order']) 271 w = self.createcomponent('up%d' % (index),(),group,Button, 272 (self.component(group).interior(),), 273 image=self.up, 274 command=lambda i=index:\ 275 self.moveUp(i), 276 ) 277 if index == 0 and active: 278 w.configure(state='disabled') 279 w.grid(row=index-offset,column=0) 280 w = self.createcomponent('name%d' % (index),(),group,Label, 281 (self.component(group).interior(),), 282 text=label,bd=1,relief='raised', 283 ) 284 w.grid(row=index-offset,column=1,sticky='ewns') 285 w = self.createcomponent('down%d' % (index),(),group,Button, 286 (self.component(group).interior(),), 287 image=self.down, 288 command=lambda i=index:\ 289 self.moveDown(i), 290 ) 291 if index == len(self['elements']) - 1 and not active: 292 w.configure(state='disabled') 293 w.grid(row=index-offset,column=2)
294
295 - def setEditable(self):
296 """En/disables the order modification buttons, as appropriate""" 297 if self['editable']: 298 state = 'normal' 299 else: 300 state = 'disabled' 301 for index in range(len(self['order'])): 302 if index > 0: 303 w = self.component('up%d' % (index)) 304 w.configure(state=state) 305 if index < len(self['elements'])-1: 306 w = self.component('down%d' % (index)) 307 w.configure(state=state)
308
309 - def moveUp(self,index):
310 """Moves the identified element up in the order""" 311 if index < len(self['order']): 312 old = self['order'][index-1] 313 new = self['order'][index] 314 self.component('name%d' % (index)).configure(text=old) 315 self.component('name%d' % (index-1)).configure(text=new) 316 self['order'][index] = old 317 self['order'][index-1] = new 318 elif index > len(self['order']): 319 old = self.component('name%d' % (index-1)).cget('text') 320 new = self.component('name%d' % (index)).cget('text') 321 self.component('name%d' % (index)).configure(text=old) 322 self.component('name%d' % (index-1)).configure(text=new) 323 else: 324 # Newly active 325 name = self.component('name%d' % (index)).cget('text') 326 self['order'].append(name) 327 self.setElements() 328 self.drawControl(index,name,True)
329
330 - def moveDown(self,index):
331 """Moves the identified element down in the order""" 332 if index < len(self['order']) - 1: 333 old = self['order'][index+1] 334 new = self['order'][index] 335 self.component('name%d' % (index)).configure(text=old) 336 self.component('name%d' % (index+1)).configure(text=new) 337 self['order'][index] = old 338 self['order'][index+1] = new 339 elif index >= len(self['order']): 340 old = self.component('name%d' % (index+1)).cget('text') 341 new = self.component('name%d' % (index)).cget('text') 342 self.component('name%d' % (index)).configure(text=old) 343 self.component('name%d' % (index+1)).configure(text=new) 344 else: 345 # Newly inactive 346 name = self.component('name%d' % (index)).cget('text') 347 self['order'].pop() 348 for label in ['up','name','down']: 349 self.destroycomponent('%s%d' % (label,index)) 350 self.setElements()
351
352 - def deactivate(self, result=None):
353 Pmw.Dialog.deactivate(self,result) 354 # Delete buttons (can't really re-use them) 355 for name in self.components(): 356 if self.componentgroup(name) in ['active','inactive']: 357 self.destroycomponent(name)
358