""" This module makes it possible to view streamlines, streamtubes, and stream ribbons for any type of vector data. Any number of point sources can be added and deleted. A fairly powerful UI is provided. This module should work with any dataset. This code is distributed under the conditions of the BSD license. See LICENSE.txt for details. Copyright (c) 2001-2002, Prabhu Ramachandran. """ __author__ = "Prabhu Ramachandran " __version__ = "$Revision: 1.8 $" __date__ = "$Date: 2005/08/02 18:30:13 $" import Base.Objects, Common import Tkinter, tkColorChooser, tkMessageBox, tkFileDialog, math import vtk import vtkPipeline.vtkMethodParser import vtkPipeline.ConfigVtkObj tk_fopen = tkFileDialog.askopenfilename tk_fsave = tkFileDialog.asksaveasfilename debug = Common.debug class SeedManager: """ Abstracts out a seed manager. This class is capable of handling a vtkPointSource as well as a vtkDiskSource. The DiskSource is used for 2D data. The DiskSource is appropriately oriented so that it is on the right plane.""" def __init__(self): """ Create the SeedManager. Call initialize to setup the seed.""" debug ("In SeedManager::__init__ ()") self.dim = 0 self.last_cen = [0.0]*3 self.seed = None self.transform = None def initialize (self, valid_coord): """ Initializes the seed given an array of valid co-ordinate directions. [x-axis, y-axis, z_axis] is the format. For instance if x-axis == 0 then the data is along the YZ plane. This method is responsible for actually creating the seed. """ debug ("In SeedManager::initialize ()") assert len (valid_coord) == 3 self.dim = reduce (lambda x, y: x+y, valid_coord) if self.dim == 3: self.seed = vtk.vtkPointSource () else: self.seed = vtk.vtkDiskSource () self.seed.SetRadialResolution (1) self.seed.SetInnerRadius (0.0) self.transform = vtk.vtkTransformFilter () self.transform.SetTransform (vtk.vtkTransform ()) self.transform.SetInput (self.seed.GetOutput ()) self.orient_2d (valid_coord) def orient_2d (self, valid_coord): """ Orients the vtkDiskSource for the given co-ordinates.""" debug ("In SeedManager::orient_2d ()") assert len (valid_coord) == 3 transform = self.transform.GetTransform () if valid_coord[0] == 0: # Data plane is along YZ plane transform.RotateY(90) elif valid_coord[1] == 0: # Data plane is along XZ plane transform.RotateX(90) elif valid_coord[2] == 0: # Data plane is along XY plane pass # default orientation! def set_n_points (self, n): """ Set the number of points created by the seed.""" debug ("In SeedManager::set_n_points ()") if self.dim == 3: self.seed.SetNumberOfPoints (n) else: self.seed.SetCircumferentialResolution (n) def get_n_points (self): """ Get the number of seed points.""" debug ("In SeedManager::get_n_points ()") if self.dim == 3: return self.seed.GetNumberOfPoints () else: return self.seed.GetCircumferentialResolution () def set_radius (self, rad): """ Set the seed radius. """ debug ("In SeedManager::set_radius ()") if self.dim == 3: self.seed.SetRadius (rad) else: self.seed.SetOuterRadius (rad) def set_center (self, cen): """ Set the seed's center given an array of co-ordinates.""" debug ("In SeedManager::set_center ()") if self.dim == 3: self.seed.SetCenter (*cen) else: diff = map (lambda x, y: x-y, cen, self.last_cen) tr = self.transform.GetTransform () tr.Translate (*diff) self.last_cen = cen[:] def GetOutput (self): """ Get the VTK Output of the appropriate seed.""" debug ("In SeedManager::GetOutput ()") if self.dim == 3: return self.seed.GetOutput () else: return self.transform.GetOutput () class PointStreamer (Base.Objects.Module): """Provides the basic class for streamline support. """ def __init__ (self, mod_m): debug ("In PointStreamer::__init__ ()") Common.state.busy () Base.Objects.Module.__init__ (self, mod_m) self.sphere_src = vtk.vtkSphereSource () self.sphere_map = vtk.vtkPolyDataMapper () self.sphere_act = vtk.vtkActor () self.seed = SeedManager () self.radius = 1.0 self.cen = [0.0, 0.0, 0.0] self.n_pnt = 50 self.strmln_mode = 0 self.color_mode = 1 # 1 is vector, 0 is scalar, -1 is no color self.integration_mode = 2 # 2 is Runge-Kutta 2 and 4 is RK 4. self.strmln = vtk.vtkStreamLine () self.ribbonf = vtk.vtkRibbonFilter () self.tubef = vtk.vtkTubeFilter () self.mapper = self.stream_map = vtk.vtkPolyDataMapper () self.actor = self.stream_act = vtk.vtkActor () self.done_init = 0 Common.state.idle () def __del__ (self): debug ("In PointStreamer::__del__ ()") Common.state.busy () self.renwin.remove_actors ((self.sphere_act, self.stream_act)) self.renwin.Render () Common.state.idle () def get_defaults (self): debug ("In PointStreamer::get_defaults ()") self.resoln_var = [] self.def_dim = [] self.dim = [] self.data_dimn = 0 self.coord = [0,0,0] dim1 = self.mod_m.get_data_source ().GetOutput ().GetBounds () max_len = -1.0 for i in range (0,3): self.dim.append ((dim1[2*i], dim1[2*i+1])) val = dim1[2*i] + dim1[2*i+1] self.def_dim.append (val*0.5) mag = abs (dim1[2*i+1] - dim1[2*i]) if mag > max_len: max_len = mag var = Tkinter.DoubleVar () var.set (mag*0.02) self.resoln_var.append (var) if dim1[2*i] != dim1[2*i+1]: self.coord[i] = 1 self.data_dimn = self.data_dimn + 1 # now that we know enough about the data - initialize the seed. self.seed.initialize (self.coord) self.cen = self.def_dim self.radius = max_len*0.1 self.sphere_src.SetCenter (*self.cen) self.sphere_src.SetRadius(self.radius) # setting some sane defaults self.ribbonf.SetWidth (self.radius*0.075) self.tubef.SetRadius (self.radius*0.075) def initialize (self, master=None): debug ("In PointStreamer::initialize ()") self.get_defaults () self.sphere_src.SetThetaResolution (10) self.sphere_src.SetPhiResolution (10) self.sphere_map.SetInput (self.sphere_src.GetOutput ()) self.sphere_act.SetMapper (self.sphere_map) self.sphere_act.GetProperty ().SetColor (0.0, 0.0, 0.5) self.sphere_act.GetProperty ().SetOpacity (0.5) self.max_v = self.mod_m.get_vector_data_range ()[1] self.seed.set_n_points (self.n_pnt) self.strmln.SetSource (self.seed.GetOutput ()) self.strmln.SpeedScalarsOn () self.stream_map.SetInput (self.strmln.GetOutput ()) self.stream_map.SetScalarRange (0, self.max_v) self.stream_map.SetLookupTable (self.mod_m.get_vector_lut ()) self.stream_act.SetMapper (self.stream_map) self.stream_act.VisibilityOff () self.renwin.add_actors ((self.sphere_act, self.stream_act)) self.configure (master) def SetInput (self, source): debug ("In PointStreamer::SetInput ()") self.strmln.SetInput (source) self.do_color_mode () def make_ball_gui (self, master): debug ("In PointStreamer::make_ball_gui ()") frame = Tkinter.Frame (master, relief="ridge", bd=2) frame.pack (side='top') self.coord_var = Tkinter.StringVar () self.coord_var.set (self.cen) lab = Tkinter.Label (frame, text="Center of Source:") lab.grid (row=0, column=0, columnspan=1, sticky='w') entr = Tkinter.Entry (frame, width=20, relief='sunken', textvariable=self.coord_var) entr.grid (row=0, column=1, columnspan=2, sticky='w') def_name = ["Move along X-axis", "Move along Y-axis ", "Move along Z-axis"] res_name = ["X resolution:", "Y resolution:", "Z resolution:"] self.slider = [] rw = 1 for i in range (0,3): if self.coord[i] == 1: sl = Tkinter.Scale (frame, label=def_name[i], from_=self.dim[i][0], to=self.dim[i][1], length="8c", orient='horizontal', resolution=self.resoln_var[i].get ()) sl.set (self.cen[i]) sl.grid (row=rw, column=0, columnspan=3, sticky='ew') rw = rw + 1 sl.bind ("", self.change_locator) lab = Tkinter.Label (frame, text=res_name[i]) lab.grid (row=rw, column=0, sticky='w') entr = Tkinter.Entry (frame, width=5, relief='sunken', textvariable=self.resoln_var[i]) entr.grid (row=rw, column=1, sticky='w') entr.bind ("", self.set_resolution) rw = rw+1 self.slider.append (sl) self.radius_var = Tkinter.DoubleVar () self.radius_var.set (self.radius) self.n_pnt_var = Tkinter.DoubleVar () self.n_pnt_var.set (self.n_pnt) lab = Tkinter.Label (frame, text="Radius of source:") lab.grid (row=rw, column=0, sticky='w') entr = Tkinter.Entry (frame, width=5, relief='sunken', textvariable=self.radius_var) entr.grid (row=rw, column=1, sticky='w') entr.bind ("", self.setup_ball) rw = rw + 1 lab = Tkinter.Label (frame, text="Number of seed points:") lab.grid (row=rw, column=0, sticky='w') entr = Tkinter.Entry (frame, width=5, relief='sunken', textvariable=self.n_pnt_var) entr.grid (row=rw, column=1, sticky='w') rw = rw + 1 entr.bind ("", self.setup_ball) self.ball_var = Tkinter.IntVar () self.ball_var.set (1) cb = Tkinter.Checkbutton (frame, text="Show PointSource", variable=self.ball_var, onvalue=1, offvalue=0, command=self.show_ball) cb.grid (row=rw, column=0, columnspan=2, sticky='w') def make_color_mode_gui (self, master): debug ("In PointStreamer::make_color_mode_gui ()") f = Tkinter.Frame (master, bd=2) f.pack (side='top') frame = Tkinter.Frame (f, relief="ridge") frame.grid (row=0, column=0, sticky='w') self.color_var = Tkinter.IntVar () self.color_var.set (self.color_mode) rb = Tkinter.Radiobutton (frame, text="No Coloring", variable=self.color_var, value=-1, command=self.set_color_mode_gui) rb.grid (row=0, column=0, sticky='w') rb = Tkinter.Radiobutton (frame, text="Scalar Coloring", variable=self.color_var, value=0, command=self.set_color_mode_gui) rb.grid (row=1, column=0, sticky='w') rb = Tkinter.Radiobutton (frame, text="Vector Coloring", variable=self.color_var, value=1, command=self.set_color_mode_gui) rb.grid (row=2, column=0, sticky='w') but = Tkinter.Button (frame, text="Streamline Color", command=self.set_stream_color) but.grid (row=3, column=0, sticky='ew') frame = Tkinter.Frame (f, relief="ridge") frame.grid (row=0, column=1, sticky='w') self.integration_var = Tkinter.IntVar () self.integration_var.set (self.integration_mode) lab = Tkinter.Label (frame, text="Integration Type") lab.grid (row=0, column=0, columnspan=1, sticky='ew') rb = Tkinter.Radiobutton (frame, text="Runge-Kutta 2nd Order", variable=self.integration_var, value=2, command=self.set_integration_gui) rb.grid (row=1, column=0, sticky='w') rb = Tkinter.Radiobutton (frame, text="Runge-Kutta 4th Order", variable=self.integration_var, value=4, command=self.set_integration_gui) rb.grid (row=2, column=0, sticky='w') def make_other_gui (self, master): debug ("In PointStreamer::make_other_gui ()") frame = Tkinter.Frame (master, relief="ridge", bd=2) frame.pack (side='top') lab = Tkinter.Label (frame, text="Integration parameters:") lab.grid (row=0, column=0, sticky='w', pady=5) but = Tkinter.Button (frame, text="Configure", command=self.setup_strmln) but.grid (row=0, column=1, sticky='w') self.strmln_var = Tkinter.IntVar () self.strmln_var.set (self.strmln_mode) rb = Tkinter.Radiobutton (frame, text="Show Streamlines", variable=self.strmln_var, value=0, command=self.set_streamline_mode) rb.grid (row=1, column=0, sticky='w') rb = Tkinter.Radiobutton (frame, text="Show Streamribbons", variable=self.strmln_var, value=1, command=self.set_streamline_mode) rb.grid (row=2, column=0, sticky='w') but = Tkinter.Button (frame, text="Configure", command=self.setup_ribbonf) but.grid (row=2, column=1, sticky='w') rb = Tkinter.Radiobutton (frame, text="Show Streamtubes", variable=self.strmln_var, value=2, command=self.set_streamline_mode) rb.grid (row=3, column=0, sticky='w') but = Tkinter.Button (frame, text="Configure", command=self.setup_tubef) but.grid (row=3, column=1, sticky='w') but = Tkinter.Button (frame, text="Update changes", command=self.update, underline=0) but.grid (row=4, column=0, sticky='w') self.root.bind ("", self.update) but = Tkinter.Button (frame, text="Close", command=self.quit, underline=0) but.grid (row=4, column=1, sticky='w') self.root.bind ("", self.quit) def _lift (self): """Lifts an already created configuration window to the top.""" debug ("In PointStreamer::_lift ()") self.root.deiconify () self.root.lift () self.root.focus_set () def configure (self, master=None): debug ("In PointStreamer::configure ()") if (self.root and self.root.winfo_exists ()): return self._lift () self.n_pnt = self.seed.get_n_points () self.radius = self.sphere_src.GetRadius () self.cen = list (self.sphere_src.GetCenter ()) self.root = Tkinter.Toplevel (master) self.root.transient (master) self.root.title ("Configure the streamlines.") self.make_ball_gui (self.root) self.make_color_mode_gui (self.root) self.make_actor_gui (scalar=0, color=0, compact=1) self.make_other_gui (self.root) self.sphere_act.VisibilityOn () self.renwin.Render () def setup_ball (self, event=None): debug ("In PointStreamer::setup_ball ()") Common.state.busy () val = self.n_pnt_var.get () self.n_pnt = val self.seed.set_n_points (self.n_pnt) val = self.radius_var.get () self.radius = val #self.seed.set_radius (self.radius) self.sphere_src.SetRadius(self.radius) self.renwin.Render () Common.state.idle () def set_streamline_mode (self, event=None): debug ("In PointStreamer::set_streamline_mode ()") Common.state.busy () self.strmln_mode = self.strmln_var.get () self.setup_stream_pipeline () self.renwin.Render () Common.state.idle () def setup_stream_pipeline (self): debug ("In PointStreamer::setup_stream_pipeline ()") val = self.strmln_mode if val == 0: self.stream_map.SetInput (self.strmln.GetOutput ()) elif val == 1: self.ribbonf.SetInput (self.strmln.GetOutput ()) self.stream_map.SetInput (self.ribbonf.GetOutput ()) elif val == 2: self.tubef.SetInput (self.strmln.GetOutput ()) self.stream_map.SetInput (self.tubef.GetOutput ()) def setup_ribbonf (self, event=None): debug ("In PointStreamer::setup_ribbonf ()") conf = vtkPipeline.ConfigVtkObj.ConfigVtkObj (self.renwin) conf.configure (None, self.ribbonf) def setup_tubef (self, event=None): debug ("In PointStreamer::setup_tubef ()") conf = vtkPipeline.ConfigVtkObj.ConfigVtkObj (self.renwin) conf.configure (None, self.tubef) def setup_strmln (self, event=None): debug ("In PointStreamer::setup_strmln ()") conf = vtkPipeline.ConfigVtkObj.ConfigVtkObj (self.renwin) conf.configure (None, self.strmln) def change_locator (self, event=None): debug ("In PointStreamer::change_locator ()") val = [] for i in range (0, 3): if self.coord[i] == 1: val.append (self.slider[i].get ()) else: val.append (self.cen[i]) self.sphere_src.SetCenter (*val) self.cen = val self.coord_var.set (val) self.renwin.Render () def show_ball (self, event=None): debug ("In PointStreamer::show_ball ()") Common.state.busy () val = self.ball_var.get () if val == 1: self.sphere_act.VisibilityOn () elif val == 0: self.sphere_act.VisibilityOff () self.renwin.Render () Common.state.idle () def set_resolution (self, event=None): debug ("In PointStreamer::set_resolution ()") for i in range (0, 3): if self.coord[i] == 1: val = self.resoln_var[i].get () self.slider[i].config (resolution=val) def set_color_mode_gui (self, event=None): "This sets up the data to setup the actual coloring mode." debug ("In PointStreamer::set_color_mode_gui ()") Common.state.busy () self.color_mode = self.color_var.get () self.do_color_mode () self.renwin.Render () Common.state.idle () def do_color_mode (self): debug ("In PointStreamer::do_color_mode ()") if self.color_mode == 1: # Vector Coloring dr = self.mod_m.get_vector_data_range () self.max_v = dr[1] self.stream_map.ScalarVisibilityOn () self.strmln.SpeedScalarsOn () self.stream_map.SetScalarRange (dr) self.stream_map.SetLookupTable (self.mod_m.get_vector_lut ()) elif self.color_mode == 0: # Scalar Coloring self.stream_map.ScalarVisibilityOn () self.strmln.SpeedScalarsOff () dr = self.mod_m.get_scalar_data_range () self.stream_map.SetScalarRange (dr) self.stream_map.SetLookupTable (self.mod_m.get_scalar_lut ()) elif self.color_mode == -1: # No colouring self.stream_map.ScalarVisibilityOff () self.strmln.SpeedScalarsOff () def set_stream_color (self, event=None): debug ("In PointStreamer::set_stream_color ()") clr = self.stream_act.GetProperty ().GetColor () init_clr = "#%02x%02x%02x"%(clr[0]*255, clr[1]*255, clr[2]*255) color = tkColorChooser.askcolor (title="Change axes color", initialcolor=init_clr) if color[1] is not None: Common.state.busy () clr = Common.tk_2_vtk_color (color[0]) self.stream_act.GetProperty ().SetColor (*clr) self.renwin.Render () Common.state.idle () if self.color_mode != -1: msg = "Warning: This setting will have effect only if "\ "the coloring mode is set to 'No Coloring'." Common.print_err (msg) def set_integration_gui (self, event=None): debug ("In PointStreamer::set_integration_gui ()") val = self.integration_var.get() self.integration_mode = val self.update_integration_mode () def update_integration_mode (self): debug ("In PointStreamer::update_integration_mode ()") Common.state.busy () val = self.integration_mode try: if val == 2: self.strmln.SetIntegrator (vtk.vtkRungeKutta2 ()) elif val == 4: self.strmln.SetIntegrator (vtk.vtkRungeKutta4 ()) except AttributeError, err: msg = "Sorry unable to change the integration type. "\ "Try upgrading your VTK installation to a more "\ "recent version." Common.print_err (msg) self.renwin.Render () Common.state.idle () def update (self, event=None): debug ("In PointStreamer::update ()") Common.state.busy () self.seed.set_center (self.cen) self.seed.set_radius (self.radius) self.seed.set_n_points (self.n_pnt) if not self.done_init: self.strmln.SetInput (self.mod_m.GetOutput ()) self.done_init = 1 self.stream_act.VisibilityOn () self.strmln.Update () self.renwin.Render () Common.state.idle () def save_config (self, file): debug ("In PointStreamer::save_config ()") file.write ("%d, %d, %d\n"%(self.n_pnt, self.strmln_mode, self.integration_mode)) # For backward compatibility - the dummy is actually unused. dummy_seed = vtk.vtkPointSource () p = vtkPipeline.vtkMethodParser.VtkPickler () for i in (self.sphere_src, self.sphere_map, self.sphere_act, self.sphere_act.GetProperty (), dummy_seed, self.strmln, self.ribbonf, self.tubef, self.stream_map, self.stream_act, self.stream_act.GetProperty ()): p.dump (i, file) def load_config (self, file): debug ("In PointStreamer::load_config ()") self.setup_pipeline () val = file.readline () try: self.n_pnt, self.strmln_mode, self.integration_mode = eval (val) except ValueError: # old format self.n_pnt, self.strmln_mode = eval (val) # For backward compatibility - the dummy is actually unused. dummy_seed = vtk.vtkPointSource () p = vtkPipeline.vtkMethodParser.VtkPickler () for i in (self.sphere_src, self.sphere_map, self.sphere_act, self.sphere_act.GetProperty (), dummy_seed, self.strmln, self.ribbonf, self.tubef, self.stream_map, self.stream_act, self.stream_act.GetProperty ()): p.load (i, file) self.setup_stream_pipeline () self.radius = self.sphere_src.GetRadius () self.cen = list (self.sphere_src.GetCenter ()) self.color_mode = self.strmln.GetSpeedScalars () if self.stream_map.GetScalarVisibility () == 0: self.color_mode = -1 self.do_color_mode () self.update () self.update_integration_mode () def setup_pipeline (self): debug ("In PointStreamer::setup_pipeline ()") self.get_defaults () self.sphere_map.SetInput (self.sphere_src.GetOutput ()) self.sphere_act.SetMapper (self.sphere_map) self.max_v = self.mod_m.get_vector_data_range ()[1] self.strmln.SetSource (self.seed.GetOutput ()) self.stream_map.SetInput (self.strmln.GetOutput ()) self.stream_map.SetScalarRange (0, self.max_v) self.stream_map.SetLookupTable (self.mod_m.get_vector_lut ()) self.stream_act.SetMapper (self.stream_map) self.stream_act.VisibilityOff () self.renwin.add_actors ((self.sphere_act, self.stream_act)) def quit (self, event=None): debug ("In PointStreamer::quit ()") self.sphere_act.VisibilityOff () self.renwin.Render () self.root.destroy () self.root = None def get_actors (self): debug ("In PointStreamer::get_actors ()") return [self.sphere_act, self.stream_act] class Streamlines (Base.Objects.Module): """ This module makes it possible to view streamlines, streamtubes, and stream ribbons for any type of vector data. Any number of point sources can be added and deleted. A fairly powerful UI is provided. This module should work with any dataset. """ def __init__ (self, mod_m): debug ("In Streamlines::__init__ ()") Common.state.busy () Base.Objects.Module.__init__ (self, mod_m) self.stream_ctl = {} self.pipe_objs = [] self.n_streams = 0 Common.state.idle () def __del__ (self): debug ("In Streamlines::__del__ ()") Common.state.busy () for key in self.stream_ctl.keys (): del self.stream_ctl[key] del self.pipe_objs self.renwin.Render () Common.state.idle () def SetInput (self, source): debug ("In Streamlines::SetInput ()") Common.state.busy () for obj in self.stream_ctl.values (): obj.SetInput (source) Common.state.idle () def add_streamline (self, key): debug ("In Streamlines::add_streamline ()") ctl = PointStreamer (self.mod_m) ctl.initialize (self.root.master) self.stream_ctl[key] = ctl self.pipe_objs.extend (ctl.get_actors ()) def config_streamline (self, key): debug ("In Streamlines::config_streamline ()") self.stream_ctl[key].configure (self.root.master) def delete_streamline (self, key): debug ("In Streamlines::delete_streamline ()") del self.stream_ctl[key] def save_config (self, file): debug ("In Streamlines::save_config ()") n = len (self.stream_ctl) file.write ("%d\n"%n) for key in self.stream_ctl.keys (): self.stream_ctl[key].save_config (file) file.flush () def load_config (self, file): debug ("In Streamlines::load_config ()") start_val = self.n_streams n = eval (file.readline ()) for i in range (0, n): ctl = PointStreamer (self.mod_m) ctl.load_config (file) key = "PointSource%d"%(start_val+i) self.stream_ctl[key] = ctl self.pipe_objs.extend (ctl.get_actors ()) self.n_streams = self.n_streams + 1 def make_custom_gui (self): debug ("In Streamlines::make_custom_gui ()") self.make_pipeline_gui () self.make_main_gui () self.make_close_button () def make_main_gui (self): debug ("In Streamlines::make_main_gui ()") frame = Tkinter.Frame (self.root, relief='ridge', bd=2) frame.pack (side='top') scr = Tkinter.Scrollbar (frame, orient='vertical') self.str_lst = Tkinter.Listbox (frame, yscrollcommand=scr.set, selectmode='single') scr.config (command=self.str_lst.yview) self.str_lst.grid (row=0, column=0, sticky='ewns') scr.grid (row=0, column=1, sticky='ns') self.str_lst.bind ("", self.config_streamline_gui) for key in self.stream_ctl.keys (): self.str_lst.insert ('end', key) but1 = Tkinter.Button (frame, text="Add streamline source", command=self.add_streamline_gui) but2 = Tkinter.Button (frame, text="Delete streamline source", command=self.delete_streamline_gui) but1.grid (row=1, column=0, columnspan=2, sticky='ew') but2.grid (row=2, column=0, columnspan=2, sticky='ew') but2 = Tkinter.Button (frame, text="Save streamlines", command=self.save) but2.grid (row=3, column=0, columnspan=2, sticky='ew') but2 = Tkinter.Button (frame, text="Load streamlines", command=self.load) but2.grid (row=4, column=0, columnspan=2, sticky='ew') def add_streamline_gui (self): debug ("In Streamlines::add_streamline_gui ()") Common.state.busy () str = "PointSource%d"%self.n_streams self.str_lst.insert ('end', str) self.n_streams = self.n_streams + 1 self.add_streamline (str) Common.state.idle () def delete_streamline_gui (self): debug ("In Streamlines::delete_streamline_gui ()") Common.state.busy () str = self.str_lst.get ('active') msg = "You are about to delete the streamlines due to the "\ "%s. Are you sure you want to do this?" %(str) ans = tkMessageBox.askyesno ("Delete Streamline?", msg) if ans == 1: self.str_lst.delete ('active') self.delete_streamline (str) Common.state.idle () def config_streamline_gui (self, event=None): debug ("In Streamlines::config_streamline_gui ()") str = self.str_lst.get ('active') self.config_streamline (str) def save (self): debug ("In Streamlines::save ()") file_name = tk_fsave (title="Save streamlines", initialdir=Common.config.initial_dir, defaultextension=".str", filetypes=[("Streamline files", "*.str"), ("All files", "*")]) if file_name: Common.state.busy () file = open (file_name, "w") self.save_config (file) file.close () Common.state.idle () def load (self): debug ("In Streamlines::load ()") file_name = tk_fopen (title="Load streamlines", initialdir=Common.config.initial_dir, filetypes=[("Streamline files", "*.str"), ("All files", "*")]) if file_name: Common.state.busy () file = open (file_name, "r") n_orig = len (self.stream_ctl) self.load_config (file) n = len (self.stream_ctl) - n_orig for i in range (0, n): str = "PointSource%d"%self.n_streams self.str_lst.insert ('end', str) self.n_streams = self.n_streams + 1 file.close () Common.state.idle ()