"""

This file defines a class LutHandler that creates and manages a lookup
table and a scalar bar (legend) for it.

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.4 $"
__date__ = "$Date: 2001/11/08 19:26:51 $"

import Tkinter, tkFileDialog
import vtkpython, os
import Common, Base.Objects
import vtkPipeline.vtkMethodParser
import Lut_Editor

tk_fopen = tkFileDialog.askopenfilename
debug = Common.debug

class LutHandler (Base.Objects.VizObject):
    """  
    Creates and manages a lookup table and a scalar bar (legend).
    Overload functions appropriately to get user defined behaviour."""
    def __init__ (self): 
        debug ("In LutHandler::__init__ ()")
        Base.Objects.VizObject.__init__ (self)
        self.lut_var = Tkinter.IntVar ()
	self.lut_var.set (1)
        self.legend_on = Tkinter.IntVar ()
        self.legend_on.set (0)
        self.legend_orient = Tkinter.IntVar ()
        self.legend_orient.set (0)        
        self.n_label = Tkinter.IntVar ()
        self.n_label.set (8)
        self.n_color_var = Tkinter.IntVar ()
        self.n_color_var.set (64)
        self.shadow_on_var = Tkinter.IntVar ()
        self.shadow_on_var.set (0)
        self.label_var = Tkinter.StringVar ()
        self.label_var.set ('')
        self.file_name = ""

    def __del__ (self):
        debug ("In LutHandler::__del__ ()")
        self.module_mgr.get_render_window().remove_actors(self.sc_bar)

    def initialize (self, module_mgr): 
	"Initialize data, given a ModuleManager object."
        debug ("In LutHandler::initialize ()")
        self.module_mgr = module_mgr
	self.init_lut ()
	self.init_scalar_bar ()
        self.pipe_objs = (self.lut, self.sc_bar)
        self.renwin = module_mgr.get_render_window ()

    def init_lut (self): 
	"Set up the default LookupTable. Defaults to a blue to red table."
        debug ("In LutHandler::init_lut ()")
	self.lut = vtkpython.vtkLookupTable ()
	self.lut.SetHueRange (0.667, 0.0)
	self.lut.SetNumberOfColors (64)
	self.lut.Build ()
	
    def init_scalar_bar (self): 
	"Sets up the default scalar bar."
        debug ("In LutHandler::init_scalar_bar ()")
	self.sc_bar = vtkpython.vtkScalarBarActor ()
	self.sc_bar.SetLookupTable (self.lut)
	self.sc_bar.GetPositionCoordinate ().SetCoordinateSystemToNormalizedViewport ()
	self.set_horizontal ()
        self.sc_bar.SetVisibility (0)
	self.sc_bar.SetNumberOfLabels (8)
        self.sc_bar.SetShadow (self.shadow_on_var.get ())
        apply (self.sc_bar.GetProperty ().SetColor, Common.config.fg_color)
        self.module_mgr.get_render_window ().add_actors (self.sc_bar)

    def save_config (self, file): 
        debug ("In LutHandler::save_config ()")
        file.write ("%d\n"%self.lut_var.get ())
        rel_file_name = ""
        if (self.file_name):
            rel_file_name = Common.get_relative_file_name (file.name,
                                                           self.file_name)
        file.write ("%s\n"%rel_file_name)
        p = vtkPipeline.vtkMethodParser.VtkPickler ()
        for obj in (self.lut, self.sc_bar, self.sc_bar.GetProperty (),
                    self.sc_bar.GetPositionCoordinate (),
                    self.sc_bar.GetPosition2Coordinate ()):
            p.dump (obj, file)

    def load_config (self, file): 
        debug ("In LutHandler::load_config ()")
        l = int (file.readline ())
        file_name = file.readline ()[:-1]
        if file_name:
            file_name = Common.get_abs_file_name (file.name, file_name)
            if not os.path.isfile (file_name):
                msg = "Unable to open Lookup Table file: " + file_name
                msg = msg + "\n\nPlease try selecting the file manually."
                Common.print_err (msg)
                file_name = tk_fopen (title="Open LuT file", 
                                      filetypes=[("Lookup table files",
                                                  "*.lut"), 
                                                 ("All files", "*")])

        p = vtkPipeline.vtkMethodParser.VtkPickler ()
        for obj in (self.lut, self.sc_bar, self.sc_bar.GetProperty (),
                    self.sc_bar.GetPositionCoordinate (),
                    self.sc_bar.GetPosition2Coordinate ()):
            p.load (obj, file)

        self.lut_var.set (l)
        self.legend_on.set (self.sc_bar.GetVisibility ())
        self.legend_orient.set (self.sc_bar.GetOrientation ())
        self.n_label.set (self.sc_bar.GetNumberOfLabels ())
        self.n_color_var.set (self.sc_bar.GetMaximumNumberOfColors ())
        self.shadow_on_var.set (self.sc_bar.GetShadow ())
        self.change_lut ()
        self.change_legend_orient ()
        self.load_lut_from_file (file_name)

    def config_changed (self): 
        debug ("In LutHandler::config_changed ()")
        apply (self.sc_bar.GetProperty ().SetColor, Common.config.fg_color)

    def set_horizontal (self): 
	"Makes the legend horizontal with default values."
        debug ("In LutHandler::set_horizontal ()")
	self.sc_bar.GetPositionCoordinate().SetValue (0.1,0.01)
	self.sc_bar.SetOrientationToHorizontal ()
	self.sc_bar.SetWidth (0.8)
	self.sc_bar.SetHeight (0.14)

    def set_vertical (self): 
	"Makes the legend horizontal with default values."
        debug ("In LutHandler::set_vertical ()")
	self.sc_bar.GetPositionCoordinate().SetValue (0.01,0.15)
	self.sc_bar.SetOrientationToVertical ()
	self.sc_bar.SetWidth (0.14)
	self.sc_bar.SetHeight (0.85)

    def set_lut_bw (self): 
	"Change the lookup table to a black and white one."
        debug ("In LutHandler::set_lut_bw ()")
	self.lut.Allocate(0,0)
	self.lut.SetHueRange (0.0, 0.0)
	self.lut.SetSaturationRange (0.0, 0.0)
	self.lut.SetValueRange (0.0, 1.0)
	self.lut.SetNumberOfColors (64)
	self.lut.Build ()
	self.sc_bar.Modified ()

    def set_lut_wb (self): 
	"Change the lookup table to a white and black one."
        debug ("In LutHandler::set_lut_wb ()")
	self.lut.Allocate(0,0)
	self.lut.SetHueRange (0.0, 0.0)
	self.lut.SetSaturationRange (0.0, 0.0)
	self.lut.SetValueRange (1.0, 0.0)
	self.lut.SetNumberOfColors (64)
	self.lut.Build ()
	self.sc_bar.Modified ()

    def set_lut_blue_red (self): 
	"Change the lookup table to a blue to red one."
        debug ("In LutHandler::set_lut_blue_red ()")
	self.lut.Allocate(0,0)
	self.lut.SetHueRange (0.6667, 0.0)
	self.lut.SetSaturationRange (1.0, 1.0)
	self.lut.SetValueRange (1.0, 1.0)
	self.lut.SetNumberOfColors (64)
	self.lut.Build ()
	self.sc_bar.Modified ()

    def set_lut_red_blue (self): 
	"Change the lookup table to a red to blue one."
        debug ("In LutHandler::set_lut_red_blue ()")
	self.lut.Allocate(0,0)
	self.lut.SetHueRange (0.0, 0.6667)
	self.lut.SetSaturationRange (1.0, 1.0)
	self.lut.SetValueRange (1.0, 1.0)
	self.lut.SetNumberOfColors (64)
	self.lut.Build ()
	self.sc_bar.Modified ()

    def set_data_range (self, data_range): 
        debug ("In LutHandler::set_data_range ()")
	self.data_range = data_range
	self.lut.SetRange (data_range[0], data_range[1])
	self.sc_bar.Modified ()

    def set_data_name (self, data_name): 
        debug ("In LutHandler::set_data_name ()")
	self.data_name = data_name
	self.sc_bar.SetTitle (data_name)
	self.sc_bar.Modified ()

    def get_lut (self): 
        debug ("In LutHandler::get_lut ()")
	return self.lut

    def get_scalarbar (self): 
        debug ("In LutHandler::get_scalarbar ()")
	return self.sc_bar

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

        self.make_lut_gui (frame)
        self.make_scbar_gui (frame)        

    def make_lut_gui (self, master): 
        debug ("In LutHandler::make_lut_gui ()")
        frame = Tkinter.Frame (master, relief='ridge', bd=2)
        frame.pack (side='top', fill='both', expand=1)
        but = Tkinter.Button (frame, text="Load Lookup Table",
                              command=self.load_lut)
        but.grid (row=0, col=0, pady=2)
        but = Tkinter.Button (frame, text="Edit Lookup Table",
                              command=self.edit_lut)
        but.grid (row=1, col=0, pady=2)

        rb = Tkinter.Radiobutton (frame, text='blue-red colormap',
                                  value=1, variable=self.lut_var,
                                  command=self.change_lut)
        rb.grid (row=2, col=0, pady=2, sticky='w')
        rb = Tkinter.Radiobutton (frame, text='red-blue colormap',
                                  value=2, variable=self.lut_var,
                                  command=self.change_lut)
        rb.grid (row=3, col=0, pady=2, sticky='w')
        rb = Tkinter.Radiobutton (frame, text='black-white colormap',
                                  value=3, variable=self.lut_var,
                                  command=self.change_lut)
        rb.grid (row=4, col=0, pady=2, sticky='w')
        rb = Tkinter.Radiobutton (frame, text='white-black colormap',
                                  value=4, variable=self.lut_var,
                                  command=self.change_lut)
        rb.grid (row=5, col=0, pady=2, sticky='w')

    def make_scbar_gui (self, master): 
        debug ("In LutHandler::make_scbar_gui ()")
        frame = Tkinter.Frame (master, relief='ridge', bd=2)
        frame.pack (side='top', fill='both', expand=1)
        rw = 0
        cb = Tkinter.Checkbutton (frame, text="Show Legend",
                                  variable=self.legend_on,
                                  onvalue=1, offvalue=0,
                                  command=self.legend_on_off)
        cb.grid (row=rw, column=0, columnspan=2, pady=2, sticky='w')
        rw = rw + 1
        rb = Tkinter.Radiobutton (frame, text='Horizontal',
                                  value=0, variable=self.legend_orient,
                                  command=self.change_legend_orient)
        rb.grid (row=rw, column=0, columnspan=2, pady=2, sticky='w')
        rw = rw + 1
        rb = Tkinter.Radiobutton (frame, text='Vertical',
                                  value=1, variable=self.legend_orient,
                                  command=self.change_legend_orient)
        rb.grid (row=rw, column=0, columnspan=2, pady=2, sticky='w')
        rw = rw + 1
        b = Tkinter.Checkbutton (frame, text="Shadow Legend", 
                                 variable=self.shadow_on_var,
                                 onvalue=1, offvalue=0,
                                 command=self.set_shadow)
        b.grid (row=rw, column=0, columnspan=2, pady=2, sticky='w')
        rw = rw + 1        
        lab = Tkinter.Label (frame, text="Number of Labels:")
        lab.grid (row=rw, column=0, pady=2, sticky='w')
        entr = Tkinter.Entry (frame, width=5, relief='sunken',
                              textvariable=self.n_label)
        entr.grid (row=rw, column=1, pady=2, sticky='ew')
        entr.bind ("<Return>", self.set_n_label)

        rw = rw + 1
        lab = Tkinter.Label (frame, text="Number of Colors:")
        lab.grid (row=rw, column=0, pady=2, sticky='w')
        entr = Tkinter.Entry (frame, width=5, relief='sunken',
                              textvariable=self.n_color_var)
        entr.grid (row=rw, column=1, pady=2, sticky='ew')
        entr.bind ("<Return>", self.set_n_color)
        rw = rw + 1

        self.label_var.set (self.sc_bar.GetTitle ())
        lab = Tkinter.Label (frame, text="Legend text:")
        lab.grid (row=rw, column=0, pady=2, sticky='w')
        entr = Tkinter.Entry (frame, width=10, relief='sunken',
                              textvariable=self.label_var)
        entr.grid (row=rw, column=1, pady=2, sticky='ew')
        entr.bind ("<Return>", self.set_label)
        
    def load_lut (self, event=None): 
        debug ("In LutHandler::load_lut ()")
	file_name = tk_fopen (title="Open LuT file", 
			      initialdir=Common.config.initial_dir,
			      filetypes=[("Lookup table files", "*.lut"), 
					 ("All files", "*")])
        self.load_lut_from_file (file_name)

    def load_lut_from_file (self, file_name): 
        debug ("In LutHandler::load_lut_from_file ()")
	lut_list = []        
	if file_name:
            try:
                f = open (file_name, 'r')
            except IOError:
                msg = "Sorry cannot open Lookup Table file: %s"%file_name
                raise IOError, msg
            else:
                try:
                    lut_list = Lut_Editor.parse_lut_file (file_name)
                except Lut_Editor.LutParseError:
                    msg = "Sorry Lut_Editor couldn't parse "\
                          "file: %s"%file_name
                    raise Lut_Editor.LutParseError, msg
                else:
                    Common.state.busy ()
                    renwin = self.module_mgr.get_render_window ()
                    Lut_Editor.set_lut (self.lut, lut_list)
                    self.file_name = file_name
                    self.lut_var.set (0)
                    renwin.Render ()
                    Common.state.idle ()

    def edit_lut (self, event=None): 
        debug ("In LutHandler::edit_lut ()")
        self.lut_var.set (0)
	app = Lut_Editor.Lut_Editor (self.root)
	app.edit_lut (self.lut)
	self.file_name = app.run ()

    def change_lut (self): 
	"Changes the lookup table to use."
        debug ("In LutHandler::change_lut ()")
        Common.state.busy ()
	val = self.lut_var.get ()
	if val == 1:
	    self.set_lut_blue_red ()
	elif val == 2:
	    self.set_lut_red_blue ()
	elif val == 3:
	    self.set_lut_bw ()
	elif val == 4:
	    self.set_lut_wb ()
        self.file_name = ""
	self.renwin.Render ()
        Common.state.idle ()

    def change_legend_orient (self): 
	"Changes orientation of the legend."
        debug ("In LutHandler::change_legend_orient ()")
	val = self.legend_orient.get ()
	if val == 0:
	    self.set_horizontal ()
	elif val == 1:
	    self.set_vertical ()
	self.renwin.Render ()

    def legend_on_off (self): 
        debug ("In LutHandler::legend_on_off ()")
        self.sc_bar.SetVisibility (self.legend_on.get ())
	self.renwin.Render ()

    def set_n_label (self, event=None):
        debug ("In LutHandler::set_n_label ()")
	self.sc_bar.SetNumberOfLabels (self.n_label.get ())
	self.sc_bar.Modified ()
	self.renwin.Render ()

    def set_n_color (self, event=None):
        debug ("In LutHandler::set_n_color ()")
	self.sc_bar.SetMaximumNumberOfColors (self.n_color_var.get ())
	self.sc_bar.Modified ()
	self.renwin.Render ()

    def set_shadow (self, event=None):
        debug ("In LutHandler::set_shadow ()")
	self.sc_bar.SetShadow (self.shadow_on_var.get ())
	self.sc_bar.Modified ()
	self.renwin.Render ()

    def set_label (self, event=None):
        debug ("In LutHandler::set_label ()")
	self.sc_bar.SetTitle (self.label_var.get ())
	self.sc_bar.Modified ()
	self.renwin.Render ()
