1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import sys
17 import types
18 import Tkinter
19 import threading
20 import traceback
21 import warnings
22 import weakref
23 import tkMessageBox
24
25 from mglutil.gui.BasicWidgets.Tk.TreeWidget.objectBrowser import ObjectBrowser
26 from mglutil.util.callback import CallbackManager, CallBackFunction
27
28
30 """Tk frame onto which a user can place selected widgets"""
31
32 - def __init__(self, name, master=None, network=None, width=120, height=90):
33
34
35 self.widgets = []
36 if master is None:
37 self.master = Tkinter.Toplevel()
38 self.master.title(name)
39 self.master.protocol('WM_DELETE_WINDOW', self.withdraw_cb)
40 else:
41 self.master = master
42
43 self.network = network
44 self.editor = network.getEditor()
45
46
47 if master is None:
48 buttonsFrame = Tkinter.Frame(self.master)
49 self.buttonRun = Tkinter.Button(buttonsFrame, text='Run', command=network.run)
50 self.buttonRun.pack(side='left', expand=1, fill='x')
51 if hasattr(network, 'isApplication') is True:
52 self.buttonQuit = Tkinter.Button(buttonsFrame, text='Quit', command=self.master.quit)
53 self.buttonQuit.pack(side='left', expand=1, fill='x')
54 else:
55 self.buttonShowHideNetwork = Tkinter.Button(buttonsFrame, text='Show / Hide Vision',
56 command=self.editor.toggleGuiVisibility)
57 self.buttonShowHideNetwork.pack(side='left', expand=1, fill='x')
58 buttonsFrame.pack(side='top', fill='x')
59
60
61 self.frame = Tkinter.Frame(
62 self.master, relief='sunken', bd=3, bg='#c3d0a6')
63 self.frame.configure(width=width, height=height)
64 self.frame.pack(side='top', expand=1, fill='both')
65
66
68 """
69 """
70
71 if hasattr(self.network, 'isApplication') is True:
72 if len(self.network.userPanels) == 1:
73 self.master.quit()
74 else:
75 self.master.iconify()
76 else:
77 self.master.iconify()
78 self.editor.master.master.master.deiconify()
79
80
82
83
84 labelSide = widget.widgetGridCfg['labelSide']
85 if labelSide is None:
86 labelSide = 'left'
87
88 widget.widgetFrame.place(relx=relx, rely=rely, anchor=Tkinter.CENTER)
89 if labelSide == 'left':
90 labelx = .5 * widget.widgetFrame.winfo_width() \
91 / widget.widgetFrame.master.winfo_width()
92 widget.tklabel.place(relx=relx-labelx, rely=rely, anchor='e')
93 elif labelSide == 'right':
94 labelx = .5 * widget.widgetFrame.winfo_width() \
95 / widget.widgetFrame.master.winfo_width()
96 widget.tklabel.place(relx=relx+labelx, rely=rely, anchor='w')
97 elif labelSide == 'top':
98 labely = .5 * widget.widgetFrame.winfo_height() \
99 / widget.widgetFrame.master.winfo_height()
100 widget.tklabel.place(relx=relx, rely=rely-labely, anchor='s')
101 elif labelSide == 'bottom':
102 labely = .5 * widget.widgetFrame.winfo_height() \
103 / widget.widgetFrame.master.winfo_height()
104 widget.tklabel.place(relx=relx, rely=rely+labely, anchor='n')
105 else:
106 warnings.warn('Wrong side for label')
107
108
118
119
127
128
130
131 widget.menu.post(event.x_root, event.y_root)
132
133
166
167
179
180
181
183 """This class provides show / hide for all parameter panels
184 """
185 - def __init__(self, node, master=None, title=None, applyFun=None,
186 dismissFun=None):
187
188 self.node = weakref.ref(node)
189 self.visible = 0
190
191
192 self.applyFun = applyFun
193 self.dismissFun = dismissFun
194 if self.dismissFun is None:
195 self.dismissFun = self.hide
196
197 if master is None:
198 master=Tkinter.Toplevel()
199 self.master = master
200 if title:
201 self.master.title(title)
202 self.master.withdraw()
203 self.master.protocol('WM_DELETE_WINDOW', self.dismissFun )
204 else:
205 self.master = master
206
207
208 self.mainFrame = Tkinter.Frame(self.master)
209 self.mainFrame.pack(fill='both',expand=1)
210
211
212 self.createMenus(self.mainFrame)
213
214
215 self.widgetFrame = Tkinter.Frame(self.mainFrame, borderwidth=3,
216 bg='#c3d0a6', relief='ridge')
217
218 self.applyButton = Tkinter.Button(self.mainFrame, text="Apply",
219 command=self.forceRun)
220 self.dismissButton = Tkinter.Button(self.mainFrame, text="Dismiss",
221 command=self.dismissFun)
222 self.widgetFrame.pack(fill='both', expand=1)
223 self.applyButton.pack(side='left', fill='x', expand=1)
224 self.dismissButton.pack(side='left')
225
226
228 self.mBar = Tkinter.Frame(parent, relief=Tkinter.RAISED,
229 borderwidth=2)
230 self.mBar.pack(side='top',fill='x')
231 self.menuButtons = {}
232 self.makeOptionsMenu(self.mBar)
233 apply( self.mBar.tk_menuBar, self.menuButtons.values() )
234
235
237 Options_button = Tkinter.Menubutton(parent, text='Options',
238 underline=0)
239 self.menuButtons['Options'] = Options_button
240 Options_button.pack(side=Tkinter.LEFT, padx="1m")
241
242
243 Options_button.menu = Tkinter.Menu(Options_button, tearoff=False)
244
245 self.immediateTk = Tkinter.IntVar()
246 self.immediateTk.set(1)
247 Options_button.menu.add_checkbutton(label='Immediate',
248 variable=self.immediateTk,
249 command=self.setImmediate)
250
251
252 Options_button.menu.add_separator()
253 Options_button.menu.add_command(label='Dismiss', underline=0,
254 command=self.dismissFun)
255 Options_button['menu'] = Options_button.menu
256
257
264
265
267 """ show paramter panel
268 """
269 if self.master.winfo_ismapped() == 0:
270 self.master.deiconify()
271 self.master.lift()
272
273
274 self.node().paramPanelTk.set(1)
275 self.visible = 1
276
277
278 - def hide(self, event=None):
279 if self.master.winfo_ismapped() == 1:
280 self.master.withdraw()
281
282
283 self.node().paramPanelTk.set(0)
284 self.visible = 0
285
286
288 if self.master.winfo_ismapped() == 1:
289 self.hide()
290 else:
291 self.show()
292
293
295 if isinstance(self.master, Tkinter.Toplevel):
296 self.master.destroy()
297 else:
298 self.mainFrame.destroy()
299
300
301 - def run(self, event=None):
302
303
304 if self.immediateTk.get():
305 if self.applyFun is not None:
306 self.applyFun()
307
308
310
311
312 if self.applyFun is not None:
313 self.applyFun()
314
315
317 """Base class for all objects that can be added to a Canvas."""
318
319
320
322 return self.vEditor()
323
325 self.vEditor = weakref.ref(editor)
326
328 del self.vEditor
329
330
331 editor = property(getEditor, setEditor, delEditor,
332 "Used for backwards compatibility because we changed this to a weakref.")
333
334
336 self.name = name
337
338
339
340
341
342
343 self.vEditor = None
344
345 self._modified = False
346
347
348
349 self._original = True
350
351
352
353
354
355
357 """set the _modified attribute. Users should not call this method"""
358
359 assert modified in [True, False]
360 self._modified = modified
361
362
364 """set the _original attribute. Users should not call this method"""
365
366 assert original in [True, False]
367 self._original = original
368
369
371 """Base class for objects that can be added to a Canvas.
372 Network items sublassing this have to extend the buildIcons method to create
373 a Canvas geometry representing this item.
374 """
375
376 - def __init__(self, name='NoName', autoRun=True):
377 NetworkItemsBase.__init__(self, name)
378
379 self.paramPanel = None
380 self.iconMaster = None
381 self.id = None
382
383 self.iconTag = None
384
385
386
387 self.network = None
388
389 self.objEditor = None
390 self.dynamicComputeFunction = None
391
392 self.selected = 0
393 self.nodeScaleFactor = 1.0
394 self.distScaleFactor = 1.0
395 self.posx = 0
396 self.posy = 0
397 self.menu = None
398 self.highlightOptions = {'highlightbackground':'red'}
399 self.unhighlightOptions = {'highlightbackground':'gray50'}
400 self.selectOptions = {'background':'yellow'}
401 self.deselectOptions = {'background':'gray85'}
402 self.objectBrowser = None
403 self.editFuncWindowWidth = 500
404 self.editFuncWindowHeight = 200
405 self.netSwitchOriginal = None
406 self.frozen = False
407 self.autoRun = autoRun
408
409
410 self.isSchedulingNode = False
411
412
413
414 self.frozenTk = Tkinter.IntVar()
415 self.frozenTk.set(self.frozen)
416
417 self.autoRunTk = Tkinter.IntVar()
418 self.autoRunTk.set(self.autoRun)
419
420
421
422
423 self.runLock = threading.RLock()
424
425
426 self.mouseButtonFlag = 0
427 self.mouseActionEvents = [
428 '<Button-1>', '<Shift-Button-1>',
429 '<Alt-Button-1>', '<Control-Button-1>',
430 '<Double-Button-1>', '<Double-Shift-Button-1>',
431 '<Double-Alt-Button-1>', '<Double-Control-Button-1>',
432 '<Button-2>', '<Shift-Button-2>',
433 '<Alt-Button-2>', '<Control-Button-2>',
434 '<Double-Button-2>', '<Double-Shift-Button-2>',
435 '<Double-Alt-Button-2>', '<Double-Control-Button-2>',
436 '<Button-3>', '<Shift-Button-3>',
437 '<Alt-Button-3>', '<Control-Button-3>',
438 '<Double-Button-3>', '<Double-Shift-Button-3>',
439 '<Double-Alt-Button-3>', '<Double-Control-Button-3>'
440 ]
441 self.mouseAction = {}
442 for event in self.mouseActionEvents:
443 self.mouseAction[event] = None
444
445 self.mouseAction['<Button-3>'] = self.postItemMenu
446
447
449 self.autoRun = not self.autoRun
450 self.autoRunTk.set(self.autoRun)
451 self._setModified(True)
452
453
455 if self.frozen:
456 self.unfreeze()
457 else:
458 self.freeze()
459 self.frozen = not self.frozen
460 self.frozenTk.set(self.frozen)
461 self._setModified(True)
462
463
465
466
467 col = '#b6d3f6'
468 self.unfreezeCol = self.setColor(col)
469 self.deselectOptions["fill"] = col
470
471
473
474
475
476
477 if self.editor.colorNodeByLibraryTk.get() == 1:
478 if self.library is not None:
479 col = self.library.color
480 else: col = "gray85"
481 else:
482 col = "gray85"
483 self.deselectOptions['fill'] = col
484 self.setColor(col)
485
486
487
488 - def run(self, force=0):
489 """run this node.
490 if force is set, the node will run regardless of the availability of new data.
491 return 0 if run failed. (Thread safe)"""
492
493 if force or self.forceExecution:
494 self.forceExecution = 1
495 elif not self.autoRun or self.frozen:
496 return
497
498
499
500 ed = self.getEditor()
501
502 self.runLock.acquire()
503
504
505
506
507
508 try:
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525 if ed.flashNodesWhenRun:
526 c = self.iconMaster
527 if c is not None:
528 c.tk.call((c._w, 'itemconfigure', self.innerBox,
529 '-outline', '#FF0000', '-width', 4))
530 col = '#000000'
531 if sys.platform !='win32' or not \
532 ed.withThreads:
533 ed.update_idletasks()
534
535 stat = self.computeFunction()
536
537 if ed.flashNodesWhenRun and stat!='Stop':
538 if col=='#557700':
539 col = self.colorBeforeFail
540
541
542
543 if c is not None:
544 c.tk.call((c._w, 'itemconfigure', self.innerBox,
545 '-outline', col, '-width', 1))
546
547 self.forceExecution = 0
548
549 except:
550 print
551 print "***********************************************************"
552 print "*** ERROR while executing node: ", self.name
553 print "***********************************************************"
554 self.forceExecution = 0
555 traceback.print_exc()
556 if ed.flashNodesWhenRun:
557 if col != '#557700':
558 self.colorBeforeFail = col
559 c.tk.call((c._w, 'itemconfigure', self.innerBox,
560 '-outline', '#557700'))
561
562 self.runLock.release()
563 return 'stop'
564
565 self.runLock.release()
566
567 if stat == 'Go':
568
569 if len(self.specialOutputPorts) \
570 and len(self.specialOutputPorts[0].children):
571 self.scheduleChildren(portList=[self.specialOutputPorts[0]])
572
573 if stat is None:
574 return 1
575 else:
576 return stat
577
578
580 if self.network.postedMenu:
581 self.network.postedMenu.unpost()
582 self.network.postedMenu = None
583 elif self.menu:
584 self.menu.post(event.x_root, event.y_root)
585 self.network.postedMenu = self.menu
586
587
589 apply( eval("self.menu."+type), args, kw )
590
591
593 return '<%s %s>'%(self.__class__.__name__, self.name)
594
595
596 - def rename(self, name, tagModified=True):
597 self.name=name
598 if tagModified is True:
599 self._setModified(True)
600
601
603
604
605 pass
606
607
609
610
611 pass
612
613
615
616
617 pass
618
619
621
622
623 pass
624
625
627 pass
628
629
631 pass
632
633
635 self.selected = 1
636 if self.iconMaster:
637 self.iconMaster.addtag_withtag('selected', self.iconTag)
638
639
641 self.selected = 0
642 if self.iconMaster:
643 self.iconMaster.dtag(self.iconTag, 'selected')
644
645
647
648 ed = self.getEditor()
649 if self.iconMaster:
650 self.iconMaster.delete(self.iconTag)
651 self.iconTag = None
652
653
654
655
656 if ed.currentNetwork is None:
657 return
658 postedMenu = ed.currentNetwork.postedMenu
659 if self.menu:
660 if postedMenu and postedMenu == self.menu:
661 ed.currentNetwork.postedMenu = None
662 self.menu.destroy()
663 self.menu = None
664
665
669
670
672 """method to be implmented by subclass
673 this method should create the geometric primitives for this item
674 and tag them all with self.iconTag
675 define its uniqueTag
676 set its tags
677 """
678
679 ed = self.getEditor()
680 if ed is not None:
681 self.paramPanel = ParamPanel(self, master=None, title=self.name,
682 applyFun=self.schedule_cb,
683 dismissFun=self.hideParamPanel)
684 if self.menu is None:
685
686 self.menu = Tkinter.Menu(ed, title=self.name, tearoff=False)
687 self.menu.add_separator()
688
689 self.menu.bind("<Any-Button>", ed.myButtonPress, '+')
690 self.iconMaster = canvas
691
692
694 self.paramPanel.hide()
695
696
698
699 pass
700
701
703 if self.objectBrowser is None:
704 self.objectBrowser = ObjectBrowser(
705 self, rootName=self.name,
706 title='Introspect Node: %s'%self.name,
707 refresh=self._introspectCB)
708 else:
709 self.objectBrowser.show()
710
711
713 """helper method used for the introspect data GUI"""
714 return self
715
716
718 """Delete a port from a node. Removes it from the list of ports,
719 updates the portsDescr list and return the descriptin of the deleted port,
720 renumber all ports after this ports and mark them modified. Update code.
721 """
722
723
724
725 net = self.network
726
727 cfg = p.configure()
728
729 from ports import InputPort, OutputPort, SpecialInputPort, \
730 SpecialOutputPort
731
732
733 if p.visible:
734 p.deleteIcon()
735
736
737 ports = None
738 if isinstance(p, SpecialInputPort):
739 self.specialInputPorts.remove(p)
740
741 elif isinstance(p, SpecialOutputPort):
742 self.specialOutputPorts.remove(p)
743
744 elif isinstance(p, InputPort):
745 ports = self.inputPorts
746 if p.widget:
747 p.deleteWidget()
748 p.deleteIcon()
749 self.inputPorts.remove(p)
750 del self.inputPortsDescr[p.number]
751
752 elif isinstance(p, OutputPort):
753 ports = self.outputPorts
754 self.outputPorts.remove(p)
755 del self.outputPortsDescr[p.number]
756
757 else:
758 print "FAILED. Port is neither of class InputPort or OuputPort!"
759 return
760
761
762 self.network.deleteConnections(p.connections, 0)
763
764 p.relposx = p.computePortPosX()
765
766
767 if ports:
768 for i in range(p.number, len(ports)):
769 port = ports[i]
770 port.number = i
771 if port.visible:
772 port.updateIconPosition()
773
774
775 del p.data
776 del p.node
777 del p.network
778 del p.vEditor
779 del p
780
781 if resize:
782 self.autoResizeX()
783