| Home | Trees | Indices | Help |
|
|---|
|
|
1 #!/usr/bin/env python
2 #
3 # The Vision Egg: EPhysGUI
4 #
5 # Copyright (C) 2001-2004 Andrew Straw.
6 # Copyright (C) 2004 Imran S. Ali, Lachlan Dowd
7 # Copyright (C) 2004, 2008 California Institute of Technology
8 #
9 # Author: Andrew Straw <astraw@users.sourceforge.net>
10 # URL: <http://www.visionegg.org/>
11 #
12 # Distributed under the terms of the GNU Lesser General Public License
13 # (LGPL). See LICENSE.TXT that came with this file.
14 #
15 # $Id: EPhysGUI.py 1455 2008-06-07 15:42:14Z astraw $
16
17 import VisionEgg
18 __version__ = VisionEgg.release_name
19 __cvs__ = '$Revision: 1455 $'.split()[1]
20 __date__ = ' '.join('$Date: 2008-06-07 08:42:14 -0700 (Sat, 07 Jun 2008) $'.split()[1:3])
21 __author__ = 'Andrew Straw <astraw@users.sourceforge.net>'
22
23 import sys, socket, re, time, string, types, os
24 import parser, symbol, token, compiler
25 import pickle, random, math, threading
26 import Tkinter, tkMessageBox, tkSimpleDialog, tkFileDialog
27 import StringIO
28 import Pyro
29 import numpy
30
31 import VisionEgg
32 import VisionEgg.PyroClient
33 import VisionEgg.PyroApps.ScreenPositionGUI
34 import VisionEgg.GUI
35 import VisionEgg.ParameterTypes as ve_types
36
37 # Add your client modules here
38 import VisionEgg.PyroApps.TargetGUI
39 import VisionEgg.PyroApps.MouseTargetGUI
40 import VisionEgg.PyroApps.FlatGratingGUI
41 import VisionEgg.PyroApps.SphereGratingGUI
42 import VisionEgg.PyroApps.SpinningDrumGUI
43 import VisionEgg.PyroApps.GridGUI
44 import VisionEgg.PyroApps.ColorCalGUI
45
46 import VisionEgg.PyroApps.DropinGUI
47 import VisionEgg.PyroApps.AST_ext as AST_ext
48 import VisionEgg.PyroApps.VarTypes as VarTypes
49
50 client_list = []
51 client_list.extend( VisionEgg.PyroApps.TargetGUI.get_control_list() )
52 client_list.extend( VisionEgg.PyroApps.MouseTargetGUI.get_control_list() )
53 client_list.extend( VisionEgg.PyroApps.FlatGratingGUI.get_control_list() )
54 client_list.extend( VisionEgg.PyroApps.SphereGratingGUI.get_control_list() )
55 client_list.extend( VisionEgg.PyroApps.SpinningDrumGUI.get_control_list() )
56 client_list.extend( VisionEgg.PyroApps.GridGUI.get_control_list() )
57 client_list.extend( VisionEgg.PyroApps.ColorCalGUI.get_control_list() )
58 client_list.extend( VisionEgg.PyroApps.DropinGUI.get_control_list() )
59
61 """Base class to encapsulate objects, provides useful methods when used in GUI"""
68 header = "unknown parameters"
69
71 - def __init__(self,master=None,list_of_contained_objects=None,contained_objectbject_maker=None,
72 container_class=ContainedObjectBase,
73 **cnf):
74 Tkinter.Frame.__init__(self, master, **cnf)
75 if list_of_contained_objects is None:
76 self.list = []
77 else:
78 self.list = list_of_contained_objects
79 self.container_class = container_class
80
81 # allow column to expand
82 self.columnconfigure(0,weight=1)
83
84 # The frame that has the list and the vscroll
85 self.frame = Tkinter.Frame(self,borderwidth=2)
86 self.frame.grid(row=0,sticky="nwes")
87
88 # allow column to expand
89 self.frame.columnconfigure(0,weight=1)
90
91 self.frame.vscroll = Tkinter.Scrollbar(self.frame,orient=Tkinter.VERTICAL)
92 self.frame.hscroll = Tkinter.Scrollbar(self.frame,orient=Tkinter.HORIZONTAL)
93 self.frame.title = Tkinter.Listbox(
94 self.frame,
95 relief=Tkinter.FLAT,
96 font=('courier',10,'bold'),
97 height=1,
98 # selectbackground='#eed5b7',
99 # selectborderwidth=0,
100 # selectmode=None,
101 exportselection=0)
102 self.frame.title.insert(Tkinter.END, self.container_class.header)
103 self.frame.list = Tkinter.Listbox(
104 self.frame,
105 relief=Tkinter.SUNKEN,
106 font=('courier',10,'normal'),
107 width=40, height=10,
108 selectbackground='#eed5b7',
109 selectborderwidth=0,
110 selectmode=Tkinter.BROWSE,
111 xscroll=self.frame.hscroll.set,
112 yscroll=self.frame.vscroll.set,
113 exportselection=0)
114
115 self.frame.hscroll['command'] = self.delegate_hscroll
116 self.frame.hscroll.grid(row=3,column=0,sticky='we')
117 self.frame.vscroll['command'] = self.frame.list.yview
118 self.frame.vscroll.grid(row=2,column=1,sticky='ns')
119 self.frame.title.grid(row=1,column=0,ipady=0,pady=0,sticky='we')
120 self.frame.list.grid(row=2,column=0,sticky='nwes')
121 self.frame.list.bind('<Double-Button-1>',self.edit_selected)
122
123 # The buttons on bottom
124 self.bar = Tkinter.Frame(self,borderwidth=2)
125 self.bar.grid(row=1,sticky="we")
126 self.bar.add = Tkinter.Button(self.bar,text='Add...',command=self.add_new)
127 self.bar.add.grid(row=0,column=0,sticky='we')
128 self.bar.edit = Tkinter.Button(self.bar,text='Edit...',command=self.edit_selected)
129 self.bar.edit.grid(row=0,column=1,sticky='we')
130 self.bar.remove = Tkinter.Button(self.bar,text='Remove',command=self.remove_selected)
131 self.bar.remove.grid(row=0,column=2,sticky='we')
132 self.bar.move_up = Tkinter.Button(self.bar,text='Up',command=self.move_selected_up)
133 self.bar.move_up.grid(row=0,column=3,sticky='we')
134 self.bar.move_down = Tkinter.Button(self.bar,text='Down',command=self.move_selected_down)
135 self.bar.move_down.grid(row=0,column=4,sticky='we')
136 self.bar.tk_menuBar(self.bar.add,self.bar.remove)
137 #Lachie- My bar for setting parent
138 self.bar.merge = Tkinter.Button(self.bar,text='Merge/Unmerge',command=self.make_merge)
139 self.bar.merge.grid(row=0,column=5,sticky='we')
140 self.bar.tk_menuBar(self.bar.add,self.bar.remove)
141 self.update_now()
142
144 # This is a function for finding the 2-d
145 # list coordinates of an element which may be inside a
146 # list-nested-list.
147 # eg. if x = [[e, e, e], [e], [e, e]]
148 # Then the coordinates of the element at index 4 is: (2, 0)
149 #
150 # Initialization:
151 i = -1
152 j = -1
153 element_count = 0
154 # Main body:
155 for nested_list in main_list:
156 j = -1
157 i = i + 1
158 for element in nested_list:
159 j = j + 1
160 element_count = element_count + 1
161 if (element_count - 1) == main_index:
162 return [i, j]
163 # Unsuccessful exit:
164 return [-1, -1]
165
169
171 results = []
172 for contained_object_item in self.list:
173 #results.append( contained_object_item.get_contained() )
174 results.append( contained_object_item )
175 return results
176
178 self.frame.list.delete(0,Tkinter.END)
179 max_len = 0
180 for loop_container in self.list:
181 for loop in loop_container:
182 item_str_30 = loop.get_str_30()
183 max_len = max(max_len,len(item_str_30))
184 self.frame.list.insert(Tkinter.END,item_str_30)
185 self.frame.list.insert(Tkinter.END,"")
186 self.frame.title.delete(0,Tkinter.END)
187 self.frame.title.insert(Tkinter.END, self.container_class.header.ljust(max_len))
188
190 contained_object = self.make_contained_object(self.container_class)
191 if contained_object:
192 self.list.append( [contained_object] )
193 self.update_now()
194
196 selected = self.get_selected()
197 # Get 2-D list coordinates of selected object of class "LoopContainedObject":
198 loop_coordinates = self.list2D_coordinates(selected, self.list)
199 main_list_index = loop_coordinates[0]
200 loop_list_index = loop_coordinates[1]
201 if selected is not None:
202 if len(self.list[main_list_index]) == 1:
203 orig_contained_object = self.list[main_list_index][loop_list_index]
204 modified_contained_object = self.edit_contained_object( orig_contained_object )
205 if modified_contained_object is not None: # "Cancel" press results in None
206 self.list[main_list_index][loop_list_index] = modified_contained_object
207 self.update_now()
208 else:
209 tkMessageBox.showerror("Cannot edit this variable", "This variable needs to be isolated/unmerged")
210
212 selected = self.get_selected()
213 # Get 2-D list coordinates of selected object of class "LoopContainedObject":
214 loop_coordinates = self.list2D_coordinates(selected, self.list)
215 main_list_index = loop_coordinates[0]
216 loop_list_index = loop_coordinates[1]
217 if selected is not None:
218 del self.list[main_list_index][loop_list_index]
219 if self.list[main_list_index] == []:
220 del self.list[main_list_index]
221 self.update_now()
222
224 selected = self.get_selected()
225 # Get 2-D list coordinates of selected object of class "LoopContainedObject":
226 loop_coordinates = self.list2D_coordinates(selected, self.list)
227 main_list_index = loop_coordinates[0]
228 loop_list_index = loop_coordinates[1]
229 new_selected_index = selected
230 if selected is not None:
231 # If the selected variable is first in its "loop_list":
232 if loop_list_index == 0:
233 # If not the first "loop_list":
234 if main_list_index != 0:
235 # Then we move up the entire "loop_list":
236 selected_loop_list = self.list[main_list_index]
237 del self.list[main_list_index]
238 new_main_list_index = main_list_index - 1
239 self.list.insert(new_main_list_index, selected_loop_list)
240 new_selected_index = selected - len(self.list[main_list_index])
241 self.update_now()
242
243 # Else we just move up a variable within a "loop_list":
244 else:
245 selected_loop_container = self.list[main_list_index][loop_list_index]
246 del self.list[main_list_index][loop_list_index]
247 new_loop_list_index = loop_list_index - 1
248 self.list[main_list_index].insert(new_loop_list_index, selected_loop_container)
249 new_selected_index = selected - 1
250 self.update_now()
251
252 new_selected_index = self.map_to_listbox_index(new_selected_index)
253 self.frame.list.selection_set(new_selected_index)
254
256 selected = self.get_selected()
257 # Get 2-D list coordinates of selected object of class "LoopContainedObject":
258 loop_coordinates = self.list2D_coordinates(selected, self.list)
259 main_list_index = loop_coordinates[0]
260 loop_list_index = loop_coordinates[1]
261 new_selected_index = selected
262 if selected is not None:
263 # If the selected variable is last in its "loop_list":
264 if loop_list_index == (len(self.list[main_list_index]) - 1):
265 # If not the last "loop_list":
266 if main_list_index != (len(self.list) - 1):
267 # Then we move down the entire "loop_list":
268 selected_loop_list = self.list[main_list_index]
269 del self.list[main_list_index]
270 new_main_list_index = main_list_index + 1
271 self.list.insert(new_main_list_index, selected_loop_list)
272 new_selected_index = selected + len(self.list[main_list_index])
273 self.update_now()
274
275 # Else we just move down a variable within a "loop_list":
276 #elif loop_list_index != (len(self.list[main_list_index]) - 1):
277 else:
278 selected_loop_container = self.list[main_list_index][loop_list_index]
279 del self.list[main_list_index][loop_list_index]
280 new_loop_list_index = loop_list_index + 1
281 self.list[main_list_index].insert(new_loop_list_index, selected_loop_container)
282 new_selected_index = selected + 1
283 self.update_now()
284 #else:
285 #tkMessageBox.showerror("Cannot move this variable down", "Select unmerge instead")
286
287 new_selected_index = self.map_to_listbox_index(new_selected_index)
288 self.frame.list.selection_set(new_selected_index)
289
290
291
292
293
294
295
297 # Notes:
298 # "self.list" is a list of lists, each of which, a
299 # "loop_list", contains "LoopContainedObject" class objects:
300 # eg. [[a], [b, c], [d]]
301 selected = self.get_selected()
302
303 merge_error = 0
304 merge_error_msg = ""
305
306 # The purpose of this function is to "merge" selected objects of class
307 # "LoopContainedObject" into a preceding list:
308 # eg. [[a], [b, c], [d]] => [[a], [b, c, d]]]
309 # where selected 'd' was "merged" into preceding list.
310 # Note, this function can also perform the reverse, provided that the
311 # the selected object of class "LoopContainedObject" is the LAST one
312 # in its "loop_list".
313 # Supported cases:
314 # [[a], [b*, c], [d]] => [[a, b, c], [d]] merge
315 # [[a], [b, c*], [d]] => [[a], [b], [c, d]] unmerge
316 # Unsupported cases:
317 # [[a], [b, c*, d], [e]] => cannot unmerge!
318
319 # Get 2-D list coordinates of selected object of class "LoopContainedObject":
320 loop_coordinates = self.list2D_coordinates(selected, self.list)
321 main_list_index = loop_coordinates[0]
322 loop_list_index = loop_coordinates[1]
323
324 # Checking that an item is actually selected:
325 if selected is not None:
326
327 selected_loop_list = self.list[main_list_index]
328 selected_loop_container = selected_loop_list[loop_list_index]
329 preceding_loop_container = self.list[main_list_index - 1][0]
330
331 # Trying to perform merge?
332 if loop_list_index == 0:
333
334 # Ensure selected "LoopContainerObject" is not in first "loop_list":
335 if main_list_index > 0:
336
337 # Can only carry out merge if "Loop" object sequence lengths are
338 # the same length within a "loop_list":
339 if len(selected_loop_container.contained.parameters.sequence) == len(preceding_loop_container.contained.parameters.sequence):
340
341 # Perform the merge. All variables that are currently merged with the selected variable,
342 # are merged with the new variable(s) as well.
343 i = 0
344 max_index = len(selected_loop_list)
345 while i < max_index:
346 dummy_loop_container = selected_loop_list[0]
347 del self.list[main_list_index][0]
348 self.list[main_list_index - 1].append(dummy_loop_container)
349 i = i + 1
350
351 # Remove the selected "loop_list" if it is now empty:
352 if self.list[main_list_index] == []:
353 del self.list[main_list_index]
354
355 else:
356 merge_error = 1
357 merge_error_msg = "Cannot merge variables with different sequence lengths"
358
359 else:
360 merge_error = 3
361 #merge_error_msg = "Variable is at the top level"
362
363 # Trying to perform an "unmerge":
364 else:
365
366 # Ensure selected "LoopContainerObject" is last object in its "loop_list":
367 if loop_list_index == (len(selected_loop_list) - 1):
368
369 # Perform the unmerge:
370 del self.list[main_list_index][loop_list_index]
371 self.list.insert((main_list_index + 1), [selected_loop_container])
372
373 else:
374 merge_error = 2
375 merge_error_msg = "Unmerge lowest variable in this cluster first"
376
377 if merge_error == 1:
378 tkMessageBox.showerror("Cannot perform merge", merge_error_msg)
379 elif merge_error == 2:
380 tkMessageBox.showerror("Cannot perform unmerge", merge_error_msg)
381 elif merge_error == 3:
382 # non critical errors
383 pass
384 else:
385 #debugger:
386 #print len(self.list)
387 #print ""
388 #for x in self.list:
389 # print len(x)
390 #print "--------------"
391 self.update_now()
392
393
394
396 """Factory function for ContainedObjectBase"""
397 if container_class == LoopContainedObject:
398 return self.make_loop_contained_object()
399 params = {}
400 p = container_class.contained_class.parameters_and_defaults
401 keys = p.keys()
402 keys.sort()
403 for pname in keys:
404 if p[pname][1] == ve_types.String:
405 params[pname] = tkSimpleDialog.askstring(pname,pname,initialvalue=p[pname][0])
406 elif p[pname][1] == ve_types.Integer:
407 params[pname] = tkSimpleDialog.askinteger(pname,pname,initialvalue=p[pname][0])
408 elif p[pname][1] == ve_types.Real:
409 params[pname] = tkSimpleDialog.askfloat(pname,pname,initialvalue=p[pname][0])
410 elif p[pname][1] == ve_types.Sequence:
411 params[pname] = eval("["+tkSimpleDialog.askstring(pname,pname,initialvalue="1,2,3")+"]")
412 if type(params[pname]) is not types.ListType:
413 raise ValueError("You must enter a list in the form of '[1,2,3]'")
414 else:
415 raise NotImplementedError("Don't know about type %s"%(p[pname][1],))
416 if params[pname] is None:
417 raise RuntimeError("Input cancelled")
418 contained = container_class.contained_class(**params) # call constructor
419 return container_class(contained)
420
422 if not isinstance(contained_object,LoopContainedObject):
423 raise NotImplementedError("")
424 orig_contained = contained_object.get_contained()
425 d = LoopParamDialog(self, title="Loop Parameters", orig_values=orig_contained )
426 if d.result:
427 return LoopContainedObject(d.result)
428 else:
429 return
430
432 d = LoopParamDialog(self, title="Loop Parameters" )
433 if d.result:
434 return LoopContainedObject(d.result)
435 else:
436 return
437
438 # Returns index of selected item ignoring blank listbox entries:
439 # eg. if listbox had:
440 #
441 # 0 a
442 # 1 b
443 # 2
444 # 3 c
445 # 4 d
446 #
447 # Then the index of element 'c' would be 2
449 items = self.frame.list.curselection()
450 try:
451 items = map(int, items)
452
453 except ValueError: pass
454 if len(items) > 0:
455 selected_item_index = items[0]
456 if self.frame.list.get(selected_item_index) != "":
457 blankentrycount = 0
458 i = 0
459 while i < selected_item_index:
460 if self.frame.list.get(i) == "":
461 blankentrycount = blankentrycount + 1
462 i = i + 1
463 return (selected_item_index - blankentrycount)
464
465 return None
466
467
468 # Performs reverse of above:
469 # eg. if listbox had:
470 #
471 # 0 a
472 # 1 b
473 # 2
474 # 3 c
475 # 4 d
476 #
477 # Then "mapping" of given index 2 would result in return value of 3
488 ###################################################
489
491 parameters_and_defaults = {'variable':('<repeat>',
492 ve_types.String),
493 'sequence':([1, 1, 1],
494 ve_types.Sequence(ve_types.Real)),
495 'rest_duration_sec':(1.0,
496 ve_types.Real)}
497 __slots__ = (
498 'num_done',
499 )
500
501
513
515 """Container for Loop class"""
516 contained_class = Loop
517 header = " variable rest N values"
529
532 #intercept orig_values argument
533 if kw.has_key('orig_values'):
534 self.orig_values = kw['orig_values']
535 del kw['orig_values']
536 else:
537 self.orig_values = None
538 return tkSimpleDialog.Dialog.__init__(self, *args, **kw )
539
541 Tkinter.Label(master,
542 text="Add sequence of automatic variable values",
543 font=("Helvetica",12,"bold"),).grid(row=0,column=0,columnspan=2)
544
545 var_frame = Tkinter.Frame(master,
546 relief=Tkinter.GROOVE,
547 borderwidth=2)
548 var_frame.grid(row=1,column=0)
549
550 sequence_frame = Tkinter.Frame(master)
551 sequence_frame.grid(row=1,column=1)
552
553 rest_dur_frame = Tkinter.Frame(master)
554 rest_dur_frame.grid(row=2,column=0,columnspan=2)
555
556 # loopable variable frame stuff
557 global loopable_variables
558 num_cols = int(math.ceil(len(loopable_variables)/10.0)) # 10 variables per column
559
560 var_frame_row = 0
561 Tkinter.Label(var_frame,
562 text="Select a variable",
563 font=("Helvetica",12,"bold"),).grid(row=var_frame_row,
564 column=0,
565 columnspan=num_cols)
566
567 self.var_name = Tkinter.StringVar()
568 self.var_name.set("<repeat>")
569 var_names = loopable_variables[:] # copy
570 var_names.sort()
571
572 var_frame_row += 1
573 Tkinter.Radiobutton( var_frame,
574 text="Repeat (Average)",
575 variable=self.var_name,
576 value="<repeat>",
577 anchor=Tkinter.W).grid(row=var_frame_row,
578 column=0,
579 sticky="w")
580 var_frame_row += 1
581 for var_name in var_names:
582 use_row = var_frame_row%10+1
583 Tkinter.Radiobutton( var_frame,
584 text=var_name,
585 variable=self.var_name,
586 value=var_name,
587 anchor=Tkinter.W).grid(row=use_row,
588 column=int(math.floor(var_frame_row/10.)),
589 sticky="w")
590 var_frame_row += 1
591
592 # sequence entry frame
593 seq_row = 0
594 Tkinter.Label(sequence_frame,
595 text="Sequence values",
596 font=("Helvetica",12,"bold"),).grid(row=seq_row,column=0,columnspan=2)
597
598 seq_row += 1
599 self.sequence_type = Tkinter.StringVar()
600 self.sequence_type.set("manual")
601
602 Tkinter.Radiobutton( sequence_frame,
603 text="Manual:",
604 variable=self.sequence_type,
605 value="manual",
606 anchor=Tkinter.W).grid(row=seq_row,column=0,sticky="w")
607
608 self.sequence_manual_string = Tkinter.StringVar()
609 self.sequence_manual_string.set("[1,2,3]")
610 Tkinter.Entry(sequence_frame,
611 textvariable=self.sequence_manual_string).grid(row=seq_row,column=1)
612
613 seq_row += 1
614 Tkinter.Radiobutton( sequence_frame,
615 text="Linear:",
616 variable=self.sequence_type,
617 value="linear",
618 anchor=Tkinter.W).grid(row=seq_row,column=0,sticky="w")
619
620 self.lin_start_tk = Tkinter.DoubleVar()
621 self.lin_start_tk.set(1.0)
622 self.lin_stop_tk = Tkinter.DoubleVar()
623 self.lin_stop_tk.set(100.0)
624 self.lin_n_tk = Tkinter.IntVar()
625 self.lin_n_tk.set(3)
626
627 lin_frame = Tkinter.Frame( sequence_frame)
628 lin_frame.grid(row=seq_row,column=1)
629 Tkinter.Label(lin_frame,text="start:").grid(row=0,column=0)
630 Tkinter.Entry(lin_frame,textvariable=self.lin_start_tk,width=6).grid(row=0,column=1)
631 Tkinter.Label(lin_frame,text=" stop:").grid(row=0,column=2)
632 Tkinter.Entry(lin_frame,textvariable=self.lin_stop_tk,width=6).grid(row=0,column=3)
633 Tkinter.Label(lin_frame,text=" N:").grid(row=0,column=4)
634 Tkinter.Entry(lin_frame,textvariable=self.lin_n_tk,width=6).grid(row=0,column=5)
635
636 seq_row += 1
637 Tkinter.Radiobutton( sequence_frame,
638 text="Log:",
639 variable=self.sequence_type,
640 value="log",
641 anchor=Tkinter.W).grid(row=seq_row,column=0,sticky="w")
642
643 self.log_start_tk = Tkinter.DoubleVar()
644 self.log_start_tk.set(-1.0)
645 self.log_stop_tk = Tkinter.DoubleVar()
646 self.log_stop_tk.set(2.0)
647 self.log_n_tk = Tkinter.IntVar()
648 self.log_n_tk.set(5)
649
650 log_frame = Tkinter.Frame( sequence_frame)
651 log_frame.grid(row=seq_row,column=1)
652 Tkinter.Label(log_frame,text="start: 10^").grid(row=0,column=0)
653 Tkinter.Entry(log_frame,textvariable=self.log_start_tk,width=6).grid(row=0,column=1)
654 Tkinter.Label(log_frame,text=" stop: 10^").grid(row=0,column=2)
655 Tkinter.Entry(log_frame,textvariable=self.log_stop_tk,width=6).grid(row=0,column=3)
656 Tkinter.Label(log_frame,text=" N:").grid(row=0,column=4)
657 Tkinter.Entry(log_frame,textvariable=self.log_n_tk,width=6).grid(row=0,column=5)
658
659 seq_row += 1
660 Tkinter.Radiobutton( sequence_frame,
661 text="Log:",
662 variable=self.sequence_type,
663 value="logb",
664 anchor=Tkinter.W).grid(row=seq_row,column=0,sticky="w")
665
666 self.logb_start_tk = Tkinter.DoubleVar()
667 self.logb_start_tk.set(0.1)
668 self.logb_stop_tk = Tkinter.DoubleVar()
669 self.logb_stop_tk.set(100.0)
670 self.logb_n_tk = Tkinter.IntVar()
671 self.logb_n_tk.set(5)
672
673 logb_frame = Tkinter.Frame( sequence_frame)
674 logb_frame.grid(row=seq_row,column=1)
675 Tkinter.Label(logb_frame,text="start:").grid(row=0,column=0)
676 Tkinter.Entry(logb_frame,textvariable=self.logb_start_tk,width=6).grid(row=0,column=1)
677 Tkinter.Label(logb_frame,text=" stop:").grid(row=0,column=2)
678 Tkinter.Entry(logb_frame,textvariable=self.logb_stop_tk,width=6).grid(row=0,column=3)
679 Tkinter.Label(logb_frame,text=" N:").grid(row=0,column=4)
680 Tkinter.Entry(logb_frame,textvariable=self.logb_n_tk,width=6).grid(row=0,column=5)
681
682 # rest duration frame
683 Tkinter.Label(rest_dur_frame,
684 text="Other sequence parameters",
685 font=("Helvetica",12,"bold"),).grid(row=0,column=0,columnspan=2)
686
687 Tkinter.Label(rest_dur_frame,
688 text="Interval duration (seconds)").grid(row=1,column=0)
689 self.rest_dur = Tkinter.DoubleVar()
690 self.rest_dur.set(0.5)
691 Tkinter.Entry(rest_dur_frame,
692 textvariable=self.rest_dur,
693 width=10).grid(row=1,column=1)
694
695 self.shuffle_tk_var = Tkinter.BooleanVar()
696 self.shuffle_tk_var.set(0)
697 Tkinter.Checkbutton( rest_dur_frame,
698 text="Shuffle sequence order",
699 variable=self.shuffle_tk_var).grid(row=2,column=0,columnspan=2)
700
701 if self.orig_values is not None:
702 self.var_name.set( self.orig_values.parameters.variable )
703
704 self.sequence_manual_string.set( str(self.orig_values.parameters.sequence) )
705
706 self.rest_dur.set( self.orig_values.parameters.rest_duration_sec )
707
708
710 if self.sequence_type.get() == "manual":
711 try:
712 seq = eval(self.sequence_manual_string.get())
713 except Exception, x:
714 tkMessageBox.showwarning("Invalid sequence parameters",
715 "Manual sequence entry: %s"%(str(x),),
716 parent=self)
717 return 0
718 if type(seq) != types.ListType:
719 tkMessageBox.showwarning("Invalid sequence parameters",
720 "Manual sequence entry: Not a list",
721 parent=self)
722 return 0
723 elif self.sequence_type.get() == "linear":
724 start = self.lin_start_tk.get()
725 stop = self.lin_stop_tk.get()
726 n = self.lin_n_tk.get()
727 if n < 2:
728 tkMessageBox.showwarning("Invalid sequence parameters",
729 "Must have n >= 2.",
730 parent=self)
731 return 0
732
733 incr = (stop-start)/float(n-1)
734 seq = range(n)
735 for i in range(n):
736 seq[i] = i*incr + start
737 elif self.sequence_type.get() == "log":
738 start = self.log_start_tk.get()
739 stop = self.log_stop_tk.get()
740 n = self.log_n_tk.get()
741 if n < 2:
742 tkMessageBox.showwarning("Invalid sequence parameters",
743 "Must have n >= 2.",
744 parent=self)
745 return 0
746
747 incr = (stop-start)/float(n-1)
748 seq = range(n)
749 for i in range(n):
750 seq[i] = 10.0**( i*incr + start )
751 elif self.sequence_type.get() == "logb":
752 start = self.logb_start_tk.get()
753 stop = self.logb_stop_tk.get()
754 start = math.log10(start)
755 stop = math.log10(stop)
756 n = self.logb_n_tk.get()
757 if n < 2:
758 tkMessageBox.showwarning("Invalid sequence parameters",
759 "Must have n >= 2.",
760 parent=self)
761 return 0
762 incr = (stop-start)/float(n-1)
763 seq = range(n)
764 for i in range(n):
765 seq[i] = 10.0**( i*incr + start )
766 else:
767 tkMessageBox.showwarning("Invalid sequence parameters",
768 "Invalid sequence type.",
769 parent=self)
770 return 0
771 rest_dur_sec = self.rest_dur.get()
772
773 if self.shuffle_tk_var.get():
774 random.shuffle(seq)
775
776 self.result = Loop(variable=self.var_name.get(),
777 sequence=seq,
778 rest_duration_sec=rest_dur_sec)
779 return 1
780
782 # clear tk variables
783 self.var_name = None
784 self.sequence_type = None
785 self.sequence_manual_string = None
786 self.rest_dur = None
787 # call master's destroy method
788 tkSimpleDialog.Dialog.destroy(self)
789
791 class ConnectWindow(Tkinter.Frame):
792 def __init__(self,master=None,hostname="",port=7766,**kw):
793 # Allow VisionEgg Tkinter exception window
794 VisionEgg.config._Tkinter_used = True
795
796 Tkinter.Frame.__init__(self,master, **kw)
797 self.winfo_toplevel().title("EPhysGUI Connect - Vision Egg")
798 current_row = 0
799 Tkinter.Message(self,\
800 text='Welcome to the "EPhys GUI" of the Vision Egg!\n\n'+\
801 'Please enter the hostname '+\
802 'and port number '+\
803 'of the computer on which you have the '+\
804 '"EPhys server" running.').grid(row=current_row,column=0,columnspan=2)
805 hostname = 'localhost'
806
807 self.hostname_tk = Tkinter.StringVar()
808 self.hostname_tk.set(hostname)
809 current_row += 1
810 Tkinter.Label(self,text="Hostname:").grid(row=current_row, column=0)
811 Tkinter.Entry(self,textvariable=self.hostname_tk).grid(row=current_row, column=1)
812
813 self.port_tk = Tkinter.IntVar()
814 self.port_tk.set(port)
815 current_row += 1
816 Tkinter.Label(self,text="Port:").grid(row=current_row, column=0)
817 Tkinter.Entry(self,textvariable=self.port_tk).grid(row=current_row, column=1)
818
819 current_row += 1
820 bf = Tkinter.Frame(self)
821 bf.grid(row=current_row,column=0,columnspan=2)
822 ok=Tkinter.Button(bf,text="OK",command=self.ok)
823 ok.grid(row=0,column=0)
824 ok.focus_force()
825 ok.bind('<Return>',self.ok)
826 Tkinter.Button(bf,text="Cancel",command=self.quit).grid(row=0,column=1)
827 self.result = None
828
829 def ok(self,dummy_arg=None):
830 self.result = (self.hostname_tk.get(),self.port_tk.get())
831 self.destroy()
832 self.quit()
833
834 connect_win = ConnectWindow(hostname=hostname,port=port)
835 connect_win.pack()
836 connect_win.mainloop()
837 return connect_win.result
838
843 Tkinter.Frame.__init__(self,master,**kw)
844 self.winfo_toplevel().title("Gamma - Vision Egg")
845 self.ephys_server = ephys_server
846
847 self.columnconfigure(0,weight=1)
848
849 row = 0
850 Tkinter.Label(self,
851 font=("Helvetica",12,"bold"),
852 text="Load Gamma Table").grid(row=row)
853
854 row += 1
855 Tkinter.Button(self,
856 text="Set from .ve_gamma file...",
857 command=self.set_from_file).grid(row=row,sticky="w")
858
859 row += 1
860 Tkinter.Button(self,
861 text="Set to monitor default (linear gamma table)",
862 command=self.set_monitor_default).grid(row=row,sticky="w")
863
864 row += 1
865 invert_frame = Tkinter.Frame(self)
866 invert_frame.grid(row=row,sticky="we")
867
868 Tkinter.Button(invert_frame,
869 text="Linearize luminance for gammas",
870 command=self.linearize).grid(row=0,column=0)
871
872 Tkinter.Label(invert_frame,
873 text="Red:").grid(row=0,column=1)
874
875 self.red_gamma = Tkinter.DoubleVar()
876 self.red_gamma.set(2.2)
877
878 Tkinter.Entry(invert_frame,
879 textvariable=self.red_gamma,
880 width=5).grid(row=0,column=2)
881
882 Tkinter.Label(invert_frame,
883 text="Green:").grid(row=0,column=3)
884
885 self.green_gamma = Tkinter.DoubleVar()
886 self.green_gamma.set(2.2)
887
888 Tkinter.Entry(invert_frame,
889 textvariable=self.green_gamma,
890 width=5).grid(row=0,column=4)
891
892 Tkinter.Label(invert_frame,
893 text="Blue:").grid(row=0,column=5)
894
895 self.blue_gamma = Tkinter.DoubleVar()
896 self.blue_gamma.set(2.2)
897
898 Tkinter.Entry(invert_frame,
899 textvariable=self.blue_gamma,
900 width=5).grid(row=0,column=6)
901
902 row += 1
903 self.success_label = Tkinter.Label(self)
904 self.success_label.grid(row=row)
905
907 # c is a constant scale factor. It is always 1.0 when
908 # luminance is normalized to range [0.0,1.0] and input units
909 # in range [0.0,1.0], as is OpenGL standard.
910 c = 1.0
911 inc = 1.0/255
912 target_luminances = numpy.arange(0.0,1.0+inc,inc)
913 output_ramp = numpy.zeros(target_luminances.shape,dtype=numpy.int32)
914 for i in range(len(target_luminances)):
915 L = target_luminances[i]
916 if L == 0.0:
917 v_88fp = 0
918 else:
919 v = math.exp( (math.log(L) - math.log(c)) /gamma)
920 v_88fp = int(round((v*255) * 256)) # convert to from [0.0,1.0] floating point to [0.0,255.0] 8.8 fixed point
921 output_ramp[i] = v_88fp # 8.8 fixed point format
922 return list(output_ramp) # convert to Python list
923
925 self.success_label.configure(text="Setting...")
926 try:
927 red = self.get_corrected_gamma_table(self.red_gamma.get())
928 green = self.get_corrected_gamma_table(self.green_gamma.get())
929 blue = self.get_corrected_gamma_table(self.blue_gamma.get())
930 except:
931 self.success_label.configure(text="Calculation error")
932 raise
933 try:
934 if self.ephys_server.set_gamma_ramp(red,green,blue):
935 self.success_label.configure(text="Success")
936 else:
937 self.success_label.configure(text="Failed: Invalid gamma values?")
938 except Exception,x:
939 self.success_label.configure(text="Failed: %s: %s"%(x.__class__,str(x)))
940 raise
941
943 self.success_label.configure(text="Setting...")
944 try:
945 red = self.get_corrected_gamma_table(1.0) # linear gamma table
946 except:
947 self.success_label.configure(text="Calculation error")
948 raise
949 green = red
950 blue = red
951 try:
952 if self.ephys_server.set_gamma_ramp(red,green,blue):
953 self.success_label.configure(text="Success")
954 else:
955 self.success_label.configure(text="Failed: Invalid gamma values?")
956 except Exception,x:
957 self.success_label.configure(text="Failed: %s: %s"%(x.__class__,str(x)))
958 raise
959
961 self.success_label.configure(text="Setting...")
962 filename = tkFileDialog.askopenfilename(
963 parent=self,
964 defaultextension=".ve_gamma",
965 filetypes=[('Configuration file','*.ve_gamma')],
966 initialdir=VisionEgg.config.VISIONEGG_USER_DIR)
967 if not filename:
968 self.success_label.configure(text="No file given")
969 return
970 fd = open(filename,"r")
971 gamma_values = []
972 for line in fd.readlines():
973 line = line.strip() # remove leading/trailing whitespace
974 if line.startswith("#"): # comment, ignore
975 continue
976 try:
977 gamma_values.append( map(int, line.split() ) )
978 except Exception, x:
979 self.success_label.configure(text="File error")
980 raise
981 if len(gamma_values[-1]) != 3:
982 self.success_label.configure(text="File error")
983 raise RuntimeError("expected 3 values per gamma entry")
984 if len(gamma_values) != 256:
985 self.success_label.configure(text="File error")
986 raise RuntimeError("expected 256 gamma entries")
987 red, green, blue = zip(*gamma_values)
988 try:
989 if self.ephys_server.set_gamma_ramp(red,green,blue):
990 self.success_label.configure(text="Success")
991 else:
992 self.success_label.configure(text="Failed: Invalid gamma values?")
993 except Exception,x:
994 self.success_label.configure(text="Failed: %s: %s"%(x.__class__,str(x)))
995 raise
996
999 Tkinter.Toplevel.__init__(self,master,**cnf)
1000 if ephys_server is None:
1001 raise ValueError("Must specify ephys_server")
1002 self.ephys_server = ephys_server
1003
1004 self.columnconfigure(1,weight=1)
1005
1006 row = 0
1007 Tkinter.Label(self,text="Frames per second").grid(row=row,column=0)
1008 self.fps_var = Tkinter.DoubleVar()
1009 self.fps_var.set(12.0)
1010 Tkinter.Entry(self,textvariable=self.fps_var).grid(row=row,column=1,sticky="we")
1011 row += 1
1012 Tkinter.Label(self,text="Filename base").grid(row=row,column=0)
1013 self.filename_base = Tkinter.StringVar()
1014 self.filename_base.set("im")
1015 Tkinter.Entry(self,textvariable=self.filename_base).grid(row=row,column=1,sticky="we")
1016 row += 1
1017 Tkinter.Label(self,text="Filename suffix").grid(row=row,column=0)
1018 self.filename_suffix = Tkinter.StringVar()
1019 self.filename_suffix.set(".tif")
1020 Tkinter.Entry(self,textvariable=self.filename_suffix).grid(row=row,column=1,sticky="we")
1021 row += 1
1022 Tkinter.Label(self,text="Save directory on server").grid(row=row,column=0)
1023 self.server_save_dir = Tkinter.StringVar()
1024 server_dir = self.ephys_server.get_cwd()
1025 self.server_save_dir.set(server_dir)
1026 Tkinter.Entry(self,textvariable=self.server_save_dir).grid(row=row,column=1,sticky="we")
1027 row += 1
1028 Tkinter.Button(self,text="Save movie",command=self.do_it).grid(row=row,column=0,columnspan=2)
1029 self.focus_set()
1030 self.grab_set()
1032 fps = self.fps_var.get()
1033 filename_base = self.filename_base.get()
1034 filename_suffix = self.filename_suffix.get()
1035 server_save_dir = self.server_save_dir.get()
1036 self.ephys_server.save_image_sequence(fps=fps,
1037 filename_base=filename_base,
1038 filename_suffix=filename_suffix,
1039 save_dir=server_save_dir)
1040 self.destroy()
1041
1043 - def __init__(self,
1044 master=None,
1045 client_list=None,
1046 server_hostname='',
1047 server_port=7766,
1048 **cnf):
1049
1050 if hasattr(VisionEgg, '_exception_hook_keeper'):
1051 # Keep original exception handler
1052 self._orig_report_callback_exception = Tkinter.Tk.report_callback_exception
1053 self._tk = Tkinter.Tk
1054 # Use Vision Egg exception handler
1055 Tkinter.Tk.report_callback_exception = VisionEgg._exception_hook_keeper.handle_exception
1056
1057 # Allow VisionEgg Tkinter exception window
1058 VisionEgg.config._Tkinter_used = True
1059
1060 # create myself
1061 Tkinter.Frame.__init__(self,master, **cnf)
1062 self.winfo_toplevel().title("EPhysGUI - Vision Egg")
1063
1064 self.client_list = client_list
1065
1066 self.server_hostname = server_hostname
1067 self.server_port = server_port
1068
1069 self.pyro_client = VisionEgg.PyroClient.PyroClient(self.server_hostname,self.server_port)
1070 self.ephys_server = self.pyro_client.get("ephys_server")
1071 self.ephys_server.first_connection()
1072
1073 self.stim_onset_cal_tk_var = Tkinter.BooleanVar()
1074 self.stim_onset_cal_tk_var.set(0)
1075
1076 self.autosave_dir = Tkinter.StringVar()
1077 self.autosave_dir.set( os.path.abspath(os.curdir) )
1078
1079 self.autosave_basename = Tkinter.StringVar()
1080
1081 # create menu bar
1082 self.bar = Tkinter.Menu(tearoff=0)
1083 top = self.winfo_toplevel()
1084 top.configure(menu=self.bar)
1085
1086 self.bar.file_menu = Tkinter.Menu(self.bar, name="file_menu")
1087 self.bar.add_cascade(label="File",menu=self.bar.file_menu)
1088
1089 self.bar.file_menu.add_command(label='Save image sequence...', command=self.save_image_sequence)
1090 self.bar.file_menu.add_command(label='Save configuration file...', command=self.save_config)
1091 self.bar.file_menu.add_command(label='Load configuration file...', command=self.load_config)
1092 self.bar.file_menu.add_command(label='Load auto-saved .py parameter file...', command=self.load_params)
1093 self.bar.file_menu.add_separator()
1094 self.bar.file_menu.add_command(label='Load Vision Egg script...', command=self.load_demoscript)
1095 self.bar.file_menu.add_separator()
1096
1097 self.quit_server_too = Tkinter.BooleanVar()
1098 self.quit_server_too.set(1)
1099 self.bar.file_menu.add_checkbutton(label='Quit server too',
1100 variable=self.quit_server_too)
1101 self.bar.file_menu.add_command(label='Quit',
1102 command=self.quit,
1103 )
1104
1105 stimkey = self.ephys_server.get_stimkey()
1106 self.stimulus_tk_var = Tkinter.StringVar()
1107 self.stimulus_tk_var.set( stimkey )
1108
1109 self.bar.stimuli_menu = Tkinter.Menu(self.bar, name="stimuli_menu")
1110 self.bar.add_cascade(label="Stimuli",menu=self.bar.stimuli_menu)
1111 for maybe_stimkey, maybe_control_frame, maybe_title in self.client_list:
1112 if maybe_title != "Vision Egg Script":
1113 self.bar.stimuli_menu.add_radiobutton(label=maybe_title,
1114 command=self.change_stimulus,
1115 variable=self.stimulus_tk_var,
1116 value=maybe_stimkey)
1117
1118 self.bar.calibration_menu = Tkinter.Menu(self.bar, name="calibration_menu")
1119 self.bar.add_cascade(label="Configure/Calibrate",
1120 menu=self.bar.calibration_menu)
1121
1122 self.bar.calibration_menu.add_command(label='3D Perspective...', command=self.launch_screen_pos)
1123 self.bar.calibration_menu.add_command(label='Stimulus onset timing...', command=self.launch_stim_onset_cal)
1124 self.bar.calibration_menu.add_command(label='Load gamma table...', command=self.launch_gamma_panel)
1125 self.notify_on_dropped_frames = Tkinter.BooleanVar()
1126 self.notify_on_dropped_frames.set(1)
1127 self.bar.calibration_menu.add_checkbutton(label='Warn on frame skip',
1128 variable=self.notify_on_dropped_frames)
1129
1130 self.override_t_abs_sec = Tkinter.StringVar() # Tkinter DoubleVar loses precision
1131 self.override_t_abs_sec.set("0.0")
1132
1133 self.override_t_abs_on = Tkinter.BooleanVar()
1134 self.override_t_abs_on.set(0)
1135 self.bar.calibration_menu.add_checkbutton(label='Override server absolute time (CAUTION)',
1136 variable=self.override_t_abs_on)
1137
1138 row = 0
1139
1140 # options for self.stim_frame in grid layout manager
1141 self.stim_frame_cnf = {'row':row,
1142 'column':0,
1143 'columnspan':2,
1144 'sticky':'nwes'}
1145
1146 row += 1
1147 Tkinter.Label(self,
1148 text="Sequence information",
1149 font=("Helvetica",12,"bold")).grid(row=row,column=0)
1150 row += 1
1151 # options for self.loop_frame in grid layout manager
1152 self.loop_frame_cnf = {'row':row,
1153 'column':0,
1154 'sticky':'nwes'}
1155
1156 row -= 1
1157 Tkinter.Label(self,
1158 text="Parameter Save Options",
1159 font=("Helvetica",12,"bold")).grid(row=row,column=1)
1160 row += 1
1161 self.auto_save_frame = Tkinter.Frame(self)
1162 asf = self.auto_save_frame # shorthand
1163 asf.grid(row=row,column=1,sticky="nwes")
1164 asf.columnconfigure(1,weight=1)
1165
1166 asf.grid_row = 0
1167 self.autosave = Tkinter.BooleanVar()
1168 self.autosave.set(1)
1169 self.auto_save_button = Tkinter.Checkbutton(asf,
1170 text="Auto save trial parameters",
1171 variable=self.autosave)
1172 self.auto_save_button.grid(row=asf.grid_row,column=0,columnspan=2)
1173
1174 self.param_file_type_tk_var = Tkinter.StringVar()
1175 self.param_file_type_tk_var.set("Python format")
1176