#############################################################################
#
# Author: Anna Omelchenko
#
# Copyright: M. Sanner TSRI
#
#############################################################################

#
#$Header: /opt/cvs/Volume/Pvv/voltransformCommands.py,v 1.2 2007/12/04 21:27:54 vareille Exp $
#
#$Id: voltransformCommands.py,v 1.2 2007/12/04 21:27:54 vareille Exp $
#
"""Module implements a command to allow the user to scale and translate
the volume geometry object along X, Y and Z axes.
The command sets the modeling transformation matrix.
The GUI: The user can choose to scale or translate
the volume object by pressing a corresponding radio button.
The amount to scale or move the object in each direction can
be specified either by typing X, Y, Z values in the provided entry fields
or by rotating the thumb wheels."""

from ViewerFramework.VFCommand import Command, CommandGUI
from mglutil.gui.InputForm.Tk.gui import InputFormDescr
from mglutil.gui.BasicWidgets.Tk.thumbwheel import ThumbWheel
from mglutil.util.misc import ensureFontCase
import Tkinter, Pmw
volGeom = None

class volTransformation(Command):
    """Command to allow the user to scale and translate
    the volume geometry object along X, Y and Z axes."""

    def __init__(self):
        Command.__init__(self)
        self.isDisplayed = 0
        self.currentScale = [1.0, 1.0, 1.0]
        self.currentTranslation = [0.0, 0.0, 0.0]
        self.idf = None
        self.form = None
        self.oldxyz = 0.0
        
    def onAddCmdToViewer(self):
        """Called when the command is loaded (added) to the viewer.""" 
        self.Xval = Tkinter.StringVar()
        self.Yval = Tkinter.StringVar()
        self.Zval = Tkinter.StringVar()
        self.switch = Tkinter.StringVar()
        self.switch.set('scale')
        self.val_list = [self.Xval, self.Yval, self.Zval]

    def guiCallback(self):
        """Creates/deiconifies the input form (GUI). Called every time
        the 'Volume Transformation' button from the main menu is pressed."""
        if self.isDisplayed: return
        self.isDisplayed=1
        self.getObjTransform()
        if self.form:
            self.form.deiconify()
            self.set_values()
            return
        
        if self.switch.get() == 'scale':
            values = self.currentScale
            minval = 0.1
        else :
            values = self.currentTranslation
            minval = None
        self.Xval.set("%.2f"%values[0])
        self.Yval.set("%.2f"%values[1])
        self.Zval.set("%.2f"%values[2])

        idf = self.idf = InputFormDescr(title = 'Set Volume Transformation')
        ew = 8
        pad = 10
       
        idf.append({'widgetType': Tkinter.Radiobutton,
                    'name': 'scale',
                    'wcfg': {'text': 'Scale',
                             'variable': self.switch,
                             'value': 'scale',
                             'command': self.set_values},
                    'gridcfg': {'column':0, 'row': 0,
                                'sticky': 'e'}
                    })
        idf.append({'widgetType': Tkinter.Radiobutton,
                    'name': 'translate',
                    'wcfg': {'text': 'Translate',
                             'variable': self.switch,
                             'value': 'translate',
                             'command': self.set_values},
                    'gridcfg': {'column':1, 'row': 0,
                                'sticky': 'w'}
                    })

        idf.append({'widgetType':Pmw.EntryField,
                    'name':'x',
                    'wcfg':{'labelpos':'w',
                            'label_text':'X  : ',
                            'entry_width': ew,
                            'validate':'real',
                            'entry_textvariable':self.Xval,
                            'command':self.set_xtransform},
                    'gridcfg':{'column':0,'row':1,'sticky':'w'}})
        idf.append({'name': 'xwheel',
                    'wtype':ThumbWheel,
                    'widgetType':ThumbWheel,
                    'wcfg':{'label':0,
                            'showLabel':0, 'width':100,
                            'wheelLabcfg1':{'font':(ensureFontCase('times'),14,'bold')},
                            'wheelLabcfg2':{'font':(ensureFontCase('times'),14,'bold')},
                            'canvascfg':{'bg':'red'},
                            'min': minval,
                            'value': values[0],
                            'continuous':1, 'oneTurn':10, 'wheelPad':2,
                            'height':20,
                            'callback': self.set_xtransform},
                    'gridcfg':{'sticky':'w','row':-1,
                               'column':1,}})
        idf.append({'widgetType':Pmw.EntryField,
                    'name':'y',
                    'wcfg':{'labelpos':'w',
                            'label_text':'Y  : ',
                            'entry_width': ew,
                            'validate':'real',
                            'entry_textvariable':self.Yval,
                            'command':self.set_ytransform},
                    'gridcfg':{'column':0,'row':2,'sticky':'w'}})
        idf.append({'name': 'ywheel',
                    'wtype':ThumbWheel,
                    'widgetType':ThumbWheel,
                    'wcfg':{'label':0,
                            'showLabel':0, 'width':100,
                            'canvascfg':{'bg':'green'},
                            'wheelLabcfg1':{'font':(ensureFontCase('times'),14,'bold')},
                            'wheelLabcfg2':{'font':(ensureFontCase('times'),14,'bold')},
                            'min': minval,
                            'value':values[1],
                            'continuous':1, 'oneTurn':10, 'wheelPad':2,
                            'height':20,
                            'callback': self.set_ytransform},
                    'gridcfg':{'sticky':'w','row':-1,
                               'column':1,}})
        idf.append({'widgetType':Pmw.EntryField,
                    'name':'z',
                    'wcfg':{'labelpos':'w',
                            'label_text':'Z  : ',
                            'entry_width': ew,
                            'validate':'real',
                            'entry_textvariable':self.Zval,
                            'command':self.set_ztransform},
                    'gridcfg':{'column':0,'row':3, 'sticky':'w'}})
        idf.append({'name': 'zwheel',
                    'wtype':ThumbWheel,
                    'widgetType':ThumbWheel,
                    'wcfg':{'label':0,
                            'showLabel':0, 'width':100,
                            'canvascfg':{'bg':'blue'},
                            'wheelLabcfg1':{'font':(ensureFontCase('times'),14,'bold')},
                            'wheelLabcfg2':{'font':(ensureFontCase('times'),14,'bold')},
                            'min':minval ,
                            'value':values[2],
                            'continuous':1, 'oneTurn':10, 'wheelPad':2,
                            'height':20,
                            'callback': self.set_ztransform},
                    'gridcfg':{'sticky':'w','row':-1,
                               'column':1,}})
        idf.append({'widgetType': Tkinter.Label,
                    'wcfg':{'text': 'XYZ: '},
                    'gridcfg': {'row': 4, 'column': 0, 'sticky':'w'}
                    })
        idf.append({'name': 'xyzwheel',
                    'wtype':ThumbWheel,
                    'widgetType':ThumbWheel,
                    'wcfg':{'label':0,
                            'showLabel':0, 'width':100,
                            'wheelLabcfg1':{'font':(ensureFontCase('times'),14,'bold')},
                            'wheelLabcfg2':{'font':(ensureFontCase('times'),14,'bold')},
                            #'min': minval,
                            'value': 0.0,
                            'continuous':1, 'oneTurn':10, 'wheelPad':2,
                            'height':20,
                            'callback': self.set_xyztransform},
                    'gridcfg':{'sticky':'w','row':-1,
                               'column':1,}})        
        
        idf.append({'widgetType':Tkinter.Button,
                    'wcfg': {'text': 'Reset',
                             'relief' : Tkinter.RAISED,
                             'borderwidth' : 3,
                             'command': self.reset_cb},
                    'gridcfg':{'columnspan':1,'column':0,
                               'sticky':'ew'},
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'wcfg': {'text': 'Dismiss',
                             'relief' : Tkinter.RAISED,
                             'borderwidth' : 3,
                             'command':self.dismiss_cb},
                    'gridcfg':{'columnspan':1,'column':1,
                               'row':-1, 'sticky':'ew'},
                    })
        
        self.form = self.vf.getUserInput(idf, modal = 0, blocking=0)
        ebn = idf.entryByName
        self.xwheel = ebn['xwheel']['widget']
        self.ywheel = ebn['ywheel']['widget']
        self.zwheel = ebn['zwheel']['widget']
        self.wheels = [self.xwheel, self.ywheel, self.zwheel]
        xyzwheel = self.xyzwheel = ebn['xyzwheel']['widget']
        self.xyzwheel.canvas.bind('<ButtonRelease-1>', self.reset_xyzwheel)

    def getObjTransform(self):
        """Get current scale and translation of the volume object."""
        # Has to be implemented by a derived class
        pass

        
    def set_values(self):
        """Called when 'Scale' or 'Translate' radiobutton is
        pressed. Updates the input form (GUI) to show values
        corresponding to selected transformation.""" 
        ebn = self.idf.entryByName
        if self.switch.get() == 'scale':
            values = self.currentScale
            minval = 0.1
        else:
            values = self.currentTranslation
            minval = None
        self.Xval.set("%.2f"%values[0])
        self.Yval.set("%.2f"%values[1])
        self.Zval.set("%.2f"%values[2])
        i = 0
        for w in self.wheels:
            w.setValue(values[i])
            w.configure(min = minval)
            i = i+1

    def set_xtransform(self, val = None):
        """Gets X value from the input form and applies
        appropriate transformation to the object. """
        if val == None:
            val = float(self.Xval.get())
            #self.xscwheel.value = val
            self.xwheel.setValue(val)
        else:
            self.Xval.set('%.2f'%val)
        if self.switch.get() == 'scale':
            self.currentScale[0] = val
            self.doitWrapper(scale = self.currentScale, log = 0)
        else:
            self.currentTranslation[0] = val
            self.doitWrapper(translate = self.currentTranslation, log = 0)

    def set_ytransform(self, val = None):
        """Gets Y value from the input form and applies
        appropriate transformation to the object. """
        if val == None:
            val = float(self.Yval.get())
            self.ywheel.setValue(val)
        else:
            self.Yval.set('%.2f'%val)
        if self.switch.get() == 'scale':
            self.currentScale[1] = val
            self.doitWrapper(scale = self.currentScale, log = 0)
        else:
            self.currentTranslation[1] = val
            self.doitWrapper(translate = self.currentTranslation, log = 0)

    def set_ztransform(self, val = None):
        """Gets Z value from the input form and applies
        appropriate transformation to the object. """
        if val == None:
            val = float(self.Zval.get())
            self.zwheel.setValue(val)
        else:
            self.Zval.set('%.2f'%val)
        if self.switch.get() == 'scale':
            self.currentScale[2] = val
            self.doitWrapper(scale = self.currentScale, log = 0)
        else:
            self.currentTranslation[2] = val
            self.doitWrapper(translate = self.currentTranslation, log = 0)

    def set_xyztransform(self, val = None):
        """Gets XYZ value from the input form and applies
        appropriate transformation to the object. """
        d = val - self.oldxyz
        if self.switch.get() == 'scale':
            scale = self.currentScale
            for i in range(3):
                scale[i] = scale[i]+d
                if scale[i] <0.1 : scale[i] = 0.1
                self.val_list[i].set("%.2f"%scale[i])
                #self.wheels[i].setValue(scale[i])
            self.doitWrapper(scale = scale, log= 0)
        else:
            transl = self.currentTranslation
            for i in range(3):
                transl[i] = transl[i]+d
                self.val_list[i].set("%.2f"%transl[i])
                #self.wheels[i].setValue(transl[i])
            self.doitWrapper(translate = transl, log = 0)
        self.oldxyz = val

    def reset_xyzwheel(self, event):
        """Sets XYZ thumbwheel value to zero. """
        self.xyzwheel.setValue(0.0)
        self.oldxyz = 0.0
        if self.switch.get() == 'scale':
            values = self.currentScale
        else:
            values = self.currentTranslation
        i = 0
        for w in self.wheels:
            w.setValue(values[i])
            i = i + 1

##      def setupUndoBefore(self, scale=None, translate=None, **kw):
##            svs = self.vf.vliTransform
##            scale= self.currentScale
##            translate = self.currentTranslation
##            self.addUndoCall((scale, translate), {}, svs.name)

    def doit(self, scale=None, translate=None, **kw):
        """Applies the user specified transformation to the volume object."""
        if scale:
            volGeom.Set(volscale = scale)
            self.currentScale = scale
        if translate:
            volGeom.Set(voltranslate = translate)
            self.currentTranslation = translate
        self.vf.GUI.VIEWER.Redraw()

    def __call__(self, scale=None, translate=None, **kw):
        """None <- vliTransform(scale=None, translate=None)
        scale: a tuple-(x,y,z)-the amount to scale the volume
        object in each direction;
        translate: a tuple-(x,y,z)-the amount to translate the volume
        object in each direction;
        """
        if scale :
            scale = list(scale)
            assert len(scale) == 3
            self.currentScale = scale
        if translate:
            translate =list(translate)
            assert len(translate) == 3
            self.currentTranslation = translate
        apply(self.doitWrapper, (scale, translate), kw)
        
        if self.isDisplayed :
            if scale and self.switch.get() == 'scale':
                self.updateGUI(scale)
            if translate and self.switch.get() == 'translate':
                self.updateGUI(translate)

    def updateGUI(self, vals):
        """Updates the input form with given scale or translation values."""
        for i in range(3):
            self.val_list[i].set("%.2f"%vals[i])
            self.wheels[i].setValue(vals[i])
    
    def dismiss_cb(self):
        """Withdraws the GUI."""
        #self.idf.form.destroy()
        self.idf.form.withdraw()
        self.isDisplayed=0
        #self.idf = None

    def reset_cb(self):
        """Called when 'Reset' button is pressed. Resets scale to
        (1., 1., 1.) or translation to (0., 0., 0.)."""
        
        if self.switch.get() == "scale":
            scale = [1.0, 1.0, 1.0]
            self.currentScale = scale
            self.doitWrapper(scale = scale)
            self.updateGUI(scale)
        else:
            translate = [0.0, 0.0, 0.0]
            self.doitWrapper(translate = translate)
            self.currentTranslation = translate
            self.updateGUI(translate)
        self.vf.GUI.VIEWER.Redraw()


class VLITransformation(volTransformation):
    """Command to allow the user to scale and translate
    VLI volume geometry object along X, Y and Z axes."""
    
    def getObjTransform(self):
        """Get object's current scale and translation."""
        if volGeom.vliScalemat:
            self.currentScale = [volGeom.vliScalemat[0][0],
                                 volGeom.vliScalemat[1][1],
                                 volGeom.vliScalemat[2][2]]
        if volGeom.vliTranslate:
            self.currentTranslation = [volGeom.vliTranslate[0][3],
                                       volGeom.vliTranslate[1][3],
                                       volGeom.vliTranslate[2][3]]


class UTVolRenTransformation(volTransformation):
    """Command to allow the user to scale and translate
    OpenGL based ( Univ. of Texas Volume Library) volume geometry object
    along X, Y and Z axes."""
    
    def getObjTransform(self):
        """Get object's current scale and translation."""
        self.currentScale = volGeom.scale
        self.currentTranslation = volGeom.translation

                
commandGUI = CommandGUI()
menuName ='Volume Transformation'
menuIndex = 6
commandNames = {'vli': 'VLITransformation', 'utvolren':'UTVolRenTransformation'}
commandList = [{'name':'', 'cmd':None, 'gui': None}]


def initModule(viewer):
    for dict in commandList:
        if dict['name']:
            viewer.addCommand(dict['cmd'], dict['name'], dict['gui'])
