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

Source Code for Module teamwork.widgets.PsychGUI.AgentWindow.GoalPane

  1  import string 
  2  from Tkinter import * 
  3  import tkMessageBox 
  4  import Pmw 
  5  from teamwork.math.Keys import StateKey,ActionKey 
  6  from teamwork.widgets.pmfScale import PMFScale 
  7  from teamwork.widgets.multiscale import MultiScale 
  8  from teamwork.widgets.images import loadImages 
  9  from teamwork.reward.goal import PWLGoal,maxGoal,minGoal 
 10  from teamwork.reward.MinMaxGoal import MinMaxGoal 
 11  from teamwork.agent.Generic import GenericModel 
 12  from teamwork.widgets.TreeBuilder import TreeBuilder 
 13   
14 -class GoalFrame(Pmw.ScrolledFrame):
15 lockLabels = ['Lock','Unlock'] 16 defaultLock = 1 17 resolution = 0.01 18
19 - def __init__(self,parent,entity,balloon,**kw):
20 # Set up images if available 21 self.images = loadImages({'del': 'icons/trophy--minus.png', 22 'new': 'icons/trophy--plus.png',}) 23 optiondefs = ( 24 ('balloon',None,Pmw.INITOPT), 25 ('society',None,None), 26 ('expert',0,self.setExpert), 27 ('generic',False,None), 28 ) 29 self.defineoptions(kw, optiondefs) 30 self.normalizing = {} 31 self.entity = entity 32 self.features = {} 33 fr = Pmw.ScrolledFrame.__init__(self,parent) 34 self.interior().grid_columnconfigure(0,weight=1) 35 # Toolbar 36 toolbar = self.createcomponent('toolbar',(),None,Frame,(self.interior(),), 37 bd=2,relief='raised') 38 toolbar.grid(row=0,column=0,sticky='ew') 39 if self['generic']: 40 # Button for adding new goal 41 button = Label(toolbar) 42 button.bind('<ButtonRelease-1>',self.promptNew) 43 if self.images.has_key('new'): 44 button.configure(image=self.images['new'],bd=0) 45 else: 46 button.configure(text='New goal') 47 button.pack(side='left',ipadx=5,ipady=3) 48 if self['balloon']: 49 self['balloon'].bind(button,'Add new goal') 50 # Sliders for goal weights 51 widget = self.createcomponent('scale',(),None,PMFScale,(self.interior(),), 52 distribution=entity.goals, 53 expand=self.expand,collapse=self.collapse, 54 viewprobs=True,floatdomain=False) 55 widget.grid(row=1,column=0,sticky='news') 56 self.initialiseoptions()
57
58 - def promptNew(self,event=None):
59 try: 60 dialog = self.component('dialog') 61 except KeyError: 62 dialog = self.createDialog() 63 # Set up the possible entity references for the new goal 64 options = self['society'].keys() 65 options.sort() 66 options.append('self') 67 if isinstance(self.entity,GenericModel): 68 options += self.entity.getRelationships() 69 else: 70 options += self.entity.relationships.keys() 71 if len(options) == 0: 72 raise UserWarning,self.entity.ancestry() 73 dialog.component('entity_listbox').delete(0,END) 74 for option in options: 75 dialog.component('entity_listbox').insert(END,option) 76 dialog.component('feature').configure(menubutton_state='normal') 77 dialog.activate()
78
79 - def setState(self,state='normal'):
80 for name in self.components(): 81 if 'Goal' in name: 82 self.component(name).configure(state=state)
83
84 - def invert(self):
85 widget = self.component('scale') 86 label = widget.deleteScale() 87 for goal in self.entity.getGoals(): 88 if str(goal) == label: 89 break 90 else: 91 raise KeyError,'Agent %s has no goal %s' % \ 92 (self.entity.ancestry(),label) 93 weight = self.entity.goals[goal] 94 del self.entity.goals[goal] 95 if goal.direction == 'min': 96 direction = 'max' 97 else: 98 direction = 'min' 99 goal = goal.__class__(goal.entity,direction,goal.type, 100 goal.key,goal.value) 101 goal.weight = weight 102 self.entity.setGoalWeight(goal,weight,False) 103 self.recreate_goals() 104 widget.reorder() 105 widget.component('select%s' % (goal.key)).invoke()
106
107 - def lock(self):
108 buttonName = self.lockLabels[self.defaultLock] 109 button = self.component('scale_box').component(buttonName) 110 if not self.locked: 111 # We're locking up, so normalize first 112 self.entity.normalizeGoals() 113 self.recreate_goals() 114 self.locked = not self.locked 115 button.configure(text=self.lockLabels[self.locked])
116
117 - def recreate_goals(self):
118 """Redraws all of the goal widgets""" 119 widget = self.component('scale') 120 disabled = widget.cget('state') == 'disabled' 121 widget.configure(state='normal') 122 widget.setDistribution() 123 if disabled: 124 widget.configure(state='disabled')
125
126 - def setExpert(self):
127 """Updates the display in response to the current expert mode""" 128 pass
129
130 - def selectEntity(self,name=None):
131 if not name: 132 name = self.component('dialog_entity').get() 133 if not name: 134 return 135 self.features = {} 136 if name == 'self': 137 eList = [self.entity.name] 138 else: 139 if isinstance(self.entity,GenericModel): 140 remaining = self.entity.ancestors() 141 else: 142 remaining = [self.entity.name] 143 for agent in remaining: 144 try: 145 eList = self['society'][agent].relationships[name][:] 146 break 147 except KeyError: 148 pass 149 else: 150 eList = [name] 151 if isinstance(self.entity,GenericModel): 152 while len(eList) > 0: 153 entity = self['society'][eList.pop()] 154 for feature in entity.getStateFeatures(): 155 if not self.features.has_key(feature): 156 self.features[feature] = {'type':'state', 157 'key':feature} 158 for option in entity.actions.getOptions(): 159 for action in option: 160 if not self.features.has_key(action['type']): 161 entry = {'type':'actActor', 162 'key':action['type']} 163 self.features[action['type']] = entry 164 eList += entity.parentModels 165 elif self['society']: 166 for feature in self['society'][name].getStateFeatures(): 167 self.features[feature] = {'type':'state','key':feature} 168 features = self.features.keys() 169 features.sort() 170 self.component('dialog_feature').setitems(features) 171 if len(features) > 0: 172 self.component('dialog_feature').invoke(features[0])
173
174 - def add(self,button='OK'):
175 self.component('dialog').deactivate() 176 if button == 'OK': 177 direction = self.component('dialog_direction').getvalue().lower() 178 entity = self.component('dialog_entity').get() 179 feature = self.features[self.component('dialog_feature').getvalue()] 180 if len(feature) == 0: 181 tkMessageBox.showerror('No Feature','The selected entity has no state features to min/maximize.') 182 return 183 if feature['type'] == 'state': 184 key = StateKey({'entity': entity, 'feature': feature['key']}) 185 elif feature['type'] == 'actActor': 186 key = ActionKey({'entity': entity, 'type': feature['key'], 187 'object': None}) 188 else: 189 raise NotImplementedError,'Unable to put goals on %s' % \ 190 (feature['type']) 191 if direction == 'complex': 192 goal = PWLGoal() 193 goal.keys.append(key) 194 elif direction == 'minimize': 195 goal = minGoal(key) 196 else: # direction == 'maximize': 197 goal = maxGoal(key) 198 for other in self.entity.getGoals(): 199 if goal.keys == other.keys: 200 msg = '%s already has a goal for %s' % \ 201 (self.entity.ancestry(),','.join(map(str,(goal.keys)))) 202 tkMessageBox.showerror('Goal exists',msg) 203 break 204 else: 205 if len(self.entity.getGoals()) == 0: 206 self.entity.setGoalWeight(goal,1.,False) 207 else: 208 self.entity.setGoalWeight(goal,0.,False) 209 self.component('scale').setDistribution()
210
211 - def createDialog(self):
212 # Draw the goal adding box 213 palette = Pmw.Color.getdefaultpalette(self.interior()) 214 dialog = self.createcomponent('dialog',(),None,Pmw.Dialog, 215 (self.interior(),), 216 buttons=('OK','Cancel'), 217 command=self.add,defaultbutton=0) 218 dialog.withdraw() 219 options = ['Maximize','Minimize','Complex'] 220 widget = dialog.createcomponent('direction',(),'New Goal', 221 Pmw.OptionMenu,(dialog.interior(),), 222 items=options, 223 menubutton_width=max(map(len,options)), 224 labelpos='nw',label_text='Direction:') 225 widget.pack(side='left',pady=10,padx=10) 226 widget = dialog.createcomponent('entity',(),'New Goal', 227 Pmw.ComboBox,(dialog.interior(),), 228 labelpos='nw',label_text='Entity:', 229 entry_state='disabled', 230 entry_disabledforeground=palette['foreground'], 231 entry_disabledbackground=palette['background'], 232 selectioncommand=self.selectEntity, 233 ) 234 widget.pack(side='left',fill='x',expand='yes') 235 widget = dialog.createcomponent('feature',(),'New Goal', 236 Pmw.OptionMenu, 237 (dialog.interior(),), 238 labelpos='nw', 239 label_text='Feature:') 240 widget.pack(side='left',fill='x',expand='yes') 241 return dialog
242
243 - def expand(self,goal,frame):
244 table = {} 245 for condition,tree in goal.dependency: 246 table[str(condition)] = {'actions': condition, 'tree': tree} 247 tree = self.createcomponent(str(goal),(),'Editor',TreeBuilder, 248 (frame,),society=self['society'], 249 orient='horizontal',expert=True, 250 key=goal.toKey(),font=('Helvetica',10), 251 treeWidth=250,new=self.newDependency, 252 table=table) 253 tree.pack(side='left',fill='both',expand='yes')
254
255 - def collapse(self,goal):
256 self.destroycomponent(str(goal))
257
258 - def newDependency(self,key,condition,tree):
259 """Callback when a new action dependency is created 260 """ 261 for goal in self.entity.getGoals(): 262 if goal.keys == [key]: 263 break 264 else: 265 raise NameError,'Unable to find goal on %s' % (str(key)) 266 goal.addDependency(condition,tree)
267