8 from matplotlib
.backends
.backend_gtkagg
import FigureCanvasGTKAgg
as FigureCanvas
9 from matplotlib
.backends
.backend_gtkagg
import NavigationToolbar2GTKAgg
as NavigationToolbar
12 def report_error(parent
, msg
):
13 dlg
= gtk
.MessageDialog(parent
,
14 gtk
.DIALOG_MODAL | gtk
.DIALOG_DESTROY_WITH_PARENT
,
15 gtk
.MESSAGE_ERROR
, gtk
.BUTTONS_OK
, msg
)
16 dlg
.set_title(parent
.get_title())
22 <menubar name="MenuBar">
24 <menuitem action="Add file"/>
25 <menuitem action="Update files"/>
26 <menuitem action="New Math Signal..."/>
27 <menuitem action="Run netlister and simulate..."/>
28 <menuitem action="Quit"/>
34 self
._scale
_to
_str
= {'lin': 'Linear', 'logx': 'LogX', 'logy': 'LogY',\
37 self
._windows
_to
_figures
= {}
38 self
._current
_graph
= None
39 self
._current
_figure
= None
40 self
._TARGET
_TYPE
_SIGNAL
= 10354
41 self
._from
_signal
_list
= [("oscopy-signals", gtk
.TARGET_SAME_APP
,\
42 self
._TARGET
_TYPE
_SIGNAL
)]
43 self
._to
_figure
= [("oscopy-signals", gtk
.TARGET_SAME_APP
,\
44 self
._TARGET
_TYPE
_SIGNAL
)]
45 self
._ctxt
= oscopy
.Context()
46 self
._store
= gtk
.TreeStore(gobject
.TYPE_STRING
, gobject
.TYPE_PYOBJECT
)
47 self
._create
_widgets
()
48 self
._add
_file
('demo/irf540.dat')
49 #self._add_file('demo/ac.dat')
50 #self._add_file('demo/res.dat')
52 def _add_file(self
, filename
):
54 self
._ctxt
.read(filename
)
55 except NotImplementedError:
56 report_error(self
._mainwindow
,
57 'Could not find a reader for %s' % filename
)
59 it
= self
._store
.append(None, (filename
, None))
60 for name
, sig
in self
._ctxt
.readers
[filename
].signals
.iteritems():
61 self
._store
.append(it
, (name
, sig
))
63 def _action_add_file(self
, action
):
64 dlg
= gtk
.FileChooserDialog('Add file', parent
=self
._mainwindow
,
65 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_REJECT
,
66 gtk
.STOCK_OK
, gtk
.RESPONSE_ACCEPT
))
68 filename
= dlg
.get_filename()
70 if resp
== gtk
.RESPONSE_ACCEPT
:
71 self
._add
_file
(filename
)
73 def _action_update(self
, action
):
76 def _action_new_math(self
, action
):
77 dlg
= gtk
.Dialog('New math signal', parent
=self
._mainwindow
,
78 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_REJECT
,
79 gtk
.STOCK_OK
, gtk
.RESPONSE_ACCEPT
))
83 label
= gtk
.Label('Expression:')
84 hbox
.pack_start(label
)
86 hbox
.pack_start(entry
)
87 dlg
.vbox
.pack_start(hbox
)
91 if resp
== gtk
.RESPONSE_ACCEPT
:
92 expr
= entry
.get_text()
96 report_error(self
._mainwindow
,
97 'Could not find a reader for %s' % expr
)
99 it
= self
._store
.append(None, (expr
, None))
100 for name
, sig
in self
._ctxt
.readers
[expr
].signals
.iteritems():
101 self
._store
.append(it
, (name
, sig
))
106 def _action_quit(self
, action
):
109 def _create_menubar(self
):
111 # (name, stock-id, label, accelerator, tooltip, callback)
113 ('File', None, '_File'),
114 ('Add file', gtk
.STOCK_ADD
, '_Add file', None, None,
115 self
._action
_add
_file
),
116 ('Update files', gtk
.STOCK_REFRESH
, '_Update', None, None,
117 self
._action
_update
),
118 ("New Math Signal...", gtk
.STOCK_NEW
, '_New Math Signal', None,
119 None, self
._action
_new
_math
),
120 ("Run netlister and simulate...", gtk
.STOCK_MEDIA_FORWARD
,\
121 "_Run netlister and simulate...", None, None,\
122 self
._action
_netlist
_and
_simulate
),
123 ('Quit', gtk
.STOCK_QUIT
, '_Quit', None, None,
126 actiongroup
= gtk
.ActionGroup('App')
127 actiongroup
.add_actions(actions
)
129 uimanager
= gtk
.UIManager()
130 uimanager
.add_ui_from_string(self
.__ui
)
131 uimanager
.insert_action_group(actiongroup
, 0)
132 return uimanager
.get_accel_group(), uimanager
.get_widget('/MenuBar')
134 def _create_treeview(self
):
135 col
= gtk
.TreeViewColumn('Signal', gtk
.CellRendererText(), text
=0)
137 tv
.append_column(col
)
138 tv
.set_model(self
._store
)
139 tv
.connect('row-activated', self
._row
_activated
)
140 tv
.connect('button-press-event', self
._treeview
_button
_press
)
141 tv
.connect('drag_data_get', self
._drag
_data
_get
_cb
)
142 tv
.drag_source_set(gtk
.gdk
.BUTTON1_MASK
,\
143 self
._from
_signal
_list
,\
147 def _create_widgets(self
):
148 accel_group
, self
._menubar
= self
._create
_menubar
()
149 self
._treeview
= self
._create
_treeview
()
151 sw
= gtk
.ScrolledWindow()
152 sw
.set_policy(gtk
.POLICY_AUTOMATIC
, gtk
.POLICY_AUTOMATIC
)
153 sw
.add(self
._treeview
)
156 vbox
.pack_start(self
._menubar
, False)
159 w
= self
._mainwindow
= gtk
.Window(gtk
.WINDOW_TOPLEVEL
)
160 w
.set_title('Oscopy GUI')
162 w
.add_accel_group(accel_group
)
163 w
.connect('destroy', lambda *x
: self
._action
_quit
(None))
164 w
.set_default_size(400, 300)
168 def _create_figure_popup_menu(self
, figure
, graph
):
169 figmenu
= gui
.menus
.FigureMenu()
170 return figmenu
.create_menu(self
._store
, figure
, graph
)
172 def _create_treeview_popup_menu(self
, signals
):
175 item_none
= gtk
.MenuItem("No signal selected")
176 menu
.append(item_none
)
178 for name
, signal
in signals
.iteritems():
179 item_freeze
= gtk
.CheckMenuItem("Freeze %s" % name
)
180 item_freeze
.set_active(signal
.freeze
)
181 item_freeze
.connect('activate',\
182 self
._signal
_freeze
_menu
_item
_activated
,\
184 menu
.append(item_freeze
)
187 def _signal_freeze_menu_item_activated(self
, menuitem
, signal
):
188 signal
.freeze
= not signal
.freeze
189 # Modify also the signal in the treeview
190 # (italic font? gray font color? a freeze column?)
192 def _treeview_button_press(self
, widget
, event
):
193 if event
.button
== 3:
195 path
, tvc
, x
, y
= tv
.get_path_at_pos(int(event
.x
), int(event
.y
))
199 row
= self
._store
[path
]
200 signals
= {row
[0]: row
[1]}
201 menu
= self
._create
_treeview
_popup
_menu
(signals
)
203 menu
.popup(None, None, None, event
.button
, event
.time
)
205 def _button_press(self
, event
):
206 if event
.button
== 3:
207 menu
= self
._create
_figure
_popup
_menu
(event
.canvas
.figure
, event
.inaxes
)
209 menu
.popup(None, None, None, event
.button
, event
.guiEvent
.time
)
211 #TODO: _windows_to_figures consistency...
212 # think of a better way to map events to Figure objects
213 def _row_activated(self
, widget
, path
, col
):
217 row
= self
._store
[path
]
218 self
._ctxt
.create({row
[0]: row
[1]})
219 fig
= self
._ctxt
.figures
[len(self
._ctxt
.figures
) - 1]
223 self
._windows
_to
_figures
[w
] = fig
224 w
.set_title('Figure %d' % self
._figcount
)
227 canvas
= FigureCanvas(fig
)
228 canvas
.mpl_connect('button_press_event', self
._button
_press
)
229 canvas
.mpl_connect('axes_enter_event', self
._axes
_enter
)
230 canvas
.mpl_connect('axes_leave_event', self
._axes
_leave
)
231 canvas
.mpl_connect('figure_enter_event', self
._figure
_enter
)
232 canvas
.mpl_connect('figure_leave_event', self
._figure
_leave
)
233 w
.connect("drag_data_received", self
._drag
_data
_received
_cb
)
234 w
.drag_dest_set(gtk
.DEST_DEFAULT_MOTION |\
235 gtk
.DEST_DEFAULT_HIGHLIGHT |\
236 gtk
.DEST_DEFAULT_DROP
,
237 self
._to
_figure
, gtk
.gdk
.ACTION_COPY
)
238 vbox
.pack_start(canvas
)
239 toolbar
= NavigationToolbar(canvas
, w
)
240 vbox
.pack_start(toolbar
, False, False)
244 def _axes_enter(self
, event
):
245 self
._current
_graph
= event
.inaxes
247 def _axes_leave(self
, event
):
248 # Unused for better user interaction
249 # self._current_graph = None
252 def _figure_enter(self
, event
):
253 self
._current
_figure
= event
.canvas
.figure
255 def _figure_leave(self
, event
):
256 # self._current_figure = None
259 def update_from_usr1(self
):
262 def _action_netlist_and_simulate(self
, action
):
263 dialog
= gtk
.Dialog("Run netlister and simulate",\
264 buttons
=(gtk
.STOCK_CANCEL
, gtk
.RESPONSE_REJECT
,\
265 gtk
.STOCK_OK
, gtk
.RESPONSE_ACCEPT
))
266 vbox_netl
= gtk
.VBox()
267 ckbutton_netl
= gtk
.CheckButton("Run netlister")
268 ckbutton_netl
.set_active(True)
269 vbox_netl
.pack_start(ckbutton_netl
)
270 entry_netl
= gtk
.Entry()
271 entry_netl
.set_text("gnetlist -s -o demo.cir -g spice-sdb demo.sch")
272 vbox_netl
.pack_start(entry_netl
)
273 dialog
.vbox
.pack_start(vbox_netl
)
274 vbox_netl
= gtk
.VBox()
276 vbox_sim
= gtk
.VBox()
277 ckbutton_sim
= gtk
.CheckButton("Run simulator")
278 ckbutton_sim
.set_active(True)
279 vbox_sim
.pack_start(ckbutton_sim
)
280 entry_sim
= gtk
.Entry()
281 entry_sim
.set_text("gnucap -b demo.cir")
282 vbox_sim
.pack_start(entry_sim
)
283 dialog
.vbox
.pack_start(vbox_sim
)
284 ckbutton_upd
= gtk
.CheckButton("Update readers")
285 ckbutton_upd
.set_active(True)
286 dialog
.vbox
.pack_start(ckbutton_upd
)
289 if resp
== gtk
.RESPONSE_ACCEPT
:
290 if ckbutton_netl
.get_active():
291 res
= commands
.getstatusoutput(entry_netl
.get_text())
293 report_error(self
._mainwindow
, res
[1])
295 if ckbutton_sim
.get_active():
296 res
= commands
.getstatusoutput(entry_sim
.get_text())
298 report_error(self
._mainwindow
, res
[1])
300 if ckbutton_upd
.get_active():
304 def _drag_data_get_cb(self
, widget
, drag_context
, selection
, target_type
,\
306 if target_type
== self
._TARGET
_TYPE
_SIGNAL
:
308 (path
, col
) = tv
.get_cursor()
309 row
= self
._store
[path
]
311 selection
.set(selection
.target
, 8, row
[0])
313 def _drag_data_received_cb(self
, widget
, drag_context
, x
, y
, selection
,\
315 if target_type
== self
._TARGET
_TYPE
_SIGNAL
:
316 if self
._current
_graph
is not None:
317 signals
= {selection
.data
: self
._ctxt
.signals
[selection
.data
]}
318 self
._current
_graph
.insert(signals
)
319 if self
._current
_figure
.canvas
is not None:
320 self
._current
_figure
.canvas
.draw()
322 def usr1_handler(signum
, frame
):
323 app
.update_from_usr1()
325 if __name__
== '__main__':
327 main_loop
= gobject
.MainLoop()
328 signal
.signal(signal
.SIGUSR1
, usr1_handler
)