## Automatically adapted for numpy.oldnumeric Jul 23, 2007 by 

#############################################################################
#
# Author: Anna Omelchenko, Michel F. SANNER
#
# Copyright: M. Sanner TSRI
#
#############################################################################

#
#$Header: /opt/cvs/Volume/Pvv/zoomvolumeCommands.py,v 1.2 2007/07/24 17:30:45 vareille Exp $
#
#$Id: zoomvolumeCommands.py,v 1.2 2007/07/24 17:30:45 vareille Exp $
#
"""Module implementing a command that enables the user to navigate
through large data volumes by choosing a subvolume from a lower
resolution dataset (with a crop box or a geometry box) followed by
loading (zoomming in) that part of data from a higher resolution
dataset into the viewer as a new volume.
The command uses VisTools Mesh API wrapped in Python.
The datasets file names, the lowest resolution number, the cache and
page sizes have to be provided by the user in a separate text file(currently
with .data extension).
Current limitations:
- the lowest resolution number must be a power of two;
- the resolution ratio between two consequent datafiles has
  to be equaled to 2;
- the number of datafiles must correspond to the given lowest
  resolution (e.g., if lowest_resolution == 8 then number_files = 4);
- the datafile names must be given in the resolution increasing order ,
  starting from the file with the lowest resolution(no order check is done);
- the data length must be 8 bit;
- .vols datafile format is supported (SDSC 'VOL' volume file format;
   info at http://vistools.npaci.edu/Documentation/C++Doc/Formats/index.html)
An example of .data file:
 Lowest Resolution 8
 File brain_stride_8_int.vols
 Page Size 14803
 Cache Size 1391485
 File brain_stride_4_int.vols
 Page Size 59474
 Cache Size 11181112
 File brain_stride_2_int.vols
 Page Size 238875
 Cache Size 30000000
 File brain_full_size_int.vols
 Page Size 1048576
 Cache Size 64000000
 scale 1.5 1.0 1.0
"""

from ViewerFramework.VFCommand import Command, CommandGUI
from mglutil.gui.InputForm.Tk.gui import InputFormDescr, InputForm
from mglutil.gui.BasicWidgets.Tk.customizedWidgets import SliderWidget
import Tkinter, time, thread
from math import log
import numpy.oldnumeric as Numeric, string, os
from ZoomBox import ZoomBox
from SimpleDialog import SimpleDialog
try:
    from Volume.IO.Mesh.MeshVolume import MeshVolume
except:
    pass
try:
    from Volume.Renderers.VLI import vli
except:
    pass
from DejaVu.Box import Box

labelFont = '-*-Helvetica-Bold-R-Normal-*-*-180-*-*-*-*-*-*'
numberFont = '-*-Helvetica-Bold-R-Normal-*-*-160-*-*-*-*-*-*'
MAXDIM = 256
MAXBOXDIM = 128

volGeom =None

class Zoom(Command):
    """Command to zoom through a number of volume datasets."""
    
    def __init__(self):
        Command.__init__(self)
        self.isDisplayed=0
        #self.form = None
        self.resol = 8
        self.lowestresol = 8
        self.volumes = []
        self.initValues()
        self.check = 0
        self.parentBox = None


    

    def initValues(self):
        """Set the initial values."""
        self.isSubform = 0
        self.form = None
        self.idf = None
        self.subidf = None
        self.subform = None
        self.isWithdrawn = 0
        self.volsizes = {}
        self.zoomboxes = {}
        self.bounds_dict = {}
        self.newVolume = 0
        self.currentVolume = 0 # meaning lowest resolution file
        self.firstUse = 1
        self.currTool = 'crop'
        volGeom.volumesizes = []
        volGeom.cropBox_list = []
        self.getresol = Tkinter.IntVar()
        self.getresol.set(0)
        self.switch = Tkinter.StringVar()
        self.switch.set('crop')
        self.showbox = Tkinter.IntVar()
        self.mode = Tkinter.StringVar()
        self.mode.set('zoom')
        self.currentMode = 'zoom'
        self.datafile = None
        
    def onAddCmdToViewer(self):
        """Called when the command is loaded (added) to the viewer. """
        cropBox = volGeom.cropBox
        cropBox.callbackFunc.append(self.updateInfo)
        self.zoomBox = ZoomBox(self.vf.GUI.VIEWER, volGeom)
        self.zoomBox.callbackFunc.append(self.updateInfo)
        self.zoomTools = {'crop':cropBox, 'box':self.zoomBox}
        

        
    def updateInfo(self, zoomTool):
        """updates crop box info on the input form"""        
        if self.form==None: return
        if zoomTool != self.zoomTools[self.currTool]: return
        ent = self.form.descr.entryByName
        ent['wx']['widget'].configure(text=zoomTool.dx)
        ent['wy']['widget'].configure(text=zoomTool.dy)
        ent['wz']['widget'].configure(text=zoomTool.dz)
        ent['minx']['widget'].configure(text=zoomTool.xmin)
        ent['maxx']['widget'].configure(text=zoomTool.xmax)
        ent['miny']['widget'].configure(text=zoomTool.ymin)
        ent['maxy']['widget'].configure(text=zoomTool.ymax)
        ent['minz']['widget'].configure(text=zoomTool.zmin)
        ent['maxz']['widget'].configure(text=zoomTool.zmax)

        disable = 0
        if self.currentMode == 'zoom':
            maxboxside = MAXBOXDIM
            #fg='#FF0000'
            if self.isSubform:
                nextresol = self.getresol.get()
                if nextresol and nextresol < self.resol:
                    maxboxside = MAXDIM/(self.resol/nextresol)
        else: # self.currentMode == 'move'
            maxboxside = MAXDIM
        if zoomTool.dx > maxboxside:
            disable = 1
            ent['wx']['widget'].configure(fg='red')
            
        else:
            ent['wx']['widget'].configure(fg='#000000')

        if zoomTool.dy > maxboxside:
            disable = 1
            ent['wy']['widget'].configure(fg='green')
        else:
            ent['wy']['widget'].configure(fg='#000000')

        if zoomTool.dz > maxboxside:
            disable = 1
            ent['wz']['widget'].configure(fg='blue')
        else:
            ent['wz']['widget'].configure(fg='#000000')
        if self.currentMode == 'zoom':
            if disable :
                ent['reduce_to_zoom']['widget'].configure(state=Tkinter.NORMAL)
            else:
                ent['reduce_to_zoom']['widget'].configure(state=Tkinter.DISABLED)

            if disable or self.currentVolume == len(self.volumes)-1:
                ent['zoomin']['widget'].configure(state=Tkinter.DISABLED)
            else:
                ent['zoomin']['widget'].configure(state=Tkinter.NORMAL)

            if self.currentVolume == 0:
                ent['zoomout']['widget'].configure(state=Tkinter.DISABLED)
            else:
                ent['zoomout']['widget'].configure(state=Tkinter.NORMAL)
        else:
            
            if disable:
                ent['reduce_to_move']['widget'].configure(state=Tkinter.NORMAL)
                ent['getvolume']['widget'].configure(state=Tkinter.DISABLED)
            else:
                ent['reduce_to_move']['widget'].configure(state=Tkinter.DISABLED)
                ent['getvolume']['widget'].configure(state=Tkinter.NORMAL)
            

    def guiCallback(self):
        """Pops up file brawser to specify data filename(if loading new
        data). Creates the GUI for zooming."""
        if self.isDisplayed:
            self.idf.form.lift()
            return
        if not self.vvInitialized():
            self.vf.warningMsg("Warning: startPmvCommands module is not loaded")
            return
        root = Tkinter.Toplevel()
        root.withdraw()
        ans = SimpleDialog(root, text="Load new data?",
                           buttons=["Yes", "No", "Cancel"],
                           default=0,
                           title="new data dialog").go()
        root.destroy()
        if ans == 1 and self.isWithdrawn:
            self.idf.form.deiconify()
            self.isWithdrawn = 0
            self.isDisplayed=1
            return
        elif ans == 1 and self.form == None:
            if len(self.volumes)==0:
                return
            else :
                self.buildForm()
        elif ans == 2:
            return
        elif ans == 0:
            #self.isDisplayed=1
            file = self.vf.askFileOpen(types=[('Data Files', '*.data')])
            if file:
                self.doitWrapper(newdata = file)
                if self.check:
                    self.buildForm()
                    self.isDisplayed = 1
                    
    def parseData(self, filename):
        """reads .data file, extracts data info used in zooming"""
        f = open(filename)
        line = f.readline()
        resol = 0
        files = []
        cs = []
        mps = []
        scale = (1.0, 1.0, 1.0)
        while line != "":
            if line != "\n":
                l = string.split(line)
                if string.find(l[0], "#") == 0:
                    line = f.readline()
                    continue
                elif l[0] == "Lowest":
                    resol = int(l[-1])
                elif l[0] == "File":
                    files.append(l[-1])
                elif l[0] == "Cache":
                    cs.append(int(l[-1]))
                elif l[0] == "Page" :
                    mps.append(int(l[-1]))
                elif l[0] == "scale" :
                    if len(l) < 4:
                        print "wrong format for scale; expected: scale float float float"
                    else:
                        scale = (float(l[1]), float(l[2]), float(l[3]))
            line = f.readline()
        return resol, files, cs, mps, scale

    def checkData(self, resol, files, cs, mps):
        """Checks info from .data file:
        resol - the lowest data resolution has to be power of 2;
        number of files(nfiles = len(files) ) has to correspond
        to resol( 2**(nfiles-1)=resol; e.g. resol = 8, nfiles = 4)."""
        nfiles = 1
        r = resol
        while r > 1:
            r, c = divmod(r,2)
            if c !=0:
                text = "lowest resolution(%d) must be power of 2"\
                   %(resol,)
                self.displayMessage(text,"Data input error ")
                return 0
            nfiles = nfiles + 1
            nf = len(files)
        if nfiles != nf:
            text = "%d files expected, %d given"%(nfiles, nf)
            self.displayMessage(text,"Data input error ")
            return 0
        ncs = len(cs)
        if nfiles != ncs:
            text = "cache sizes given for %d files, %d expected "%(ncs, nfiles)
            self.displayMessage(text,"Data input error ")
            return 0
        nmps = len(mps)
        if nfiles != nmps:
            text = "page sizes given for %d files, %d expected "%(nmps, nfiles)
            self.displayMessage(text,"Data input error ")
            return 0
        for file in files:
            if not os.path.exists(file):
                text = "File %s does not exist"%file
                self.displayMessage(text,"Data input error")
                return 0
            if os.path.splitext(file)[-1] != '.vols':
                text = "Expected .vols file; got file %s"%file
                self.displayMessage(text,"Data input error")
                return 0
        return 1
        

    def displayMessage(self, text, title):
        """Creates and displays a message dialog."""
        
        root = Tkinter.Toplevel()
        root.withdraw()
        ans = SimpleDialog(root, text=text,
                           buttons=["OK"], default=0,
                           title=title).go()
        root.destroy()
        
    def buildForm(self):
        """Builds the input form (GUI). """
        idf = self.idf = InputFormDescr(title = 'Zoom Volume')
##          self.switch = Tkinter.StringVar()
##          self.showbox = Tkinter.IntVar()

        crop = volGeom.cropBox 
        wx, wy, wz = crop.dx, crop.dy, crop.dz
        xmin, ymin, zmin = crop.xmin, crop.ymin, crop.zmin
        xmax, ymax, zmax = crop.xmax, crop.ymax, crop.zmax

        self.zoomBox.setVolSize(volGeom.volumeSize)
        self.zoomBox.setScale()
        self.zoomBox.xmin=xmin
        self.zoomBox.xmax = xmax
        self.zoomBox.ymin = ymin
        self.zoomBox.ymax = ymax
        self.zoomBox.zmin = zmin
        self.zoomBox.zmax = zmax
        self.zoomBox.update()
            
        idf.append({'widgetType':Tkinter.Label,
                    'wcfg':{'text':'Level :', 'font':labelFont},
                    'gridcfg':{'column':0,'row':0,'sticky':'w'}
                    })
        
        idf.append({'widgetType':Tkinter.Label,
                    'name':'level',
                    'wcfg':{'text':str(self.currentVolume+1),
                            'font':numberFont},
                    'gridcfg':{'row':0,'column':1,'sticky':'w'}
                    })

        idf.append({'widgetType': Tkinter.Radiobutton,
                    'wcfg':{'font':numberFont,
                            'text':'zoom',
                            'value': 'zoom',
                            'variable': self.mode,
                            'command': self.setMode},
                    'gridcfg':{'column':0,'sticky':'w' ,'columnspan':2},
                    })
        idf.append({'widgetType': Tkinter.Radiobutton,
                    'direction':'col',
                    'wcfg':{'font':numberFont,
                            'text':'move',
                            'value': 'move',
                            'variable': self.mode,
                            'command': self.setMode},
                    'gridcfg':{'column':2,'sticky':'w','row':-1, 'columnspan':2},
                    })
        self.mode.set('zoom')

        idf.append({'widgetType':Tkinter.Label,
                    'name':'selectby',
                    'wcfg':{'text':'Select subvolume by:',
                            'font':numberFont},
                    'gridcfg':{'column':0, 'row': 2,'columnspan':4,
                               'sticky':'w'}
                    }) 
        idf.append({'widgetType': Tkinter.Radiobutton,
                    'name': 'crop',
                    'wcfg':{'font':numberFont,
                            'text':'crop',
                            'value': 'crop',
                            'variable': self.switch,
                            'command': self.setZoomTool},
                    'gridcfg':{'column':0, 'row': 3,'sticky':'w' ,'columnspan':2},
                    })
        idf.append({'widgetType': Tkinter.Radiobutton,
                    'name': 'box',
                    'direction':'col',
                    'wcfg':{'font':numberFont,
                            'text':'box',
                            'value': 'box',
                            'variable': self.switch,
                            'command': self.setZoomTool},
                    'gridcfg':{'column':2,'sticky':'w','row': 3, 'columnspan':2},
                    })
        #self.switch.set('crop')

        idf.append({'widgetType':Tkinter.Checkbutton,
                    'name': 'showbox',
                    'wcfg':{'font': numberFont,
                            'text': 'show box',
                            'variable': self.showbox,
                            'command': self.showZoomBox},        
                    'gridcfg':{'column':0, 'columnspan':2,
                               'sticky':'w'}
                    })
        self.showbox.set(0)
        self.volumeboxvar = Tkinter.IntVar()
        self.volumeboxvar.set(0)
        idf.append({'widgetType':Tkinter.Checkbutton,
                    'name':'volumebox',
                    'wcfg':{'text':'all outlines',
                            'variable':self.volumeboxvar,
                            'font': numberFont,
                            'command':self.volumeboxes_onoff_cb},
                    'gridcfg':{'row':-1, 'column':2,
                               'columnspan':2, 'sticky':'w'},
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'name':'resetcrop',
                    'wcfg':{'borderwidth':2,
                            'text':'reset crop',
                            'font': numberFont,
                            'command': self.reset_crop},
                    'gridcfg':{'column':0,
                               'columnspan':2,
                               'sticky': 'w'},
                    })
        
        idf.append({'widgetType':Tkinter.Button,
                    'name':'resetbox',
                    'wcfg':{'borderwidth':2,
                            'text':'reset box',
                            'font': numberFont,
                            'command': self.reset_box},
                    'gridcfg':{'row':-1, 'column':2,
                               'columnspan':2,
                               'sticky': 'w'}
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'name':'reduce_to_move',
                    'wcfg':{'borderwidth':4, #'width':16,'height':2,
                            'text':'Reduce To Move',
                            'disabledforeground':'#CCCCCC',
                            'font':labelFont,
                            'command': self.reduce_to_move},
                    'gridcfg':{'column':0, 'row':6,'columnspan':4,'sticky':'ew'},
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'name':'max_move_box',
                    'wcfg':{'borderwidth':4, #'width':16,'height':2,
                            'text':'Max Movable Box',
                            'disabledforeground':'#CCCCCC',
                            'font':labelFont,
                            'command': self.max_move_box},
                    'gridcfg':{'column':0, 'row':7,'columnspan':4,'sticky':'ew'},
                    })
        
        idf.append({'widgetType':Tkinter.Button,
                    'name':'reduce_to_zoom',
                    'wcfg':{'borderwidth':4, #'width':16,'height':2,
                            'text':'Reduce To Zoom',
                            'disabledforeground':'#CCCCCC',
                            'font':labelFont,
                            'command': self.reduce_to_zoom},
                    'gridcfg':{'column':0, 'row':6,'columnspan':4,'sticky':'ew'},
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'name':'max_zoom_box',
                    'wcfg':{'borderwidth':4, #'width':16,'height':2,
                            'text':'Max Zoomable Box',
                            'disabledforeground':'#CCCCCC',
                            'font':labelFont,
                            'command': self.max_zoom_box},
                    'gridcfg':{'column':0, 'row':7,'columnspan':4,'sticky':'ew'},
                    })

        maxboxside = MAXBOXDIM
        if self.isSubform:
            nextresol = self.getresol.get()
            if nextresol:
                maxboxside = MAXDIM/(self.resol/nextresol)
                
        idf.append({'widgetType':Tkinter.Label,
                    'wcfg':{'text':'width', 'font':labelFont},
                    'gridcfg':{'column':0, 'sticky':'w'}})
        if wx > maxboxside: col = 'red'
        else: col = '#000000'    
        idf.append({'widgetType':Tkinter.Label,
                    'name':'wx',
                    'wcfg':{'text':str(wx), 'fg':col,
                            'font':numberFont},
                    'gridcfg':{'column':1,'row':-1,'sticky':'e'}})
        if wy > maxboxside: col = 'green'
        else: col = '#000000'    
        idf.append({'widgetType':Tkinter.Label,
                    'name':'wy',
                    'wcfg':{'text':str(wy), 'fg':col,
                            'font':numberFont},
                    'gridcfg':{'column':2,'row':-1,'sticky':'e'}})
        if wz > maxboxside: col = 'blue'
        else: col = '#000000'    
        idf.append({'widgetType':Tkinter.Label,
                    'name':'wz',
                    'wcfg':{'text':str(wz), 'fg':col,
                            'font':numberFont},
                    'gridcfg':{'column':3,'row':-1,'sticky':'e'}})
        
        idf.append({'widgetType':Tkinter.Label,
                    'wcfg':{'text':'min', 'font':labelFont},
                    'gridcfg':{'column':0,'sticky':'w'}})
        idf.append({'widgetType':Tkinter.Label,
                    'name':'minx',
                    'wcfg':{'text':str(xmin),
                            'font':numberFont},
                    'gridcfg':{'column':1,'row':-1,'sticky':'e'}})
        idf.append({'widgetType':Tkinter.Label,
                    'name':'miny',
                    'wcfg':{'text':str(ymin),
                            'font':numberFont},
                    'gridcfg':{'column':2,'row':-1,'sticky':'e'}})
        idf.append({'widgetType':Tkinter.Label,
                    'name':'minz',
                    'wcfg':{'text':str(zmin),
                            'font':numberFont},
                    'gridcfg':{'column':3,'row':-1,'sticky':'e'}})
        
        idf.append({'widgetType':Tkinter.Label,
                    'wcfg':{'text':'max', 'font':labelFont},
                    'gridcfg':{'column':0, 'sticky':'w'}})
        idf.append({'widgetType':Tkinter.Label,
                    'name':'maxx',
                    'wcfg':{'text':str(xmax),
                            'font':numberFont},
                    'gridcfg':{'column':1,'row':-1,'sticky':'e'}})
        idf.append({'widgetType':Tkinter.Label,
                    'name':'maxy',
                    'wcfg':{'text':str(ymax),
                            'font':numberFont},
                    'gridcfg':{'column':2,'row':-1,'sticky':'e'}})
        idf.append({'widgetType':Tkinter.Label,
                    'name':'maxz',
                    'wcfg':{'text':str(zmax),
                            'font':numberFont},
                    'gridcfg':{'column':3,'row':-1,'sticky':'e'}})

        idf.append({'name':'linewidth',
                    'widgetType': SliderWidget,
                    'wcfg':{'label':'Line width',
                            'minval':1, 'maxval': 10,'incr':1,
                            'labelsCursorFormat':'%2d',
                            'sliderType': 'int',
                            'height': 15,
                            'width':100, 'left':10, 'right':10,
                            'immediate':1,
                            'command': self.setLineWidth},
                    'gridcfg': {'column':0, 'columnspan':4, 'sticky':'w'}}) 

        idf.append({'widgetType':Tkinter.Button,
                    'name':'getvolume',
                    'wcfg':{'borderwidth':4, #'width':10,'height':2,
                            'text':'Get New Volume',
                            'disabledforeground':'#CCCCCC',
                            'font': labelFont,
                            'command': self.getvolume_callback},
                    'gridcfg':{'column':0,'row':12,'columnspan':4, 'sticky':'ew'},
                    })

        idf.append({'widgetType':Tkinter.Button,
                    'name':'zoomin',
                    'wcfg':{'borderwidth':4, #'width':10,'height':2,
                            'text':'Zoom In',
                            'disabledforeground':'#CCCCCC',
                            'font': labelFont,
                            'command': self.zoomin_callback},
                    'gridcfg':{'column':0,'row':12,'columnspan':4, 'sticky':'ew'},
                    })
        
        idf.append({'widgetType':Tkinter.Button,
                    'name':'zoomout',
                    'wcfg':{'borderwidth':4, #'width':10,'height':2,
                            'text':'Zoom Out',
                            'disabledforeground':'#CCCCCC',
                            'font': labelFont,
                            'command': self.zoomout_callback},
                    'gridcfg':{'column':0,'row':13, 'columnspan':4,'sticky':'ew'},
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'name':'zoomto',
                    'wcfg':{'borderwidth':4, #'width':10,'height':2,
                            'text':'Zoom To...',
                            'disabledforeground':'#CCCCCC',
                            'font': labelFont,
                            'command': self.zoomto_callback},
                    'gridcfg':{'column':0,'row':14, 'columnspan':4,'sticky':'ew'},
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'name':'dismiss',
                    'wcfg':{'borderwidth':4, #'width':10,'height':2,
                            'text':'Dismiss',
                            'font': labelFont,
                            'command': self.dismiss},
                    'gridcfg':{'column':0, 'columnspan':4, 'sticky':'ew'},
                    })
        
        self.form = self.vf.getUserInput(idf, modal = 0, blocking=0)
        ent = self.form.descr.entryByName
        ent['max_move_box']['widget'].grid_forget()
        ent['reduce_to_move']['widget'].grid_forget()
        ent['getvolume']['widget'].grid_forget()
        ent['linewidth']['widget'].label.configure(font=numberFont)
        if self.firstUse:
            if wx<<1 > MAXDIM or wy<<1 > MAXDIM or wz<<1 > MAXDIM:
                w = self.form.descr.entryByName['zoomin']['widget']
                w.configure(state=Tkinter.DISABLED)
            w = self.form.descr.entryByName['zoomout']['widget']
            w.configure(state=Tkinter.DISABLED) 
            self.firstUse = 0



    def setMode(self):
        """sets the command's mode: zoom - for zooming between
        resolution levels, move - to get another part of parent volume
        (the one with highest resolution) at current level"""
        mode = self.mode.get()
        if mode == self.currentMode: return
        if self.currentVolume == 0:
            self.mode.set('zoom')
            return
        self.currentMode = mode
        ebn = self.idf.entryByName
        widgets_zoom = ['selectby', 'crop', 'box', 'reduce_to_zoom',
                       'max_zoom_box', 'zoomin','zoomout','zoomto']
        widgets_move = ['reduce_to_move', 'max_move_box','getvolume']
        zoomBox = self.zoomBox
        if mode == 'move':
            for w in widgets_zoom:
                ebn[w]['widget'].grid_forget()
            for w in widgets_move:
                apply(ebn[w]['widget'].grid, (), ebn[w]['gridcfg'])
            vs = self.showParentVolume()
            #self.zoomBox.setScale()
            self.switch.set('box')
            self.setZoomTool()
            zoomBox.setVolSize(vs)
            p1, p2 = zoomBox.cornerPoints
            zoomBox.xmin = int(p1[0]-vs[0])
            zoomBox.xmax = zoomBox.xmin+zoomBox.dx
            zoomBox.ymin = int(p1[1]-vs[1])
            zoomBox.ymax = zoomBox.ymin+zoomBox.dy
            zoomBox.zmin = int(p1[2]-vs[2])
            zoomBox.zmax = zoomBox.zmin+zoomBox.dz
            #zoomBox.update()
            self.updateInfo(zoomBox)

        elif mode == 'zoom':
            for w in widgets_move:
                ebn[w]['widget'].grid_forget()
            for w in widgets_zoom:
                apply(ebn[w]['widget'].grid, (), ebn[w]['gridcfg'])
            crop = volGeom.cropBox 
            wx, wy, wz = crop.dx, crop.dy, crop.dz
            xmin, ymin, zmin = crop.xmin, crop.ymin, crop.zmin
            xmax, ymax, zmax = crop.xmax, crop.ymax, crop.zmax
            
            zoomBox.setVolSize(volGeom.volumeSize)
            zoomBox.xmin=xmin
            zoomBox.xmax = xmax
            zoomBox.ymin = ymin
            zoomBox.ymax = ymax
            zoomBox.zmin = zmin
            zoomBox.zmax = zmax
            zoomBox.update()
            self.parentBox.Set(visible=0)
        self.vf.GUI.VIEWER.Redraw()    
            
        
    def setZoomTool(self):
        """sets the zooming tool to be either the crop box or
        the geometry box"""
        var = self.switch.get()
        #print "zoomtool:", var
        zoomTool_old = self.zoomTools[self.currTool]
        from DejaVu.VolumeGeom import CropBox
        if var == 'crop':
            if isinstance(zoomTool_old, CropBox): return
            self.currTool = 'crop'
            #self.zoomBox.showBox(0)
            showbox = 0
            volGeom.BindMouseToCropScale()
            volGeom.BindMouseToCropTransAll()     
        elif var == 'box':
            if isinstance(zoomTool_old, ZoomBox): return
            self.currTool = 'box'
            #self.zoomBox.showBox(1)
            showbox = 1
            self.zoomBox.BindMouseToBoxScale()
            self.zoomBox.BindMouseToBoxTransAll()
        zoomTool_new = self.zoomTools[self.currTool]
        zoomTool_new.setVolSize(zoomTool_old.volSize)
        zoomTool_new.xmin = zoomTool_old.xmin
        zoomTool_new.ymin = zoomTool_old.ymin
        zoomTool_new.zmin = zoomTool_old.zmin
        zoomTool_new.xmax = zoomTool_old.xmax
        zoomTool_new.ymax = zoomTool_old.ymax
        zoomTool_new.zmax = zoomTool_old.zmax
        zoomTool_new.update()
        self.showbox.set(showbox)
        self.zoomBox.showBox(showbox)

    def setLineWidth(self, val):
        """sets the line width of the geometry zooming box"""
        self.zoomBox.setLineWidth(val)

    def reset_box(self):
        """resets the geometry zoom box to outline the volume"""
        self.zoomBox.resetBox()

    def reset_crop(self):
        """resets the crop box to full volume size"""
        cropBox = volGeom.cropBox
        cropBox.xmin = 0
        cropBox.xmax = cropBox.volSize[0]
        cropBox.ymin = 0
        cropBox.ymax = cropBox.volSize[1]
        cropBox.zmin = 0
        cropBox.zmax = cropBox.volSize[2]
        cropBox.update()

    def volumeboxes_onoff_cb(self):
        """switches the outlines of the nested volumes on/off"""
        if self.volumeboxvar.get():
           volGeom.volumeBoxes = 1
        else:
           volGeom.volumeBoxes = 0
        self.vf.GUI.VIEWER.Redraw()

    def showZoomBox(self):
        """shows/hides the geometry zooming box"""
        var = self.showbox.get()
        self.zoomBox.showBox(var)

    def max_zoom_box(self):
        """reduces the current zoomming tool to the max. zoomable
        size(MAXBOXDIMxMAXBOXDIMxMAXBOXDIM)"""
        maxboxside = 64 
        if self.isSubform:
           nextresol = self.getresol.get()
           if nextresol and nextresol < self.resol:
               maxboxside = (MAXDIM/(self.resol/nextresol))/2

        zoomTool = self.zoomTools[self.currTool]
        vx = zoomTool.volSize[0]
        vy = zoomTool.volSize[1]
        vz = zoomTool.volSize[2]
           
        midx = vx/2
        midy = vy/2
        midz = vz/2
        zoomTool.xmin = max(0, midx-maxboxside)
        zoomTool.xmax = min(midx+maxboxside, vx-1)
        zoomTool.ymin = max(0, midy-maxboxside)
        zoomTool.ymax = min(midy+maxboxside, vy-1)
        zoomTool.zmin = max(0, midz-maxboxside)
        zoomTool.zmax = min(midz+maxboxside, vz-1)
        zoomTool.update()


    def reduce_to_zoom(self):
        """reduces current zomming tool dimensions that are greater than
        MAXBOXDIM to MAXBOXDIM"""
        maxboxside = MAXBOXDIM
        if self.isSubform:
           nextresol = self.getresol.get()
           if nextresol and nextresol < self.resol:
               maxboxside = MAXDIM/(self.resol/nextresol)
        zoomTool = self.zoomTools[self.currTool]
        wx, wy, wz = zoomTool.dx, zoomTool.dy, zoomTool.dz
        if wx > maxboxside:
            diff = (wx-maxboxside)/2.
            #print 'diff', diff
            if diff%2 != 0 :
                zoomTool.xmin = zoomTool.xmin+int(diff)+1
                zoomTool.xmax = zoomTool.xmax-int(diff)
            else:
                zoomTool.xmin = zoomTool.xmin+int(diff)
                zoomTool.xmax = zoomTool.xmax-int(diff)
        if wy > maxboxside:
            diff = (wy-maxboxside)/2.
            #print 'diff', diff
            if diff%2 != 0 :
                zoomTool.ymin = zoomTool.ymin+int(diff)+1
                zoomTool.ymax = zoomTool.ymax-int(diff)
            else:
                zoomTool.ymin = zoomTool.ymin+int(diff)
                zoomTool.ymax = zoomTool.ymax-int(diff)
        if wz > maxboxside:
            diff = (wz-maxboxside)/2.
            #print 'diff', diff
            if diff%2 != 0 :
                zoomTool.zmin = zoomTool.zmin+int(diff)+1
                zoomTool.zmax = zoomTool.zmax-int(diff)
            else:
                zoomTool.zmin = zoomTool.zmin+int(diff)
                zoomTool.zmax = zoomTool.zmax-int(diff)
        zoomTool.update()

    def dismiss(self):
        """dismisses the input form"""
        
        self.idf.form.withdraw()
        self.isDisplayed = 0
        self.isWithdrawn = 1
        if self.isSubform:
            #self.subidf.form.destroy()
            self.subidf.form.withdraw()
            self.isSubform = 0

    def max_move_box(self):
        """reduces the moving box size  to the max. subvolume
        size(MAXDIMxMAXDIMxMAXDIM)"""
        maxboxside = MAXBOXDIM 
        vx = self.zoomBox.volSize[0]
        vy = self.zoomBox.volSize[1]
        vz = self.zoomBox.volSize[2]
        midx = vx/2
        midy = vy/2
        midz = vz/2
        self.zoomBox.xmin = max(0, midx-maxboxside)
        self.zoomBox.xmax = min(midx+maxboxside, vx-1)
        self.zoomBox.ymin = max(0, midy-maxboxside)
        self.zoomBox.ymax = min(midy+maxboxside, vy-1)
        self.zoomBox.zmin = max(0, midz-maxboxside)
        self.zoomBox.zmax = min(midz+maxboxside, vz-1)
        self.zoomBox.update()


    def reduce_to_move(self):
        """reduces moving box dimentions that are greater than
        MAXDIM to MAXDIM"""
        maxboxside = MAXDIM
        box = self.zoomBox
        wx, wy, wz = box.dx, box.dy, box.dz
        if wx > maxboxside:
            diff = (wx-maxboxside)/2.
            #print 'diff', diff
            if diff%2 != 0 :
                box.xmin = box.xmin+int(diff)+1
                box.xmax = box.xmax-int(diff)
            else:
                box.xmin = box.xmin+int(diff)
                box.xmax = box.xmax-int(diff)
        if wy > maxboxside:
            diff = (wy-maxboxside)/2.
            #print 'diff', diff
            if diff%2 != 0 :
                box.ymin = box.ymin+int(diff)+1
                box.ymax = box.ymax-int(diff)
            else:
                box.ymin = box.ymin+int(diff)
                box.ymax = box.ymax-int(diff)
        if wz > maxboxside:
            diff = (wz-maxboxside)/2.
            #print 'diff', diff
            if diff%2 != 0 :
                box.zmin = box.zmin+int(diff)+1
                box.zmax = box.zmax-int(diff)
            else:
                box.zmin = box.zmin+int(diff)
                box.zmax = box.zmax-int(diff)
        box.update()

    def getSub(self, bounds, action, ratio, zoombounds):
        """gets a subvolume from a given resolution level and
        loads it into the Viewer"""
        volGeom.updateBoundBox = 0
        zoomTool = self.zoomTools[self.currTool]
        t1 = time.time()
        dx = bounds[1]-bounds[0]
        dy = bounds[3]-bounds[2]
        dz = bounds[5]-bounds[4]
        volume = self.volumes[self.currentVolume]
        arrPtr = volume.getSubVolume( 'value', bounds[0], bounds[1],
                                      bounds[2], bounds[3],
                                      bounds[4], bounds[5])
        volumesize = volGeom.volumeSize
        if action=='zoom out':
            currbounds = self.bounds_dict[self.resol]
            nextbounds = bounds
            xo = currbounds[0]/ratio - nextbounds[0]
            yo = currbounds[2]/ratio - nextbounds[2]
            zo = currbounds[4]/ratio - nextbounds[4]
            box = (xo + (zoombounds[0]/ratio),  xo + (zoombounds[1]/ratio),
                    yo + (zoombounds[2]/ratio),  yo + (zoombounds[3]/ratio),
                    zo + (zoombounds[4]/ratio),  zo + (zoombounds[5]/ratio))
            scale = (ratio, ratio, ratio)
        elif action=='zoom in' :
            self.zoomboxes[self.resol] = zoombounds
            self.volsizes[self.resol] = volumesize
            self.resol = self.resol/ratio
            self.bounds_dict[self.resol] = bounds
            scale= (1./ratio, 1./ratio, 1./ratio)
        volGeom.lock.acquire()
        vlivol = self.createNewVolume(arrPtr, dx, dy, dz)

        if self.currentMode == 'zoom':
            self.vf.GUI.VIEWER.rootObject.ConcatScale(scale)
        self.setTransfomation(dx,dy,dz)
        self.loadNewVolume(vlivol, arrPtr)
        self.zoomBox.setVolSize((dx,dy,dz))
        volGeom.lock.release()
        if action=='zoom in':
            print 'zoomin in getSub'
            zoomTool.xmin = 0
            zoomTool.xmax = dx
            zoomTool.ymin = 0
            zoomTool.ymax = dy
            zoomTool.zmin = 0
            zoomTool.zmax = dz
            #update vliGeom attributes used for drawing nested volumes outlines
            volGeom.cropBox_list.append(zoombounds)
            volGeom.volumesizes.append(volumesize)
            volGeom.ratios.append(ratio)

        elif action=='zoom out':
            print 'zoom out in getSub'
            zoomTool.xmin = box[0]
            zoomTool.xmax = box[1]
            zoomTool.ymin = box[2]
            zoomTool.ymax = box[3]
            zoomTool.zmin = box[4]
            zoomTool.zmax = box[5]
            self.resol = self.resol * ratio
            
            for k in self.bounds_dict.keys():
                if k < self.resol:
                    del(self.bounds_dict[k])
                if k <= self.resol:
                    if self.volsizes.has_key(k):
                        del(self.volsizes[k])
                        del(self.zoomboxes[k])
                        volGeom.volumesizes.pop()
                        volGeom.cropBox_list.pop()
            res_list = self.bounds_dict.keys()
            res_list.sort()
            res_list.reverse()
            ratios = []
            for i in range(len(res_list)-1):
                ratios.append(res_list[i]/res_list[i+1])
            volGeom.ratios = ratios
        t2= time.time()
        print "time %s: %.2f"%(action, t2-t1,)
        volGeom.newVolumeLock.acquire()
        self.newVolume = 1
        volGeom.newVolumeLock.release()
        if self.form:
            ent = self.form.descr.entryByName
            ent['level']['widget'].configure(text=str(self.currentVolume+1))

    def createNewVolume(self, arrPtr, dx, dy, dz):
        """Creates a new volume object."""
        # Has to be implemented by a derived class.
        pass

    def setTransfomation(self, dx,dy,dz):
        """Sets the volume transformation matrix."""
        # Has to be implemented by a derived class.
        pass

    def loadNewVolume(self, vlivol, arrPtr):
        """ Loads new volume object in to the viewer."""
        # Has to be implemented by a derived class.
        pass

       
    def doit_thread(self, bounds, action, ratio, zoombounds):
        """Executes method getSub() in a new thread. """
        volGeom.lock.acquire()
        print 'getting SubVolume ...', bounds
        thread.start_new_thread( self.getSub, (bounds, action,
                                               ratio, zoombounds))
        #self.getSub(bounds, action, ratio, zoombounds)
        self.vf.GUI.VIEWER.cameras[0].after(100, self.updateZoomTool)
        volGeom.lock.release()

    def updateZoomTool(self):
        """Updates the size of the crop box or geometry box after a new
        volume has been loaded. """
        newval = volGeom.newVolumeLock.acquire(0)
        if newval == 0:
            self.vf.GUI.VIEWER.cameras[0].after(100, self.updateZoomTool)
        if self.newVolume:
            self.newVolume = 0
            zoomTool = self.zoomTools[self.currTool]
            if self.currentMode == 'move':
                zoomTool = self.zoomBox
                vs = self.showParentVolume()
                zoomTool.setVolSize(vs)
                vx, vy, vz = volGeom.volume.GetSize()
                zoomTool.xmin = int(-vx/2.-vs[0])
                zoomTool.xmax = zoomTool.xmin+zoomTool.dx
                zoomTool.ymin = int(-vy/2.-vs[1])
                zoomTool.ymax = zoomTool.ymin+zoomTool.dy
                zoomTool.zmin = int(-vz/2.-vs[2])
                zoomTool.zmax = zoomTool.zmin+zoomTool.dz
            zoomTool.update()
            if zoomTool == self.zoomTools['crop']:
                xmin, ymin, zmin = zoomTool.xmin, zoomTool.ymin, zoomTool.zmin
                xmax, ymax, zmax = zoomTool.xmax, zoomTool.ymax, zoomTool.zmax
                self.zoomBox.xmin= xmin
                self.zoomBox.xmax = xmax
                self.zoomBox.ymin = ymin
                self.zoomBox.ymax = ymax
                self.zoomBox.zmin = zmin
                self.zoomBox.zmax = zmax
                self.zoomBox.update()
            volGeom.updateBoundBox = 1
            self.update_volumeBoundBox()
            if self.vf.commands.has_key('vliAddBoundBox'):
                self.vf.vliAddBoundBox.updateBox()
            
        else:
           self.vf.GUI.VIEWER.cameras[0].after(100, self.updateZoomTool) 
        volGeom.newVolumeLock.release()

    def doit(self, zoombounds = None, action = None, nextresol = None,
             newdata = None, **kw):
        """Computes bounds of subvolume when zooming in/out.
        Creates and loads new volume."""

        if newdata:
            resol, datafiles, cachesizes, pagesizes, scale  = \
                   self.parseData(newdata)
            self.check = self.checkData(resol, datafiles, cachesizes,
                                        pagesizes)
            if self.check:
                self.resol = resol
                self.lowestresol = resol
                self.volumes = []
                for i in range(len(datafiles)):
                    self.volumes.append(MeshVolume(datafiles[i],
                                                   ps=pagesizes[i],
                                                   mcs=cachesizes[i]))
                print 'get voxels from low resolution mesh'
                bounds = self.volumes[0].bounds
                #self.vf.GUI.busy()
                from time import time
                t1= time()
                arrPtrLow = self.volumes[0].getSubVolume( 'value',
                                                          0, bounds[0],
                                                          0, bounds[1],
                                                          0, bounds[2])
                vlivol = self.createNewVolume(arrPtrLow, bounds[0],
                                              bounds[1], bounds[2])
                t2 = time()
                print "time to get a subvolume: %.2f" % (t2-t1)
                self.loadNewVolume(vlivol, arrPtrLow)
                volGeom.Set(volscale=scale)
                volGeom.viewer.Redraw()
                #self.vf.GUI.idle()
                if self.form:
                    self.form.destroy()
                self.initValues()
                self.bounds_dict[self.resol] = (0, bounds[0],
                                                0, bounds[1],
                                                0, bounds[2])
                self.datafile = newdata
            else: return
        if zoombounds is None or action is None or nextresol is None:
            return
        if action == 'zoom in':
            ratio = self.resol / nextresol
            dx = ratio*(zoombounds[1]-zoombounds[0])
            dy = ratio*(zoombounds[3]-zoombounds[2])
            dz = ratio*(zoombounds[5]-zoombounds[4])
            if dx > MAXDIM or dy > MAXDIM or dz > MAXDIM:
                print "zoomming box is too large"
                from SimpleDialog import SimpleDialog
                root = Tkinter.Toplevel()
                root.withdraw()
                ans = SimpleDialog(root, text="Zoomming box is too large",
                                   buttons=["OK"], default=1,
                                   title=" ").go()
                root.destroy()
                return
            currentVolume = self.currentVolume
            #print "currentVolume1:", currentVolume
            self.currentVolume = currentVolume+int(log(ratio)/log(2))
            if self.isDisplayed :
                ent = self.form.descr.entryByName
                ent['level']['widget'].configure(text=str(currentVolume+1)+\
                                              "->"+ str(self.currentVolume+1))
            bounds = self.bounds_dict[self.resol]
            xo, yo, zo = bounds[0], bounds[2], bounds[4]
            bounds = ((xo+zoombounds[0])*ratio, (xo+zoombounds[1])*ratio,
                      (yo+zoombounds[2])*ratio, (yo+zoombounds[3])*ratio,
                      (zo+zoombounds[4])*ratio, (zo+zoombounds[5])*ratio)

            self.doit_thread(bounds, 'zoom in', ratio, zoombounds)
            
        elif action == 'zoom out':
            currentVolume = self.currentVolume
            ratio = nextresol/self.resol
            self.currentVolume = self.currentVolume-int(log(ratio)/log(2))
            if self.isDisplayed:
                ent = self.form.descr.entryByName
                ent['level']['widget'].configure(text=str(currentVolume+1)+\
                                              "->"+ str(self.currentVolume+1))

            bounds = self.bounds_dict.get(nextresol, 0)
            if not bounds:
                #need to find the bounds of subvolume for
                #the zoom out resolution
                destresol = nextresol
                while not bounds:
                    nextresol = nextresol*2
                    bounds = self.bounds_dict.get(nextresol, 0)
                r = nextresol/destresol
                b = MAXDIM/r
                currbounds = self.bounds_dict[self.resol]
                xo, yo, zo = bounds[0], bounds[2], bounds[4]
                zmbox = self.zoomboxes[nextresol]
                volsize = self.volsizes[nextresol]
                dx1 = zmbox[0]
                dx2 = volsize[0]-zmbox[1]
                dy1 = zmbox[2]
                dy2 = volsize[1]-zmbox[3]
                dz1 = zmbox[4]
                dz2 = volsize[2]-zmbox[5]
                X = min(b, volsize[0])
                Y = min(b, volsize[1])
                Z = min(b, volsize[2])
                dX = X-(zmbox[1]-zmbox[0])
                dY = Y-(zmbox[3]-zmbox[2])
                dZ = Z-(zmbox[5]-zmbox[4])
                if dX/2 > dx1:
                    xmin = 0
                    xmax = X
                elif dX/2 > dx2:
                    xmin = volsize[0]-X
                    xmax = volsize[0]
                else:
                    xmin = zmbox[0]-dX/2
                    xmax = zmbox[1]+dX/2
                if dY/2 > dy1:
                    ymin = 0
                    ymax = Y
                elif dY/2 > dy2:
                    ymin = volsize[1]-Y
                    ymax = volsize[1]
                else:
                    ymin = zmbox[2]-dY/2
                    ymax = zmbox[3]+dY/2
                if dZ/2 > dz1:
                    zmin = 0
                    zmax = Z
                elif dZ/2 > dz2:
                    zmin = volsize[2]-Z
                    zmax = volsize[2]
                else:
                    zmin = zmbox[4]-dZ/2
                    zmax = zmbox[5]+dZ/2
                self.zoomboxes[nextresol] = (xmin, xmax, ymin, ymax,
                                             zmin, zmax)

                bounds = ((xo+xmin)*r, (xo+xmax)*r,
                          (yo+ymin)*r, (yo+ymax)*r,
                          (zo+zmin)*r, (zo+zmax)*r)
                self.bounds_dict[destresol] = bounds
                res_list = self.zoomboxes.keys()
                res_list.sort()
                res_list.reverse()
                volGeom.cropBox_list = []
                for r in res_list:
                    volGeom.cropBox_list.append(self.zoomboxes[r])

            self.doit_thread(bounds, 'zoom out', ratio, zoombounds)
            

    def __call__(self, zoombounds=None, action=None, resolution=None,
                 newdata = None, **kw):
        """None <- Zoom(zoombounds=None, action=None,
                        resolution=None, newdata=None, **kw)
        zoombounds: the bounds of the zooming box,
        a tuple(Xmin, Xmax, Ymin, Ymax, Zmin, Zmax), if None - no zooming
        action is performed;
        action: 'zoom in' or 'zoom out'. If None - no zooming action is
        performed;
        resolution: zoom to resolution, an integer of power of 2. If None -
        no zooming action is performed;
        newdata - a text file containing data information"""

        if newdata:
            if zoombounds is None or action is None or resolution is None:
                self.doitWrapper(newdata = newdata)
                return
        else:
          if zoombounds is None or action is None or resolution is None:
              print "Must specify zoombounds ,resolution and action"
              return
        if len(zoombounds)!= 6:
            raise ValueError("Wrong number of zoombounds; expected 6, got %d."\
                             %len(zoombounds))
        for cb in zoombounds:
            if cb < 0:
                raise ValueError("zoombounds should be positive values")
        size = volGeom.volume.GetSize()
        if zoombounds[1] > size[0]:
            zoombounds = list(zoombounds)
            zoombounds[1]=size[0]
        if zoombounds[3] > size[1]:
            zoombounds = list(zoombounds)
            zoombounds[3] = size[1]
        if zoombounds[5] > size[2]:
            zoombounds = list(zoombounds)
            zoombounds[5] = size[2]
        reslist = []
        r = self.lowestresol
        while r >1:
            reslist.append(r)
            r=r/2
        reslist.append(1)
        if resolution not in reslist:
            raise ValueError("wrong resolution number; expected 8, 4, 2 or 1")
        if action == 'zoom in':
            if resolution > self.resol:
                raise ValueError("action and resolution do not match")
        elif action == 'zoom out':
            if resolution < self.resol:
               raise ValueError("action and resolution do not match")
        else:
            raise ValueError("wrong action ")
        apply(self.doitWrapper,(zoombounds, action, resolution, newdata),kw)


    
    def zoomin_callback(self, *arg):
        """Called when 'Zoom in' button is pressed.
        Gets the bounds of current zoomtool (crop box or geometry box).
        Calls doitWrapper() method. """ 
        if arg:
            nextresol = arg[0]
        else:
            nextresol = self.resol/2
            if self.isSubform:
                #self.subidf.form.destroy()
                self.subidf.form.withdraw()
                self.isSubform = 0
        zoomTool = self.zoomTools[self.currTool]
        zoombounds = (zoomTool.xmin, zoomTool.xmax,
                      zoomTool.ymin, zoomTool.ymax,
                      zoomTool.zmin, zoomTool.zmax)
        self.doitWrapper(zoombounds, 'zoom in', nextresol)


    def zoomout_callback(self, *arg):
        """Called when 'Zoom out' button is pressed.
        Gets the bounds of current zoomtool (crop box or geometry box).
        Calls doitWrapper() method. """ 
        if arg:
            nextresol = arg[0]
        else:
            ratio = 2
            nextresol = self.resol*ratio
            if self.isSubform:
                #self.subidf.form.destroy()
                self.subidf.form.withdraw()
                self.isSubform = 0
        zoomTool = self.zoomTools[self.currTool]
        zoombounds = (zoomTool.xmin, zoomTool.xmax,
                      zoomTool.ymin, zoomTool.ymax,
                      zoomTool.zmin, zoomTool.zmax)
        self.doitWrapper(zoombounds, 'zoom out', nextresol)

    def zoomto_callback(self):
        """Called when 'Zoom To...' button is pressed. Creates
        a subinput for to specify a zooming level. """
        if self.isSubform:
            return
        self.isSubform = 1
        if self.subform:
            ent = self.subform.descr.entryByName
            ent['maxboxsize']['widget'].configure(text="        ")
            self.subform.deiconify()
            self.getresol.set(0)
            return
        idf = InputFormDescr(title = "Zoom To...")

        font = '-*-Helvetica-Bold-R-Normal-*-*-160-*-*-*-*-*-*'
        r = self.lowestresol
        l=1
        for i in range(len(self.volumes)):
            idf.append({'widgetType':Tkinter.Radiobutton,
                        'name':"Res%d"%r,
                        'wcfg':{'text': "level %d"%l,
                                'font': font,
                                'variable': self.getresol,
                                'value':str(r),
                                'command':self.maxboxsizeinfo},
                        'gridcfg':{'row':i, 'column':0,
                                   'sticky':Tkinter.NSEW,'columnspan':2},
                        })
            r=r/2 # for resolutions with ratio = 2
            l=l+1

        idf.append({'widgetType':Tkinter.Label,
                    'name':'maxbox',
                    'wcfg':{'text': 'max box',
                            'font': font},
                    'gridcfg':{'column': 0 }
                    })
        idf.append({'widgetType':Tkinter.Label,
                    'name':'maxboxsize',
                    'wcfg':{'text': '        ',
                            'font': font},
                    'gridcfg':{'row':-1,'column': 1 }
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'name':'zoomtolevel',
                    'wcfg':{'text':'Zoom',
                            'font': font,
                            'command': self.zoomtolevel},
                    'gridcfg':{'column':0},
                    })
        idf.append({'widgetType':Tkinter.Button,
                    'name':'cancel',
                    'wcfg':{'text':'Cancel',
                            'font': font,
                            'command': self.cancel_cb},
                    'gridcfg':{'row':-1, 'column':1},
                    })
        self.subidf = idf
        self.subform = self.vf.getUserInput(idf, modal=0, blocking=0)


    def cancel_cb(self):
        """Withdraws the GUI."""
        #self.subidf.form.destroy()
        self.subidf.form.withdraw()
        self.isSubform = 0
        zoomTool = self.zoomTools[self.currTool]
        self.updateInfo(zoomTool)

    def zoomtolevel(self):
        """Called when 'Zoom' button of 'Zoom To' input form is pressed.
        """
        nextresol = self.getresol.get()
        #print "nextresol =", nextresol 
        if nextresol:
            if nextresol == self.resol:
                return
            #self.subidf.form.destroy()
            self.subidf.form.withdraw()
            self.isSubform = 0
            if nextresol < self.resol:
                self.zoomin_callback(nextresol)
                
            elif nextresol > self.resol:
                self.zoomout_callback(nextresol)

    def maxboxsizeinfo(self):
        nextresol = self.getresol.get()
        ent = self.subform.descr.entryByName
        zoomTool = self.zoomTools[self.currTool]
        if self.resol > nextresol:
            vx = zoomTool.volSize[0]
            vy = zoomTool.volSize[1]
            vz = zoomTool.volSize[2]
            s = MAXDIM/(self.resol/nextresol)
            xmax = min(s, vx)
            ymax = min(s, vy)
            zmax = min(s, vz)
            ent['maxboxsize']['widget'].configure(text = "%dx%dx%d" \
                                                  % (xmax,ymax,zmax))
            self.updateInfo(zoomTool)
        else:
            ent['maxboxsize']['widget'].configure(text="        ")

    def showParentVolume(self):
        if len(volGeom.volumesizes) == 0: return
        scale=self.getVolumeScale()
        tx, ty, tz = 0, 0, 0
        ratio = 1
        for i in range(len(volGeom.volumesizes)):
                Vx, Vy, Vz = volGeom.volumesizes[-(i+1)]
                val = volGeom.cropBox_list[-(i+1)]
                ratio = ratio*volGeom.ratios[-(i+1)]
                #print "ratio", ratio
                tx = tx + ((Vx-(val[1]-val[0]))/2.-val[0])*ratio
                ty = ty + ((Vy-(val[3]-val[2]))/2.-val[2])*ratio
                tz = tz + ((Vz-(val[5]-val[4]))/2.-val[4])*ratio
        Vx = Vx/2.*ratio
        Vy = Vy/2.*ratio
        Vz = Vz/2.*ratio
        volCorners = (-Vx+tx, -Vy+ty, -Vz+tz ,Vx+tx, Vy+ty, Vz+tz)
        corners = ((-Vx+tx, -Vy+ty, -Vz+tz) ,(Vx+tx, Vy+ty, Vz+tz))
        #parentVolSize = map(lambda x,y: y-x, corners[0],corners[1])
        if self.parentBox:
            self.parentBox.Set(cornerPoints = corners, visible = 1)
        else:
            self.parentBox = Box("parentBox", cornerPoints = corners,
                                  inheritMaterial = 0)
            self.vf.GUI.VIEWER.AddObject(self.parentBox)
        boxscale = self.parentBox.scale
        if scale[0] != boxscale[0] or \
           scale[1] != boxscale[1] or \
           scale[2] != boxscale[2]:
            self.parentBox.SetScale((scale[0],scale[1],scale[2]))
        return volCorners

    def update_volumeBoundBox(self):
        """Checks if the volume bounding box needs to be updated."""
        # has to be implemented by a derived class.
        pass

    def getVolumeScale(self):
        """ Get current scale of the volume object."""
        # has to be implemented by a derived class.
        pass

    def getvolume_callback(self):
        """gets bounds of another subvolume of parent volume
         at current level in 'move' mode. (Parent volume is the one with
         highest resolution)."""
        ratio = self.lowestresol/self.resol
        box = self.zoomBox
        print "zoomBox", box
        zoombounds = (box.xmin/ratio, box.xmax/ratio,
                      box.ymin/ratio, box.ymax/ratio,
                      box.zmin/ratio, box.zmax/ratio)
        dx = ratio*(zoombounds[1]-zoombounds[0])
        dy = ratio*(zoombounds[3]-zoombounds[2])
        dz = ratio*(zoombounds[5]-zoombounds[4])
        print "zoombounds:", zoombounds
        print "dx=%d, dy=%d, dz=%d"% (dx,dy,dz)
        print "ratio:", ratio
        print "self.resol:", self.resol
        if dx > MAXDIM or dy > MAXDIM or dz > MAXDIM:
            print "zoomming box is too large"
            print zoombounds
            return
        resol = self.resol
        self.resol = self.lowestresol
        self.currentVolume = 0
        volGeom.volumeSize = self.volsizes[self.lowestresol]
        self.volsizes = {}
        self.zoomboxes = {}
        for k in self.bounds_dict.keys():
            if k != self.lowestresol:
                del(self.bounds_dict[k])
        volGeom.cropBox_list = []
        volGeom.volumesizes = []
        volGeom.ratios = []
        self.doitWrapper(zoombounds, 'zoom in', resol)

class VLIZoom(Zoom):
    """Command to zoom through a number of volume datasets.
    GUI description:
    A subvolume can be selected by operating with a zooming tool,
    which can be either the crop box (select the 'crop' button) or
    an outlined geometry box (select the 'box' button).
    The following mouse/keyboard bindings can be used to interactevly
    manipulate a chosen zooming tool:
    -- 'Control' + mouse button 1, 2 or 3 are used to change the size
         of the zooming tool along X, Y, Z respectively;
    -- 'meta' + mouse button 3 changes the zooming tool size in all directions;
    -- 'meta' + button 1 moves(translates) the zooming tool inside the volume
       in all directions.
    The maximum viewable volume size is 256 voxels in any dimension.
    Pressing the 'Max Zoomable Box' button sets the zooming tool
    dimensions to 256/ratio (where ratio is the resolution ratio between two
    consequent datafiles).
    Pressing the 'Reduce To Zoom' button reduces the zooming tool dimensions
    exceeding the value of 256/ratio to 256/ratio.
    Pressing the 'Zoom In' button results in acquireing a subvolume from 
    the subsequent level (a higher resolution dataset) and loading it as a new
    volume into the viewer.
    Pressing the 'Zoom Out' button results in loading a volume from the
    previous level (a lower resolution dataset). The crop box or geometry
    box will show the area that was cropped or outlined in the level
    the zooming out was initialized from.
    Pressing the 'Zoom To...' button pops up a new interface that allows to
    select a zooming level.
    The 'Show box' button makes the geometry box visible/invisible.
    The 'All outlines' button shows the nested outlines of volumes following
    one or more zoom-in actions.
    The 'reset crop' and 'reset box' buttons reset the dimensions of the crop 
    and geometry boxes (respectively) to the volume dimensions.
    """
    
    def checkDependencies(self):
          from Volume.Renderers.VLI import vli
          from Volume.IO.Mesh import mesh

    def vvInitialized(self):
        return hasattr(self.vf, "StartVLI")

    def createNewVolume(self, arrPtr, dx, dy, dz):
        """Creates a new volume object."""

        if volGeom.volume:
            volGeom.volume.Release()
        return  vli.VLIVolume_Create( vli.kVLIVoxelFormatUINT8,
                                       arrPtr, dx, dy, dz)
    
    
    def setTransfomation(self, dx,dy,dz):
        """Sets the volume transformation matrix."""

        matVLI=vli.VLIMatrix(Numeric.reshape\
                             (self.vf.GUI.VIEWER.rootObject.GetMatrix(),
                              (16,)))
        #volGeom.context.GetCamera().SetViewMatrix(matVLI)
        centerMat = vli.VLIMatrix_Translate(-.5*dx, -.5*dy, -.5*dz)
        volGeom.volume.SetModelMatrix(centerMat*matVLI)
    
    def loadNewVolume(self, vlivol, arrPtr):
        """ Loads new volume object in to the viewer."""
        volGeom.AddVolume(vlivol, arrPtr)

    def update_volumeBoundBox(self):
        """Checks if the volume bounding box needs to be updated."""
        if self.vf.commands.has_key('VLIBoundBox'):
            self.vf.VLIBoundBox.updateBox()

    def getVolumeScale(self):
        """ Get current scale of the volume object."""
        scale=[1,1,1]
        if volGeom.vliScalemat:
            scale[0] = volGeom.vliScalemat[0][0]
            scale[1] = volGeom.vliScalemat[1][1]
            scale[2] = volGeom.vliScalemat[2][2]
        return scale

        

commandGUI = CommandGUI()
##  ZoomGUI.addMenuCommand('menuRoot','start VLI','Zoom', index=17)
menuName = 'Zoom volume'
menuIndex = 13
commandNames = {'vli': 'VLIZoom', 'utvolren': None}
commandList = [{'name':'', 'cmd': None, 'gui': None}]

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