"""

Defines a simple wrapper for the vtkRenderWindow.  This the class
which is responsible for all the actual rendering. It is also
responsible for saving the scene to a image.

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/07 09:09:44 $"

import Tkinter, tkFileDialog, tkMessageBox
import vtkpython, vtkRenderWidget
import Common, Base.Objects
import types, os
import vtkPipeline.ConfigVtkObj
import vtkPipeline.vtkMethodParser

tk_fsave = tkFileDialog.asksaveasfilename
debug = Common.debug


class JPEGDialog:
    def __init__ (self, values):
        debug ("In JPEGDialog ::__init__ ()")
        self.values = values
        top = self.top = Tkinter.Toplevel (Tkinter._default_root)
        top.transient (top.master)
        top.title ("Set JPEG parameters.")
        top.protocol ("WM_DELETE_WINDOW", self.close_gui)
        Tkinter.Label (top, text="JPEG Properties.").pack ()
        self.prog_var = Tkinter.IntVar ()
        self.prog_var.set (values[1])
        cb = Tkinter.Checkbutton (top, text="Progressive JPEG",
                                  variable=self.prog_var, onvalue=1,
                                  offvalue=0)
        cb.pack(side='top', fill='both', expand=1)

        sl = Tkinter.Scale (top, label="JPEG Quality", from_=0, to=100,
                            length="8c", orient='horizontal')
        sl.set (values[0])
        sl.pack (side='top')
        sl.bind ("<ButtonRelease>", self.set_quality)
        self.quality_scale = sl

        but = Tkinter.Button (top, text="OK", underline=0,
                              command=self.close_gui)
        but.pack (side='bottom', fill='both', expand=1)
        top.bind ("<Alt-o>", self.close_gui)
        top.wait_window(top)

    def set_quality (self, event):
        debug ("In JPEGDialog ::set_quality ()")
        self.values[0] = self.quality_scale.get ()
        
    def close_gui (self, event=None):
        debug ("In JPEGDialog ::close_gui ()")
        self.values[1] = self.prog_var.get()
        self.values[0] = self.quality_scale.get ()
        self.top.destroy ()

def get_jpeg_prop ():
    debug ("In get_jpeg_prop ()")
    val = [75, 1]
    d = JPEGDialog (val)
    return val


class RenderWindow (Base.Objects.VizObject):
    
    """ Defines a simple wrapper for the vtkRenderWindow.  This the
    class which is responsible for all the actual rendering. It is
    also responsible for saving the scene to a image. """

    def __init__ (self, master): 
        debug ("In RenderWindow::__init__ ()")
        Base.Objects.VizObject.__init__ (self)
        self.frame = Tkinter.Frame (master)
        self.frame.pack (side='top', fill='both', expand=1)
	self.tkwidget = vtkRenderWidget.vtkTkRenderWidget (self.frame,
                                                           width=600,
                                                           height=500)
	self.tkwidget.pack (expand='true',fill='both')
	#self.tkwidget.bind ("<KeyPress-q>", self.quit)
        # disabling surface and wireframe toggling.
        self.tkwidget.unbind ("<KeyPress-s>")
        self.tkwidget.unbind ("<KeyPress-w>")        
	self.ren = vtkpython.vtkRenderer ()
        self.ren.TwoSidedLightingOn ()
	self.renwin = self.tkwidget.GetRenderWindow ()
	self.renwin.AddRenderer (self.ren)
	self.camera = self.ren.GetActiveCamera()        
        # this sets up the tkwidget and forces _CurrentRenderer
        # etc. to be updated
        self.tkwidget.UpdateRenderer (0.0, 0.0)

	buttonFrame=Tkinter.Frame (self.frame, relief='sunken', bd=2)
	buttonFrame.pack (side='bottom')
        Tkinter.Label (buttonFrame, text="View:").pack (side='left')
	Tkinter.Button(buttonFrame, text="Front",
                       command=self.front_view).pack(side='left')
	Tkinter.Button(buttonFrame, text="Back",
                       command=self.back_view).pack(side='left')
	Tkinter.Button(buttonFrame, text="Left",
                       command=self.left_view).pack(side='left')
	Tkinter.Button(buttonFrame, text="Right",
                       command=self.right_view).pack(side='left')
	Tkinter.Button(buttonFrame, text="Top",
                       command=self.top_view).pack(side='left')
	Tkinter.Button(buttonFrame, text="Bottom",
                       command=self.bottom_view).pack(side='left')
	#Tkinter.Button(buttonFrame, text="Default View",
        #               command=self.reset_zoom).pack(side='left')
	Tkinter.Button(buttonFrame, text="Isometric",
                       command=self.isometric_view).pack(side='left')

        self.set_background (Common.config.bg_color)
        self.def_pos = 1
        self.root = None
        self.pipe_objs = self.renwin

    def __del__ (self):
        debug ("In RenderWindow::__del__ ()")
        pass
    
    def update_view (self, x, y, z, vx, vy, vz):
        debug ("In RenderWindow::update_view ()")
        self.camera.SetFocalPoint (0.0, 0.0, 0.0)
        self.camera.SetPosition (x, y, z)
        self.camera.SetViewUp (vx, vy, vz)
	self.ren.ResetCamera()
	self.renwin.Render()

    def front_view (self): 
        debug ("In RenderWindow::front_view ()")
        self.update_view (self.def_pos, 0, 0, 0, 1, 0)
	
    def back_view (self): 
        debug ("In RenderWindow::back_view ()")
        self.update_view (-self.def_pos, 0, 0, 0, 1, 0)
	
    def top_view (self): 
        debug ("In RenderWindow::top_veiw ()")
        self.update_view (0, self.def_pos, 0, 0, 0, 1)

    def bottom_view (self):
        debug ("In RenderWindow::bottom_veiw ()")
        self.update_view (0, -self.def_pos, 0, 0, 0, 1)
        
    def left_view (self): 
        debug ("In RenderWindow::left_view ()")
        self.update_view (0, 0, self.def_pos, 0, 1, 0)
	
    def right_view (self): 
        debug ("In RenderWindow::right_view ()")
        self.update_view (0, 0, -self.def_pos, 0, 1, 0)

    def reset_zoom (self): 
        debug ("In RenderWindow::reset_zoom ()")
	self.ren.ResetCamera ()
	self.renwin.Render ()

    def isometric_view (self): 
        debug ("In RenderWindow::isometric_view ()")
        self.update_view (self.def_pos, self.def_pos, self.def_pos,
                          0, 1, 0)

    def add_actors (self, actors):
        """ Adds a single actor or a tuple or list of actors to the
	renderer."""
        debug ("In RenderWindow::add_actors ()")
        if type (actors) is types.ListType or \
           type (actors) is types.TupleType:            
            for actor in actors:
                self.add_actors (actor)
        else:
            # warning: I dont check if the type is valid.
            if actors:
                self.ren.AddActor (actors)

    def remove_actors (self, actors): 
        """ Renders a single actor or a tuple or list of actors to the
        renderer."""
        debug ("In RenderWindow::remove_actors ()")
        if type (actors) is types.ListType or \
           type (actors) is types.TupleType:
            for actor in actors:
		self.remove_actors (actor)
        else:
            # warning: I dont check if the type is valid.
            if actors:
                self.ren.RemoveActor (actors)

    def save_ps (self, file_name=""):        
        debug ("In RenderWindow::save_ps ()")
        if not file_name:
            file_name = tk_fsave (title="Export to PostScript",
                                  initialdir=Common.config.initial_dir,
                                  defaultextension=".ps",
                                  filetypes=[("PS files", "*.ps"),
                                             ("All files", "*")])
        if len (file_name) != 0:
            Common.state.busy ()
            w2if = vtkpython.vtkWindowToImageFilter ()
            self.lift ()
            w2if.SetInput (self.renwin)
            ex = vtkpython.vtkPostScriptWriter ()
            ex.SetFileName (file_name)
            ex.SetInput (w2if.GetOutput ())
            ex.Write ()
            Common.state.idle ()

    def save_ppm (self, file_name=""): 
        debug ("In RenderWindow::save_ppm ()")
        if not hasattr(self.renwin, 'SetFileName'):
            msg = "Saving to a PPM file is no longer supported under "\
                  "this VTK version please use another format. "
            Common.print_err (msg)
            return        
        if not file_name:
            file_name = tk_fsave (title="Save scene to PPM image file",
                                  initialdir=Common.config.initial_dir,
                                  defaultextension=".ppm",
                                  filetypes=[("PPM images", "*.ppm"), 
                                             ("All files", "*")])
	if len (file_name) != 0:
            Common.state.busy ()
	    self.renwin.SetFileName (file_name)
	    self.lift ()
	    self.renwin.SaveImageAsPPM ()
            Common.state.idle ()

    def save_bmp (self, file_name=""): 
        debug ("In RenderWindow::save_bmp ()")
        if not file_name:
            file_name = tk_fsave (title="Export to BMP image",
                                  initialdir=Common.config.initial_dir,
                                  defaultextension=".bmp",
                                  filetypes=[("BMP images", "*.bmp"), 
                                             ("All files", "*")])
        if len (file_name) != 0:
            Common.state.busy ()
            w2if = vtkpython.vtkWindowToImageFilter ()
            self.lift ()
            w2if.SetInput (self.renwin)
            ex = vtkpython.vtkBMPWriter ()
            ex.SetFileName (file_name)
            ex.SetInput (w2if.GetOutput ())
            ex.Write () 
            Common.state.idle ()

    def save_tiff (self, file_name=""): 
        debug ("In RenderWindow::save_tiff ()")
        if not file_name:
            file_name = tk_fsave (title="Export to TIFF image",
                                  initialdir=Common.config.initial_dir,
                                  defaultextension=".tif",
                                  filetypes=[("TIFF images", "*.tiff"), 
                                             ("TIFF images", "*.tif"),
                                             ("All files", "*")])
        if len (file_name) != 0:
            Common.state.busy ()
            w2if = vtkpython.vtkWindowToImageFilter ()
            self.lift ()
            w2if.SetInput (self.renwin)
            ex = vtkpython.vtkTIFFWriter ()
            ex.SetFileName (file_name)
            ex.SetInput (w2if.GetOutput ())
            ex.Write () 
            Common.state.idle ()

    def save_png (self, file_name=""):
        """Requires VTK 4 to work."""
        debug ("In RenderWindow::save_png ()")
        try:
            ex = vtkpython.vtkPNGWriter ()
        except AttributeError:
            msg = "Saving to a PNG file is not supported by your "\
                  "version of VTK.  Versions 4.0 and above support this."
            Common.print_err (msg)
            return
        if not file_name:
            file_name = tk_fsave (title="Export to PNG image",
                                  initialdir=Common.config.initial_dir,
                                  defaultextension=".png",
                                  filetypes=[("PNG images", "*.png"),
                                             ("All files", "*")])
        if len (file_name) != 0:
            Common.state.busy ()
            w2if = vtkpython.vtkWindowToImageFilter ()
            self.lift ()
            w2if.SetInput (self.renwin)
            ex = vtkpython.vtkPNGWriter ()
            ex.SetFileName (file_name)
            ex.SetInput (w2if.GetOutput ())
            ex.Write () 
            Common.state.idle ()

    def save_jpg(self, file_name="", quality=None, progressive=None):
        """Requires VTK 4 to work.  Arguments: file_name if passed
        will be used, quality is the quality of the JPEG (10-100) are
        valid, the progressive arguments toggles progressive jpegs."""
        debug ("In RenderWindow::save_jpg ()")
        try:
            ex = vtkpython.vtkJPEGWriter()
        except AttributeError:
            msg = "Saving to a JPEG file is not supported by your "\
                  "version of VTK.  Versions 4.0 and above support this."
            Common.print_err (msg)
            return
        if not file_name:
            file_name = tk_fsave (title="Export to JPEG image",
                                  initialdir=Common.config.initial_dir,
                                  defaultextension=".jpg",
                                  filetypes=[("JPEG images", "*.jpg"), 
                                             ("JPEG images", "*.jpeg"),
                                             ("All files", "*")])
        if len (file_name) != 0:
            if not quality and not progressive:
                quality, progressive = get_jpeg_prop ()
            Common.state.busy ()
            w2if = vtkpython.vtkWindowToImageFilter ()
            self.lift ()
            w2if.SetInput (self.renwin)
            ex = vtkpython.vtkJPEGWriter ()
            ex.SetQuality (quality)
            ex.SetProgressive (progressive)
            ex.SetFileName (file_name)
            ex.SetInput (w2if.GetOutput ())
            ex.Write () 
            Common.state.idle ()

    def save_iv (self, file_name=""): 
        debug ("In RenderWindow::save_iv ()")
        if not file_name:
            file_name = tk_fsave (title="Export to OpenInventor",
                                  initialdir=Common.config.initial_dir,
                                  defaultextension=".iv",
                                  filetypes=[("OpenInventor files",
                                              "*.iv"), 
                                             ("All files", "*")])
        if len (file_name) != 0:
            Common.state.busy ()
            ex = vtkpython.vtkIVExporter ()
            self.lift ()
            ex.SetInput (self.renwin)
            ex.SetFileName (file_name)
            ex.Write ()
            Common.state.idle ()

    def save_vrml (self, file_name=""): 
        debug ("In RenderWindow::save_vrml ()")
        if not file_name:
            file_name = tk_fsave (title="Export to VRML", 
                                  initialdir=Common.config.initial_dir,
                                  defaultextension=".wrl",
                                  filetypes=[("VRML files", "*.wrl"), 
                                             ("All files", "*")])
        if len (file_name) != 0:
            Common.state.busy ()
            ex = vtkpython.vtkVRMLExporter ()
            self.lift ()
            ex.SetInput (self.renwin)
            ex.SetFileName (file_name)
            ex.Write ()
            Common.state.idle ()

    def save_rib (self, file_name=""):
        debug ("In RenderWindow::save_rib ()")
        if not file_name:
            file_name = tk_fsave (title="Export to RIB", 
                                  initialdir=Common.config.initial_dir,
                                  defaultextension=".rib",
                                  filetypes=[("RIB files", "*.rib"), 
                                             ("All files", "*")])
        
        if len (file_name) != 0:
            msg = "Do you want the image shader to use a background?\n"\
                  "If you are using Pixar's Renderman, say no. "\
                  "Otherwise say yes and see if you get the desired "\
                  "results."
            bg = tkMessageBox.askyesno ("Background On?", message=msg)
            Common.state.busy ()
            f_pref = os.path.splitext (file_name)[0]
            ex = vtkpython.vtkRIBExporter ()
            ex.SetFilePrefix (f_pref)
            ex.SetTexturePrefix (f_pref + "_tex")
            self.lift ()
            ex.SetRenderWindow (self.renwin)
            if bg:
                ex.BackgroundOn ()
            else:
                ex.BackgroundOff ()
            ex.Write ()
            Common.state.idle ()        

    def quit (self, event=None): 
        debug ("In RenderWindow::quit ()")
        del self.pipe_objs
        del self.root
        del self.renwin
	self.tkwidget.destroy()
	self.frame.destroy ()

    def no_quit (self, event=None):
        debug ("In RenderWindow::no_quit ()")
        msg = "Sorry! You cannot delete this window without exiting "\
              "the application."
        tkMessageBox.showerror ("ERROR", msg)

    def lift (self): 
	"Lift the window to the top. Useful for scene dumps."
        debug ("In RenderWindow::lift ()")
        top = self.frame.winfo_toplevel ()
	top.deiconify ()
	top.lift ()
	self.frame.update_idletasks ()
	self.Render ()

    def Render (self): 
        debug ("In RenderWindow::Render ()")
	self.renwin.Render ()

    def GetActiveCamera (self):
        debug ("In RenderWindow::GetActiveCamera ()")
        return self.camera

    def get_active_camera (self):
        debug ("In RenderWindow::get_active_camera ()")
        return self.camera

    def get_renderer (self): 
        debug ("In RenderWindow::get_renderer ()")
	return self.ren

    def get_render_window (self): 
        debug ("In RenderWindow::get_render_window ()")
	return self.renwin

    def get_vtk_render_window (self): 
        debug ("In RenderWindow::get_vtk_render_window ()")
	return self.renwin

    def set_background (self, clr=Common.config.bg_color): 
        debug ("In RenderWindow::set_background ()")
	apply (self.ren.SetBackground, clr)
	#self.Render ()

    def save_config (self, file): 
        "Save the current configuration to file."
        debug ("In RenderWindow::save_config ()")
        p = vtkPipeline.vtkMethodParser.VtkPickler ()
        for obj in (self.ren, self.camera):
            p.dump (obj, file)

    def load_config (self, file): 
        "Load the saved configuration from a file."
        debug ("In RenderWindow::load_config ()")
        p = vtkPipeline.vtkMethodParser.VtkPickler ()
        for obj in (self.ren, self.camera):
            p.load (obj, file)

    def config_changed (self): 
        debug ("In RenderWindow::config_changed ()")
        self.set_background (Common.config.bg_color)

    def make_custom_gui (self):
        debug ("In RenderWindow::configure ()")
        self.make_pipeline_gui ()
        self.make_main_gui ()
        self.make_close_button ()
        
    def make_main_gui (self):
        debug ("In RenderWindow::make_main_gui ()")
        frame = Tkinter.Frame (self.root, relief='ridge', bd=2)
        frame.pack (side='top', fill='both', expand=1)
        but = Tkinter.Button (frame, text="Configure RenderWindow",
                              command=self.config_renwin)
        but.pack (side='top')
        but = Tkinter.Button (frame, text="Configure Renderer",
                              command=self.config_ren)
        but.pack (side='top')
        but = Tkinter.Button (frame, text="Configure Camera",
                              command=self.config_camera)
        but.pack (side='top')
        
    def config_renwin (self, event=None):
        debug ("In RenderWindow::config_renwin ()")
        c = vtkPipeline.ConfigVtkObj.ConfigVtkObj (self.renwin)
        c.configure (self.root, self.renwin)

    def config_ren (self, event=None):
        debug ("In RenderWindow::config_ren ()")
        c = vtkPipeline.ConfigVtkObj.ConfigVtkObj (self.renwin)
        c.configure (self.root, self.ren)

    def config_camera (self, event=None):
        debug ("In RenderWindow::config_camera ()")
        c = vtkPipeline.ConfigVtkObj.ConfigVtkObj (self.renwin)
        c.configure (self.root, self.camera)

