"""

This module defines the basic classes used by MayaVi.  The debug
function enables a rudimentary debug support.  Using this one can in
theory fix bugs faster.

This code is distributed under the conditions of the GPL (GNU General
Public License).  Look at the file LICENSE included with the
distribution for details.

Copyright (C) 2001, Prabhu Ramachandran.
"""

__author__ = "Prabhu Ramachandran <prabhu_r@users.sf.net>"
__version__ = "$Revision: 1.6 $"
__date__ = "$Date: 2001/11/09 07:08:20 $"
__credits__ = """Many thanks to Jose Paulo <moitinho@civil.ist.utl.pt> 
for adding tensor data support."""


import Tkinter, vtkpython, math, tkColorChooser
import Common, vtkPipeline.vtkPipeline 
import vtkPipeline.vtkMethodParser

debug = Common.debug


class ParseException (Exception):
    """ An exception that is raised when there is a problem with
    parsing a file."""
    pass


class ModuleException (Exception):
    """ An exception that is raised when there is a problem running a
    particular visualization module."""
    pass


class BaseObject:

    """ The basic object type."""

    def save_config (self, file): 
        """Save the objects configuration to file."""
        debug ("In BaseObject::save_config ()")
        debug ("BaseObject::save_config not implemented.")

    def load_config (self, file): 
        """Load the saved objects configuration from a file."""
        debug ("In BaseObject::load_config ()")
        debug ("BaseObject::load_config not implemented.")

    def config_changed (self): 
        """The configuration file has changed - take notice."""
        debug ("In BaseObject::config_changed ()")
        debug ("BaseObject::config_changed not implemented.")
        

class VizObject (BaseObject):

    """ The basic object type for visualization components."""

    def __init__ (self):
        debug ("In VizObject::__init__ ()")
        self.pipe_objs = None
        self.renwin = None
        self.root = None

    def _auto_sweep_init (self):
        """ Initialize variables for the autosweep GUI controls."""
        debug ("In VizObject::_auto_sweep_init ()")
	self.sweep_var = Tkinter.IntVar ()
	self.sweep_var.set (0)
	self.sweep_step = Tkinter.IntVar ()
	self.sweep_step.set (10)
	self.sweep_delay = Tkinter.DoubleVar ()
	self.sweep_delay.set (1.0)

    def configure (self, master=None): 
        "Create the GUI configuration controls for this object."
        debug ("In VizObject::configure ()")
        if (self.root and self.root.winfo_exists ()):
            return
        self.root = Tkinter.Toplevel (master)
        self.root.transient (self.root.master)
        self.root.title ("Configure %s module"%self.__class__.__name__)
        self.root.protocol ("WM_DELETE_WINDOW", self.close_gui)

        self.make_custom_gui ()

    def make_custom_gui (self):        
        """ This function is called by configure().  Use this to
        customize your own GUI."""
        debug ("In VizObject::configure ()")
        self.make_pipeline_gui ()
        self.make_main_gui ()
        #self.make_auto_sweep_gui ()
        self.make_close_button ()

    def make_pipeline_gui (self):
        """ Create the GUI for the segmented pipeline browser."""
        debug ("In VizObject::make_pipeline_gui ()")
        self.pipe_frame = Tkinter.Frame (self.root, relief='ridge', bd=2)
        self.pipe_frame.pack (side='top', fill='both', expand=1)
        self.pipe_var = Tkinter.IntVar ()
        self.pipe_var.set (0)
        cb = Tkinter.Checkbutton (self.pipe_frame, text="Show Pipeline",
                                  variable=self.pipe_var, onvalue=1,
                                  offvalue=0, command=self.show_pipeline)
        cb.pack(side='top', fill='both', expand=1)

    def make_auto_sweep_gui (self):
        """ Create the GUI controls for the auto-sweep animation."""
        debug ("In VizObject::make_auto_sweep_gui ()")
	frame = Tkinter.Frame (self.root, relief='ridge', bd=2)
	frame.pack (side='top', fill='both', expand=1)

	cb = Tkinter.Checkbutton (frame, text='Auto Sweep',
                                  variable=self.sweep_var,
                                  command=self.do_sweep)
	cb.grid (row=0, column=0, columnspan=2, sticky='w')

	lab = Tkinter.Label (frame, text="Auto Sweep Step:")
	lab.grid (row=1, column=0, sticky='w')
	entry = Tkinter.Entry (frame, width=5, relief='sunken', 
                               textvariable=self.sweep_step)
	entry.grid (row=1, column=1, sticky='we')
	entry.bind ("<Return>", self.sweep_step_validate)

	lab = Tkinter.Label (frame, text="Auto Sweep Delay:")
	lab.grid (row=2, column=0, sticky='w')
	entry = Tkinter.Entry (frame, width=5, relief='sunken', 
                               textvariable=self.sweep_delay)
	entry.grid (row=2, column=1, sticky='we')
	entry.bind ("<Return>", self.sweep_delay_validate)
        
    def make_close_button (self):
        """ Create a close button for the GUI control."""
        debug ("In VizObject::make_close_button ()")
        but = Tkinter.Button (self.root, text="Close", underline=0,
                               command=self.close_gui)
        but.pack (side='bottom', fill='both', expand=1)
        self.root.bind ("<Alt-c>", self.close_gui)

    def show_pipeline (self, event=None):
        """ Show the segmented pipeline browser when required."""
        debug ("In VizObject::show_pipeline ()")
        val = self.pipe_var.get ()
        if val:
            self.p_frame = Tkinter.Frame (self.pipe_frame)
            self.p_frame.pack (side='top', fill='both', expand=1)
            cl_obj = vtkPipeline.vtkPipeline.vtkPipelineSegmentBrowser
            pipe = cl_obj (self.p_frame, self.pipe_objs, self.renwin)
            pipe.pack (side='top', fill='both', expand=1)
        else:
            if self.p_frame:
                self.p_frame.destroy ()        

    def do_sweep (self, event=None):
        """Called when the user requests auto-sweeping."""
        debug ("In VizObject::do_sweep ()")
        debug ("VizObject::do_sweep () is not implemented.")

    def sweep_step_validate(self, event=None):
        """Validate the sweep step set by the user. """
        debug ("In VizObject::sweep_step_validate ()")
        #if self.sweep_step.get() < 1 :
        #self.sweep_step.set(1)
        pass

    def sweep_delay_validate(self, event=None):
        """Validate the sweep delay set by the user. """
        debug ("In VizObject::sweep_delay_validate ()")
	if self.sweep_delay.get() <= 0:
	   self.sweep_delay.set(1.0)

    def close_gui (self, event=None):
        """Called when the 'close' button is clicked."""
        debug ("In VizObject::close_gui ()")
        self.root.destroy ()
        self.root = None
        try:
            self.sweep_var.set (0)
        except AttributeError:
            pass
            

class Source (VizObject):
    
    """Basic source object.  The source is similar in concept to a VTK
    source object.  It is basically a source of data."""

    def __init__ (self):
        VizObject.__init__ (self)
        
    def GetOutput (self): 
        """Output of the vtkSource object wrapped."""
        debug ("In Source::GetOutput ()")
        debug ("Source::GetOutput not implemented.")
    

class DataSource (Source):

    """ The basic class from which all are Data source classes are
    derived. """

    def __init__ (self): 
        debug ("In DataSource::__init__ ()")
        Source.__init__ (self)
        self.file_name = ""
        self.scalar_data_name = ""
        self.vector_data_name = ""        
        self.tensor_data_name = ""
        self.ref_lst = []
        self.grid_type = ""
        self.root = None
    
    def initialize (self, file_name): 
        """Initialize the object given a valid file name."""
        debug ("In DataSource::initialize ()")
        debug ("DataSource::initialize not implemented.")

    def get_file_name (self):
        """Get the data file name. """
        debug ("In DataSource::get_file_name ()")
        return self.file_name

    def add_reference (self, ref):
        """ Add a reference object that is notified each time anything
        is changed in the DataSource object.  This is used for all
        ModuleManager instances."""
        debug ("In DataSource::add_reference ()")
        if ref in self.ref_lst:
            msg = "In DataSource::add_reference: Cannot add "\
                  "reference since reference already exists."
            debug (msg)
            return
        else:
            self.ref_lst.append (ref)

    def del_reference (self, ref):
        """ Remove an object that is to be notified of changes in
        self.  This is called when a ModuleManager is being
        deleted."""
        debug ("In DataSource::del_reference ()")
        self.ref_lst.remove (ref)

    def update_references (self):        
        """ Called when the configuration of the DataSource has
        changed.  This updates all the necessary objects via their
        update method."""
        debug ("In DataSource::update_references ()")
        for ref in self.ref_lst:
            ref.Update ()

    def config_changed (self):
        """ Called when the configuration options (in the Preferences
        menu) is changed."""
        debug ("In DataSource::config_changed ()")
        pass

    def GetOutput (self): 
	"""Get the Data reader's output. """
        debug ("In DataSource::GetOutput ()")
        pass

    def get_grid_type (self): 
	"""Get the type of grid used in the data file."""
        debug ("In DataSource::get_grid_type ()")
	return self.grid_type

    def get_scalar_data_name (self): 
	"""Get the name of the scalar data attribute being used."""
        debug ("In DataSource::get_scalar_data_name ()")
	return self.scalar_data_name

    def get_vector_data_name (self): 
	"""Get the name of the vector data attribute being used."""
        debug ("In DataSource::get_vector_data_name ()")
	return self.vector_data_name

    def get_tensor_data_name (self):
        """Get the name of the tensor data attribute being used."""
        debug ("In DataSource::get_tensor_data_name ()")
        return self.tensor_data_name

class Filter (Source):

    """ The basic Filter class from which all are filters
    derived. This implements sufficient functionality that more
    complex filters are pretty much trivial to create."""

    def __init__ (self, mod_m):
        """ The argument 'mod_m' is a ModuleManager."""
        debug ("In Filter::__init__ ()")
        Common.state.busy ()
        Source.__init__ (self)
        self.mod_m = mod_m
        self.renwin = mod_m.get_render_window ()
        self.prev_fil = mod_m.get_last_source ()
        # try to use this as your filter
        self.fil = None
        self.initialize ()
        Common.state.idle ()

    def initialize (self):
        """Override this to create the actual filter and do what you
        want.  Use self.fil as the wrapped filter."""
        debug ("In Filter::initialize ()")        
        pass

    def set_input_source (self, source):
        """Set the input source object for this Filter."""
        debug ("In Filter::set_input_source ()")
        debug ("Filter::set_input_source not implemented.")        

    def SetInputSource (self, source): 
        """Set the input source object for this Filter."""
        debug ("In Filter::SetInputSource ()")
        self.set_input_source (source)

    def GetOutput (self):
        debug ("In Filter::GetOutput ()")        
        return self.fil.GetOutput ()    

    def get_scalar_data_name (self):
	"""Get the name of the scalar data attribute being used.
	Defaults to returning the previous filters scalar
	data_name."""
        debug ("In Filter::get_scalar_data_name ()")
        return self.prev_fil.get_scalar_data_name ()
        
    def get_vector_data_name (self):
	"""Get the name of the vector data attribute being used.
	Defaults to returning the previous filters vector
	data_name."""
        debug ("In Filter::get_vector_data_name ()")
        return self.prev_fil.get_vector_data_name ()

    def get_tensor_data_name (self):
        """Get the name of the tensor data attribute being used.
        Defaults to returning the previous filters tensor
	data_name."""
        debug ("In Filter::get_tensor_data_name ()")
        return self.prev_fil.get_tensor_data_name ()

    def save_config (self, file):
        """Saves the filter config to passed file."""
        debug ("In Filter::save_config ()")
        p = vtkPipeline.vtkMethodParser.VtkPickler ()
        for obj in (self.fil, ):
            p.dump (obj, file)
        
    def load_config (self, file):
        """Loads the filter config from passed file."""
        debug ("In Filter::load_config ()")
        p = vtkPipeline.vtkMethodParser.VtkPickler ()
        for obj in (self.fil, ):
            p.load (obj, file)
        self.fil.Update ()


class Module (VizObject):
    
    """ The basic Module class from which all modules are derived."""

    def __init__ (self, mod_m): 
        """ The argument 'mod_m' is a ModuleManager."""
        debug ("In Module::__init__ ()")
        VizObject.__init__ (self)
        self.mod_m = mod_m
        self.renwin = mod_m.get_render_window ()
        # Set this to the actor you need to be able to configure
        self.actor = None
        self.mapper = None
    
    def SetInput (self, source):        
        """ Set the input for this Module.  This function is similar
        to the VTK obj1.SetInput(obj2.GetOutput()) kind of function
        call. """
        debug ("In Module::SetInput ()")
        debug ("Module::SetInput not implemented.")

    def _contour_init (self):
        """ Initialize variables for contour GUI controls."""
        debug ("In Module::_contour_init ()")
        self.contour_on = Tkinter.IntVar ()
        self.linew_var = Tkinter.DoubleVar ()
        self.n_cnt = Tkinter.IntVar ()
        self.min_cnt = Tkinter.DoubleVar ()
        self.max_cnt = Tkinter.DoubleVar ()

    def make_contour_gui (self):
        """ Create the GUI controls for contours."""
        debug ("In Module::make_contour_gui ()")
        frame = Tkinter.Frame (self.root, relief='ridge', bd=2)
        frame.pack (side='top', fill='both', expand=1)
        
        cb = Tkinter.Checkbutton (frame, text="Show Contours", 
                                  variable=self.contour_on, onvalue=1,
                                  offvalue=0, command=self.do_contour)
        cb.grid (row=0, column=0, sticky='w')
        
        lab = Tkinter.Label (frame, text="Number of contours:")
        lab.grid (row=1, column=0, sticky='w')
        entry = Tkinter.Entry (frame, width=5, relief='sunken', 
                       textvariable=self.n_cnt)
        entry.grid (row=1, column=1, sticky='we')
        entry.bind ("<Return>", self.change_contour)
        
        lab = Tkinter.Label (frame, text="Minimum contour:")
        lab.grid (row=2, column=0, sticky='w')
        entry = Tkinter.Entry (frame, width=10, relief='sunken', 
                                     textvariable=self.min_cnt)
        entry.grid (row=2, column=1, sticky='we')
        entry.bind ("<Return>", self.change_contour)

        lab = Tkinter.Label (frame, text="Maximum contour:")
        lab.grid (row=3, column=0, sticky='w')
        entry = Tkinter.Entry (frame, width=10, relief='sunken', 
                             textvariable=self.max_cnt)
        entry.grid (row=3, column=1, sticky='we')
        entry.bind ("<Return>", self.change_contour)

    def make_actor_gui (self, event=None, color=1, linewidth=1,
                        scalar=1, representation=1, opacity=1,
                        compact=0):
        """Creates controls for the actor config.  This requires that
        there be an instance variable called self.actor and
        self.mapper."""        
        debug ("In Module::make_actor_gui ()")

        self.scalar_on_var = Tkinter.IntVar ()
        self.scalar_on_var.set (0)
        if self.mapper:
            self.scalar_on_var.set (self.mapper.GetScalarVisibility ())

        frame = Tkinter.Frame (self.root, relief='ridge', bd=2)
        frame.pack (side='top', fill='both', expand=1)

        rw = 0
        if scalar:
            cb = Tkinter.Checkbutton (frame, text="Scalar Coloring",
                                      variable=self.scalar_on_var,
                                      onvalue=1, offvalue=0,
                                      command=self.scalar_config)
            cb.grid (row=rw, column=0, columnspan=2, pady=3, sticky='w')
            rw = rw + 1
        if color:
            but = Tkinter.Button (frame, text="Change Object Color",
                                  underline=2, command=self.change_color)
            but.grid (row=rw, column=0, columnspan=2, pady=3, sticky='ew')
            self.root.bind ("<Alt-a>", self.change_color)            
            rw = rw + 1

        if representation:
            self.rep_var = Tkinter.IntVar ()
            self.rep_var.set (self.actor.GetProperty().GetRepresentation())
            rb1 = Tkinter.Radiobutton (frame,
                                       text="Set Representation "\
                                       "to Wireframe",
                                       variable=self.rep_var, value=1,
                                       command=self.represent_config)
            rb1.grid (row=rw, column=0, columnspan=2, pady=3, sticky='w')
            rw = rw + 1
            rb2 = Tkinter.Radiobutton (frame,
                                       text="Set Representation to Surface",
                                       variable=self.rep_var, value=2,
                                       command=self.represent_config)
            rb2.grid (row=rw, column=0, columnspan=2, pady=3, sticky='w')
            rw = rw + 1

        if opacity:
            self.opaq_res_var = Tkinter.DoubleVar ()
            self.opaq_res_var.set (0.01)
            if compact:
                but = Tkinter.Button (frame, text="Change Object Opacity",
                                      underline=7,
                                      command=self.compact_opacity)
                but.grid (row=rw, column=0, columnspan=2, pady=3,
                          sticky='ew')
                self.root.bind ("<Alt-o>", self.compact_opacity)
                rw = rw + 1
            else:
                sl = Tkinter.Scale (frame, label="Set Opacity", 
                                    from_=0.0, to=1.0,
                                    length="5c", orient='horizontal', 
                                    resolution=self.opaq_res_var.get ())
                sl.set (self.actor.GetProperty ().GetOpacity ())
                sl.grid (row=rw, column=0, columnspan=2, sticky='ew')
                sl.bind ("<ButtonRelease>", self.change_opacity)
                self.opaq_slider = sl
                rw = rw + 1
                lab = Tkinter.Label (frame, text="Opacity resolution: ")
                lab.grid (row=rw, column=0, sticky='w')
                entr = Tkinter.Entry (frame, width=5, relief='sunken',
                                      textvariable=self.opaq_res_var)
                entr.grid (row=rw, column=1, sticky='ew')
                entr.bind ("<Return>", self.set_opacity_resolution)
                rw = rw+1

        if linewidth:
            self.linew_var = Tkinter.DoubleVar ()
            self.linew_var.set (self.actor.GetProperty ().GetLineWidth ())
            lab = Tkinter.Label (frame, text="Line width:")
            lab.grid (row=rw, column=0, sticky='w')
            entr = Tkinter.Entry (frame, width=5, relief='sunken',
                                  textvariable=self.linew_var)
            entr.grid (row=rw, column=1, sticky='we')
            entr.bind ("<Return>", self.set_linewidth)
            rw = rw + 1

    def do_contour (self, event=None):
        """Called when the user requests contour lines."""
        debug ("In Module::do_contour ()")
        debug ("Module::do_contour () is not implemented.")

    def change_contour (self, event=None):
        """Called when the user changes the contour line config."""
        debug ("In Module::change_contour ()")
        debug ("Module::change_contour () is not implemented.")

    def set_linewidth (self, event=None):
        """Called when the actor linewidth to be changed."""
        debug ("In Module::set_linewidth ()")
        Common.state.busy ()
        self.actor.GetProperty ().SetLineWidth (self.linew_var.get ())
        self.renwin.Render ()
        Common.state.idle ()

    def scalar_config (self, event=None):        
        """ Called when the user requests ScalarVisibility on or
        off."""
        debug ("In Module::scalar_config ()")
        Common.state.busy ()
        val = self.scalar_on_var.get ()
        self.mapper.SetScalarVisibility (val)
        self.renwin.Render ()
        Common.state.idle ()

    def represent_config (self, event=None):        
        """ Called when the user changes the Representation of the
        actor."""
        debug ("In Module::plane_config ()")
        Common.state.busy ()
        val = self.rep_var.get ()
        self.actor.GetProperty ().SetRepresentation (val)
        self.renwin.Render ()
        Common.state.idle ()

    def change_color (self, event=None): 
        """ Called when the user changes the color of the actor."""
        debug ("In Module::change_color ()")
	clr = self.actor.GetProperty ().GetColor ()
	init_clr = "#%02x%02x%02x"%(clr[0]*255, clr[1]*255, clr[2]*255)
	color = tkColorChooser.askcolor (title="Change object color", 
					 initialcolor=init_clr)
	if color[1] is not None:
            Common.state.busy ()
	    clr = Common.tk_2_vtk_color (color[0])
	    apply (self.actor.GetProperty ().SetColor, clr)
	    self.renwin.Render ()        
            Common.state.idle ()
            if self.scalar_on_var.get () != 0:
                msg = "Warning: This setting will have effect only if "\
                      "there is no ScalarVisibility."
                Common.print_err (msg)

    def change_opacity (self, event=None):
        """ Called when the opacity slider is changed."""
        debug ("In Module::change_opacity ()")
        Common.state.busy ()
        val = self.opaq_slider.get ()
        self.actor.GetProperty ().SetOpacity (val)
        self.renwin.Render ()
        Common.state.idle ()

    def set_opacity_resolution (self, event=None):
        """ Called when the opacity slider resolution is changed. """
        self.opaq_slider.config (resolution=self.opaq_res_var.get ())
        
    def compact_opacity (self, event=None):        
        """ Called when the opacity button (when compact=1) is
        clicked."""
        self.o_top = top = Tkinter.Toplevel (self.root)
        top.transient (self.root.master)
        top.protocol ("WM_DELETE_WINDOW", top.destroy)
        frame = Tkinter.Frame (top, relief='ridge', bd=2)
        frame.pack (side='top', fill='both', expand=1)
        rw = 0
        sl = Tkinter.Scale (frame, label="Set Opacity", 
                            from_=0.0, to=1.0,
                            length="5c", orient='horizontal', 
                            resolution=self.opaq_res_var.get ())
        sl.set (self.actor.GetProperty ().GetOpacity ())
        sl.grid (row=rw, column=0, columnspan=2, sticky='ew')
        sl.bind ("<ButtonRelease>", self.change_opacity)
        self.opaq_slider = sl
        rw = rw + 1
        lab = Tkinter.Label (frame, text="Opacity resolution: ")
        lab.grid (row=rw, column=0, sticky='w')
        entr = Tkinter.Entry (frame, width=5, relief='sunken',
                              textvariable=self.opaq_res_var)
        entr.grid (row=rw, column=1, sticky='ew')
        entr.bind ("<Return>", self.set_opacity_resolution)
        rw = rw+1
        but = Tkinter.Button (frame, text="Close", underline=0,
                              command=lambda t=top, e=None: t.destroy ())
        but.grid (row=rw, column=0, columnspan=2, sticky='ew')
        top.bind ("<Alt-c>", self.__opacity_quit)

    def __opacity_quit (self, event=None):
        self.o_top.destroy ()


class CutPlaneModule (Module):

    """ An abstraction for cut plane based modules. """

    def __init__ (self, mod_m):
        debug ("In CutPlaneModule::__init ()")
        Module.__init__ (self, mod_m)
        # this should be a vtkPlane
        self.plane = vtkpython.vtkPlane ()
	self.step_var = Tkinter.DoubleVar ()
	self.n_step_var = Tkinter.IntVar ()
        self.resoln_var = Tkinter.DoubleVar ()
        self.resoln_var.set (1.0)
        self.slider = []

    def get_angles (self):
        debug ("In CutPlaneModule::get_angles ()")
        nor = self.plane.GetNormal ()
        pos = self.plane.GetOrigin ()
        zang = math.acos (nor[2])
        xang = math.atan2 (nor[1], nor[0])
        if xang < 0:
            xang = xang + 2.0*math.pi

        zang = zang*180.0/math.pi
        xang = xang*180.0/math.pi
        return (zang, xang)    

    def config_extents (self, val):
        debug ("In CutPlaneModule::config_extents ()")
        zang = val[0]*math.pi/180.0
        xang = val[1]*math.pi/180.0
        ds = val[2]*self.step_size
        cos1 = math.cos (zang)
        sin1 = math.sin (zang)
        cos2 = math.cos (xang)
        sin2 = math.sin (xang)
        nor = (sin1*cos2, sin1*sin2, cos1)
        cen = self.center
        pos = (cen[0] + ds*nor[0], cen[1] + ds*nor[1], cen[2] + ds*nor[2])
        self.plane.SetNormal (nor)
        self.plane.SetOrigin (pos)

    def make_cut_plane_gui (self):
        debug ("In CutPlaneModule::make_cut_plane_gui ()")
        frame = Tkinter.Frame (self.root, relief='ridge', bd=2)
        frame.pack (side='top', fill='both', expand=1)

        angle = self.get_angles ()
        self.slider = []
        sl = Tkinter.Scale (frame, label="Angle from Z-axis", from_=0,
                            to=180, length="8c", orient='horizontal')
        sl.set (angle[0])
        sl.pack (side='top')
        sl.bind ("<ButtonRelease>", self.change_slider)
        self.slider.append (sl)
        
        sl = Tkinter.Scale (frame, label="Angle from X-axis", from_=0,
                            to=360, length="8c", orient='horizontal')
        sl.set (angle[1])
        sl.pack (side='top')
        sl.bind ("<ButtonRelease>", self.change_slider)
        self.slider.append (sl)
        
        val = self.n_step_var.get ()
        sl = Tkinter.Scale (frame, length="8c", 
                            label="Distance from center along normal",
                            from_=-val, to=val, orient='horizontal')
        sl.set (self.slider_pos)
        sl.pack (side='top')
        sl.bind ("<ButtonRelease>", self.change_slider)
        self.slider.append (sl)

	f = Tkinter.Frame (frame)
	f.pack (side='top')

        rw = 0
	labl = Tkinter.Label (f, text="Angle resolution:")
	labl.grid (row=rw, column=0, sticky='w')
	self.step_entr = Tkinter.Entry (f, width=5, relief='sunken',
                                        textvariable=self.resoln_var)
	self.step_entr.grid (row=rw, column=1, sticky='we')
	self.step_entr.bind ("<Return>", self.change_resoln)
        rw = rw + 1

	labl = Tkinter.Label (f, text="Distance step:")
	labl.grid (row=rw, column=0, sticky='w')
	self.step_entr = Tkinter.Entry (f, width=5, relief='sunken',
                                        textvariable=self.step_var)
	self.step_entr.grid (row=rw, column=1, sticky='we')
	self.step_entr.bind ("<Return>", self.change_cut)
        rw = rw + 1

	labl = Tkinter.Label (f, text="Step bounds:")
	labl.grid (row=rw, column=0, sticky='w')
	self.n_step_entr = Tkinter.Entry (f, width=5, relief='sunken',
                                          textvariable=self.n_step_var)
	self.n_step_entr.grid (row=rw, column=1, sticky='we')
	self.n_step_entr.bind ("<Return>", self.change_cut)
    
    def change_cut (self, event=None):
        debug ("In CutPlaneModule::change_cut ()")
	self.step_size = self.step_var.get ()
	n_s = self.n_step_var.get ()
	self.slider[2].config (from_=-n_s, to=n_s)
	self.change_slider (event)

    def change_slider (self, event=None):
        debug ("In CutPlaneModule::change_slider ()")
        Common.state.busy ()
	val = []
	for i in range (3):
	    val.append (self.slider[i].get ())

        self.slider_pos = val[2]
	self.config_extents (val)
	self.renwin.Render ()
        Common.state.idle ()    

    def change_resoln (self, event=None):
        debug ("In CutPlaneModule::change_resoln ()")
        val = self.resoln_var.get ()
	for i in range (0, 2):
	    self.slider[i].config (resolution=val)        
    
