; $Id: dm_plot__define.pro,v 1.93 2008/04/02 16:25:13 ymqiu Exp $
;#######################################################################
;
; NAME:
;  dm_plot
;
; PURPOSE:
;  A versatile object plotting program.
;
; CATEGORY:
;  general graphics
;
; AUTHOR:
;  Yiming Qiu
;  NIST Center for Neutron Research
;  100 Bureau Drive, Gaithersburg, MD 20899-6102
;  United States
;  yiming.qiu@nist.gov
;  April, 2008
;
; LICENSE:
;  The software in this file is written by an employee of
;  National Institute of Standards and Technology
;  as part of the DAVE software project.
;
;  The DAVE software package is not subject to copyright protection
;  and is in the public domain. It should be considered as an
;  experimental neutron scattering data reduction, visualization, and
;  analysis system. As such, the authors assume no responsibility
;  whatsoever for its use, and make no guarantees, expressed or
;  implied, about its quality, reliability, or any other
;  characteristic. The use of certain trade names or commercial
;  products does not imply any endorsement of a particular product,
;  nor does it imply that the named product is necessarily the best
;  product for the stated purpose. We would appreciate acknowledgment
;  if the DAVE software is used or if the code in this file is
;  included in another product.
;
;#######################################################################

;if widget is killed
pro dm_plot_Exit,tlb
    widget_control,tlb,get_uvalue=self
    if obj_valid(self) then begin
       self->getproperty,group_leader=group_leader,tlb=tlb,parenthandler=parenthandler,parentobj=parentobj
       sendevent={dm_plot_kill,ID:tlb,TOP:group_leader,HANDLER:tlb,object:self}
       if obj_valid(parentobj) then $                           ;notify parent object
          call_method,parenthandler,parentobj,sendevent $
       else if widget_info(group_leader,/valid_id) ne 0 then $  ;notify the group leader
          widget_control,group_leader,send_event=sendevent,/no_copy
       obj_destroy,self
    endif
end

;event handler
pro dm_plot_event,event
    compile_opt IDL2    ;,strictarrsubs
    ;catch and ignore all errors in this program
    catch, myerror
    if myerror ne 0 then begin
       catch,/cancel
       ok = dialog_message(!error_state.msg,/error)
       widget_control,event.top,/update
       return
    end
    widget_control,/hourglass
    widget_control,event.handler,get_uvalue=self
    if obj_valid(self) then begin
       if self->getproperty(/enotebook) then $
          IF DAVE_SET_FOCUS(EVENT) THEN RETURN
       self->event,event   ;actual event handler
    endif
end

;add a plot to the object
pro dm_plot::add_plot,xdat,ydat,zdat,idat,yerr=yerr,color=color,coltable=coltable,$
    hideintbar=hideintbar,layer=layer,legend=legend,linestyle=linestyle,no_copy=no_copy,$
    psym=psym,shading=shading,surfplot=surfplot,symsize=symsize,thick=thick,usepolygon=usepolygon,$
    zpos=zpos

    self.drawView->setproperty,/hide    ;get rid of blinking

    if n_elements(xdat) eq 1 then xdat=[xdat]
    if n_elements(ydat) eq 1 then ydat=[ydat]
    if n_elements(zdat) eq 1 then zdat=[zdat]
    if n_elements(idat) eq 1 then idat=[idat]

    if float(!version.release) ge 6.0 then v6p0_extra= {register_properties:1}  ;register_properties keyword for IDL6.0 or later
    if n_elements(color) eq 0 then color=(['white','black'])[self.bgcol]
    if n_elements(zpos)  eq 0 then zpos=!values.f_nan
    mycolor = self->getcolor(color)
    wbcolor = self->getcolor((['white','black'])[self.bgcol])
    ;check keywords
    if keyword_set(surfplot) then cshift=0.5 else cshift=0.0
    if n_params() lt 2 then begin
       ok = dialog_message('Wrong number of parameters for dm_plot::add_plot.',/error,dialog_parent=self.tlb)
       return
    endif
    if total(finite(self.xran[*,0])) ne 2 then begin
       xmax = max(xdat,min=xmin,/nan)
       self.xran[*,0] = [temporary(xmin),temporary(xmax)]
       if self.xran[0,0] eq self.xran[1,0] then begin
          tmp = (self.xran[0,0] eq 0)? 0.5:abs(self.xran[0,0]/2.)
          self.xran[0,0] = self.xran[0,0]-tmp
          self.xran[1,0] = self.xran[1,0]+tmp
       endif
    endif
    if total(finite(self.xran[*,2])) ne 2 then begin   ;set the correct x log range from the data
       poselts = where(xdat gt 0,count)
       if count gt 0 then begin
          xmax = max(xdat[temporary(poselts)],min=xmin)
       endif else begin
          xmin = 1.0 & xmax = 10.0
       endelse
       self.xran[0,2] = (xmin gt self.xran[0,0])?((self.xran[0,0] gt 0)?(self.xran[0,0]):(xmin)):(self.xran[0,0])
       self.xran[1,2] = (xmax gt self.xran[1,0])?((self.xran[1,0] gt 0)?(self.xran[1,0]):(xmax)):(self.xran[1,0])
       if self.xran[1,2] le self.xran[0,2] then self.xran[1,2] = self.xran[0,2]*10.0
    endif
    if total(finite(self.yran[*,0])) ne 2 then begin
       if n_elements(yerr) eq n_elements(ydat) then begin
          ymin = min(ydat-yerr,/nan)
          ymax = max(ydat+yerr,/nan)
       endif else begin
          ymax = max(ydat,min=ymin,/nan)
       endelse
       self.yran[*,0] = [temporary(ymin),temporary(ymax)]
       if self.yran[0,0] eq self.yran[1,0] then begin
          tmp = (self.yran[0,0] eq 0)? 0.5:abs(self.yran[0,0]/2.)
          self.yran[0,0] = self.yran[0,0]-tmp
          self.yran[1,0] = self.yran[1,0]+tmp
       endif
    endif
    if total(finite(self.yran[*,2])) ne 2 then begin   ;set the correct y log range from the data
       poselts = where(ydat gt 0,count)
       if count gt 0 then begin
          ymax = max(ydat[temporary(poselts)],min=ymin)
       endif else begin
          ymin = 1.0 & ymax = 10.0
       endelse
       self.yran[0,2] = (ymin gt self.yran[0,0])?((self.yran[0,0] gt 0)?(self.yran[0,0]):(ymin)):(self.yran[0,0])
       self.yran[1,2] = (ymax gt self.yran[1,0])?((self.yran[1,0] gt 0)?(self.yran[1,0]):(ymax)):(self.yran[1,0])
       if self.yran[1,2] le self.yran[0,2] then self.yran[1,2] = self.yran[0,2]*10.0
    endif
    ;create x & y axis if nonexistent
    if not obj_valid(self.drawxAxis[0]) then begin
       ;x axis
       self.drawxAxis[0] = obj_new('IDLgrAxis',0,range=self.xran[*,0],title=self.xtit,_extra=v6p0_extra,$
          color=wbcolor,ticklen=self.default[0]*1.5,/exact,location=[0,-cshift,0],name='axis') ;bottom
       self.drawGroup->add,self.drawxAxis[0]
       if not keyword_set(surfplot) then begin
          self.title->getproperty,strings=title & obj_destroy,self.title
          self.title = obj_new('IDLgrText',title,recompute_dimensions=2,font=self.font[4],/enable,_extra=v6p0_extra,$
             color=wbcolor,name='titl')
          self.drawxAxis[1] = obj_new('IDLgrAxis',0,range=self.xran[*,0],color=wbcolor,_extra=v6p0_extra,$
             ticklen=self.default[0]*1.5,/tickdir,location=[1,1,0],/exact,name='axis',title=self.title,textpos=1,textalignments=[0.5,0])  ;top
          self.drawGroup->add,self.drawxAxis[1]
       endif
       ;y axis
       self.drawyAxis[0] = obj_new('IDLgrAxis',1,range=self.yran[*,0],title=self.ytit,_extra=v6p0_extra,$
          color=wbcolor,ticklen=self.default[0],location=[-cshift,0,0],/exact,name='axis') ;left
       self.drawGroup->add,self.drawyAxis[0]
       if not keyword_set(surfplot) then begin
          self.drawyAxis[1] = obj_new('IDLgrAxis',1,range=self.yran[*,0],color=wbcolor,_extra=v6p0_extra,$
             ticklen=self.default[0],/tickdir,location=[1,1,0],/exact,/notext,name='axis')    ;right
             self.drawGroup->add,self.drawyAxis[1]
       endif
    endif
    if n_params() ge 3  then begin        ;2d data
       if n_elements(hideintbar) eq 1 then self.hideIntbar = 0>(fix(hideintbar[0]))<1
       if n_elements(shading) ne 0 then  shading  = 0>(fix(shading[0]))<1 else shading=fix(self.default[3]) ;default flat shading
       if n_elements(coltable) ne 0 then coltable = 0>(fix(coltable[0]))<40 else coltable=fix(self.default[4]) ;default rainbow color table
       drawPal = self->getpalette(coltable)
       if total(finite(self.zran[*,0])) ne 2 then begin
          zmax = max(zdat,min=zmin,/nan)
          self.zran[*,0] = [zmin,zmax]
          if self.zran[0,0] eq self.zran[1,0] then begin
             tmp = (self.zran[0,0] eq 0)? 0.5:abs(self.zran[0,0]/2.)
             self.zran[0,0] = self.zran[0,0]-tmp
             self.zran[1,0] = self.zran[1,0]+tmp
          endif
       endif
       if total(finite(self.zran[*,2])) ne 2 then begin  ;set the correct z log range from the data
          finelts = where(finite(zdat),count)
          if count gt 0 then poselts = where(zdat[finelts] gt 0,count)
          if count gt 0 then begin
             zmax = max(zdat[finelts[poselts]],min=zmin)
          endif else begin
             zmin = 1.0 & zmax = 10.0
          endelse
          finelts = -1 & poselts = -1
          self.zran[0,2] = (zmin gt self.zran[0,0])?((self.zran[0,0] gt 0)?(self.zran[0,0]):(zmin)):(self.zran[0,0])
          self.zran[1,2] = (zmax gt self.zran[1,0])?((self.zran[1,0] gt 0)?(self.zran[1,0]):(zmax)):(self.zran[1,0])
          if self.zran[1,2] le self.zran[0,2] then self.zran[1,2] = self.zran[0,2]*10.0
       endif
       if n_elements(idat) ne 0 then begin
          if total(finite(self.iran[*,2])) ne 2 then begin
             finelts = where(finite(idat),count)
             if count gt 0 then poselts = where(idat[finelts] gt 0,count)
             if count gt 0 then begin
                imax = max(idat[finelts[poselts]],min=imin)
             endif else begin
                imin = 1.0 & imax = 10.0
             endelse
             finelts = -1 & poselts = -1
             self.iran[0,2] = (imin gt self.iran[0,0])?((self.iran[0,0] gt 0)?(self.iran[0,0]):(imin)):(self.iran[0,0])
             self.iran[1,2] = (imax gt self.iran[1,0])?((self.iran[1,0] gt 0)?(self.iran[1,0]):(imax)):(self.iran[1,0])
             if self.iran[1,2] le self.iran[0,2] then self.iran[1,2] = self.iran[0,2]*10.0
          endif
       endif else if total(finite(self.iran[*,0])) ne 2 then  $
          self.iran[*,[0,2]]=self.zran[*,[0,2]]
       if not finite(self.zmin) then self.zmin = self.iran[0,2*self.ilog]
       if not finite(self.zmax) then self.zmax = self.iran[1,2*self.ilog]
       if keyword_set(surfplot) then begin
          type = 2   ;surface plot
          ;z axis
          if not obj_valid(self.drawzAxis) then begin
             self.drawzAxis = obj_new('IDLgrAxis',2,range=self.zran[*,0],title=self.ztit,name='axis',_extra=v6p0_extra,$
                 color=wbcolor,ticklen=self.default[0],location=[-cshift,1-cshift,1],/exact)
             self.drawGroup->add,self.drawzAxis
          endif
          drawPlot = obj_new('idlgrsurface',style=2,color=[255,255,255],shading=shading,palette=drawPal,name='twod',_extra=v6p0_extra)
          self.title->getproperty,strings=title & obj_destroy,self.title
          self.title = obj_new('IDLgrText',title,recompute_dimensions=2,font=self.font[4],/enable,_extra=v6p0_extra,$
             color=wbcolor,alignment=0.5,location=[0,1.05,1.0],name='titl')
          self.drawModel->add,self.title
       endif else begin
          type = 1   ;contour plot
          if keyword_set(usepolygon) then begin
             ;use idlgrpolygon object instead of idlgrcontour object to speed up plotting
             drawPlot = obj_new('IDLgrPolygon',palette=drawPal,shading=shading,style=2,shade_range=[1,255],name='twod',$
                 _extra=v6p0_extra)
          endif else begin
             drawPlot = obj_new('IDLgrContour',/fill,name='twod',c_color=1b+bindgen(255),palette=drawPal,shade_range=[1,255],$
                shading=shading,_extra=v6p0_extra)
          endelse
       endelse
       newplotInfo = {dm_plot_info,obj:drawPlot,type:type,coltable:coltable,shading:shading,legend:'',color:mycolor,psym:'',symsize:0e,$
          thick:0e,linestyle:0,xPtr:ptr_new(xdat,no_copy=no_copy),yPtr:ptr_new(ydat,no_copy=no_copy),$
          zPtr:ptr_new(zdat,no_copy=no_copy),iPtr:ptr_new(idat,no_copy=no_copy),zpos:zpos,hide:0b}
       ;colorbar
       ;check if the colorbar axis exists
       if not obj_valid(self.drawxAxis[2]) then begin
          ;x
          self.drawxAxis[2] = obj_new('IDLgrAxis',0,range=[1.1,1.2]-cshift/2.,hide=self.hideIntbar,_extra=v6p0_extra,$
             color=wbcolor,ticklen=0.0,/exact,location=[1.1-cshift/2,-cshift/4.,0],/notext,name='cbar')     ;bottom
          self.drawxAxis[3] = obj_new('IDLgrAxis',0,range=[1.1,1.2]-cshift/2.,hide=self.hideIntbar,_extra=v6p0_extra,$
             color=wbcolor,ticklen=0.0,location=[1.2-cshift/2.,1-cshift/4.,0],/exact,name='cbar',/notext)   ;top
          self.drawModel->add,self.drawxAxis[2]
          self.drawModel->add,self.drawxAxis[3]
          ;y
          self.drawyAxis[2] = obj_new('IDLgrAxis',1,range=self.iran[*,0],/notext,minor=0,hide=self.hideIntbar,$
             color=wbcolor,ticklen=self.default[0],location=[1.1-cshift/2.,-cshift/4.,0],/exact,$
             _extra=v6p0_extra,name='cbar');left
          self.drawyAxis[3] = obj_new('IDLgrAxis',1,range=self.iran[*,0],color=wbcolor,$
             hide=self.hideIntbar,ticklen=self.default[0],/tickdir,location=[1.2-cshift/2.,-cshift/4.,0],/exact,$
             name='cbar',minor=0,textpos=1,_extra=v6p0_extra) ;right
          self.drawModel->add,self.drawyAxis[2]
          self.drawModel->add,self.drawyAxis[3]
          i_level = self.iran[0,0]+findgen(256)/255.0*(self.iran[1,0]-self.iran[0,0])
          self.colBar = obj_new('IDLgrContour',transpose([[i_level],[i_level]]),geomy=i_level,geomz=-0.001,$
             geomx=[1.1,1.2]-cshift/2.,/plan,/fill,name='cbar',c_color=1b+bindgen(255),palette=drawPal,shading=shading,$
             hide=self.hideIntbar,_extra=v6p0_extra)
          self.drawModel->add,self.colBar
       endif
    endif else begin  ;1d data or filled polygon
       if keyword_set(usepolygon) then $
          type = 3 $    ;filled polygon
       else $
          type =0       ;1d plot
       nplot = n_elements(*self.plotInfo)
       if n_elements(layer) eq 0 then begin
          layer = nplot
          if layer gt 0 then onedplot=where((*self.plotInfo)[*].type eq type,layer)
       endif else begin
          if nplot gt 0 then begin
             onedplot = where((*self.plotInfo)[*].type eq type,count1)
             if count1 gt 0 then begin ;avoid plots with the same layer
                for i=0,count1-1 do begin
                    if *(*self.plotInfo)[onedplot[i]].zptr eq layer then begin
                       *(*self.plotInfo)[onedplot[i]].zptr=count1
                       if onedplot[i]+1 lt nplot then $ ;check if error bar exists
                          if (*self.plotInfo)[onedplot[i]+1].type eq -1 then $
                             *(*self.plotInfo)[onedplot[i]+1].zptr=count1
                    endif
                endfor
             endif
          endif
       endelse
       if keyword_set(usepolygon) then begin
          drawPlot = obj_new('IDLgrPolygon',name='poly',color=mycolor,_extra=v6p0_extra)
          newplotInfo = {dm_plot_info,obj:drawPlot,type:type,coltable:-1,shading:-1,legend:'',color:mycolor,psym:'',$
                    symsize:0e,thick:0e,linestyle:0,xPtr:ptr_new(xdat),yPtr:ptr_new(ydat),zPtr:ptr_new(layer),$
                    iPtr:ptr_new(),zpos:zpos,hide:0b}
       endif else begin
          if n_elements(symsize)   eq 0 then symsize=self.default[1] else symsize=(0.0>(symsize[0])<1.0)
          if n_elements(linestyle) eq 0 then linestyle=0 else linestyle=self->getlinestyle(linestyle[0])
          if n_elements(thick)     eq 0 then thick=self.default[2] else thick=1.0>(thick[0])<10.0
          if n_elements(psym)      eq 0 then psym='no symbol' else psym=self->getpsym(psym,/name)
          if n_elements(legend)    eq 0 then legend=' ' else legend=' '+self->textadjust(strtrim(legend,2),/AA)
          drawPsym = self->getpsym(psym,symsize,thick,mycolor)
          drawPlot = obj_new('IDLgrPlot',xdat,ydat,color=mycolor,symbol=drawPsym,linestyle=linestyle,zvalue=(-1.0e-4)*(1+layer),$
                    /use_zvalue,thick=thick,xrange=self.xran[*,0],yrange=self.yran[*,0],name='plot',_extra=v6p0_extra)
          newplotInfo = {dm_plot_info,obj:drawPlot,type:type,coltable:-1,shading:-1,legend:legend,color:mycolor,psym:psym,$
                    symsize:symsize,thick:thick,linestyle:linestyle,xPtr:ptr_new(xdat),yPtr:ptr_new(ydat),zPtr:ptr_new(layer),$
                    iPtr:ptr_new(),zpos:zpos,hide:0b}
          if n_elements(yerr) eq n_elements(ydat) then begin
             nx  = n_elements(xdat)
             x   = fltarr(nx*2)
             y   = x
             con = lonarr(nx*3)
             idx = lindgen(nx)
             x[idx*2L]     = xdat
             x[idx*2L+1]   = xdat
             y[idx*2L]     = ydat-yerr
             y[idx*2L+1]   = ydat+yerr
             con[idx*3L]   = 2
             con[idx*3L+1] = 2L*idx
             con[idx*3L+2] = 2L*idx+1 & idx = -1
             errorPlot = obj_new('idlgrpolyline',x,y,fltarr(nx*2)-(1.0e-4)*(0.5+layer),color=mycolor,$
                        polylines=temporary(con),thick=thick,name='error',_extra=v6p0_extra)
             self.drawGroup->add,errorPlot
             newplotInfo = [newplotInfo,{dm_plot_info,obj:errorPlot,type:-1,coltable:-1,shading:-1,legend:'',color:mycolor,psym:'',$
                        symsize:0e,thick:thick,linestyle:0,xPtr:ptr_new(x,/no_copy),yPtr:ptr_new(y,/no_copy),zPtr:ptr_new(layer),iPtr:ptr_new(),$
                        zpos:zpos,hide:0b}]
          endif
       endelse
    endelse
    self.drawGroup->add,drawPlot
    if keyword_set(no_copy) then begin ;destroy xdat and ydat and zdat
       xdat = 0 & tmp = temporary(xdat)
       ydat = 0 & tmp = temporary(ydat)
       zdat = 0 & tmp = temporary(zdat)
    endif
    if n_elements(*self.plotInfo) eq 0 then $
       *self.plotInfo = newplotInfo $
    else $
       *self.plotInfo = [*self.plotInfo,newplotInfo]
    if type eq 2 then begin    ;initial rotation for surface plot
       self.drawGroup->rotate,[1,0,0],-90
       self.drawGroup->rotate,[0,1,0],30
       self.drawGroup->rotate,[1,0,0],30
    endif
    onedplot = where((*self.plotInfo)[*].type eq 0,count0)
    twodplot = where(((*self.plotInfo)[*].type gt 0) and ((*self.plotInfo)[*].type lt 3),count1)
    sufplot  = where((*self.plotInfo)[*].type eq 2,count2)
    polyplot = where((*self.plotInfo)[*].type eq 3,count3)
    ;allow(disallow) changing ztitle,zran,colortable, disallow(allow) changing color,psym,and linestyle
    sensitive = (count2 gt 0)
    self->my_widget_control,'dm_'+['ztitBut','zlogBut','zranBut'],sensitive=sensitive
    sensitive = (count1 gt 0)
    self->my_widget_control,'dm_'+['iranBut','ilogBut','cs_coltable','cs_shade'],sensitive=sensitive
    id = self->my_widget_id('dm_cs_hidecbar')
    if id gt 0 then widget_control,id,sensitive=sensitive
    if sensitive then dm_set_button,id,self.hideIntbar,onstring='Show Colorbar',offstring='Hide Colorbar'
    sensitive = (count0 gt 0)
    self->my_widget_control,'dm_'+['psymBut','lineBut','lgndBut'],sensitive=sensitive
    id = self->my_widget_id('dm_cs_hidelegend')
    if id gt 0 then widget_control,id,sensitive=sensitive
    if sensitive then begin
       self.drawLegend->setproperty,hide=self.hideLegend
       dm_set_button,id,self.hideLegend,onstring='Show Legend',offstring='Hide Legend'
    endif else $
       self.drawLegend->setproperty,/hide
    sensitive = (count0 gt 0) or (count3 gt 0)
    self->my_widget_control,'dm_pcolBut',sensitive=sensitive
end

;add a text to the object
;parameters:
;   xpos,ypos:   normalized position of the text in the plot window
;keywords:
;   orientation: the angle of the baseline orientation
pro dm_plot::add_text,text,xpos,ypos,color=color,fontname=fontname,fontsize=fontsize,orientation=orientation
    if n_elements(text) eq 0 then return
    if n_elements(xpos) eq 0 then xpos = 0.04
    if n_elements(ypos) eq 0 then ypos = 0.9
    text = self->textadjust(text,/AA)
    if float(!version.release) ge 6.0 then v6p0_extra= {register_properties:1}  ;register_properties keyword for IDL6.0 or later
    if n_elements(fontname) eq 0 then fontname = 'helvetica'
    if n_elements(fontsize) eq 0 then fontsize = 8
    if n_elements(color)    eq 0 then color    = (['white','black'])[self.bgcol]
    self.drawView->getproperty,dimensions=dim                 ;viewport size
    nsize = fix((1>min(dim/self.default[5:6]))*fontsize)
    ofont = obj_new('idlgrfont',fontname,size=nsize,substitute='Hershey')
    if n_elements(orientation) eq 0 then orientation = 0.0
    orientation = orientation*!dtor
    orie_cos = cos(orientation) & orie_sin = sin(orientation)
    baseline = [orie_cos,orie_sin]
    updir    = [-orie_sin,orie_cos]
    otext = obj_new('idlgrtext',text,font=ofont,color=self->getcolor(color),xcoord_conv=[xpos,1],$
            ycoord_conv=[ypos,1],zcoord_conv=[1.0,1.0],recompute_dimensions=2,/enable,$
            baseline=baseline,updir=updir,_extra=v6p0_extra,name='text')
    self.drawModel->add,otext
    self.drawWin->draw,self.drawView
    help,ofont,output=id & id=strsplit(id,' ',/extract) & id=id[n_elements(id)-1]
    if n_elements(*self.textsize) eq 0 then *self.textsize=[id,dm_to_string(fontsize)] $
    else *self.textsize=[*self.textsize,id,dm_to_string(fontsize)]
end

;remove all text strings
pro dm_plot::remove_text
    oChildArr = self.drawModel->IDL_Container::Get(/ALL, COUNT=nKids)
    for i=0,nKids-1 do begin
        if obj_isa(oChildArr[i],'IDLgrText') then begin
           oChildArr[i]->getproperty,name=name
           if name eq 'text' then begin
              oChildArr[i]->getproperty,font=ofont
              obj_destroy,[ofont,oChildArr[i]]
           endif
        endif
    endfor
    self.cursorpos->setproperty,strings=''  ;cursor position string
end

;draw the data using object graphics
pro dm_plot::draw,view=view
    widget_control,/hourglass
    self->totop ;push the drawwindow to the top

    if keyword_set(view) then begin ;show the view only
       self.drawView->setproperty,hide=0
       self.drawWin->draw,self.drawView
       return
    endif

    nplot = n_elements(*self.plotInfo)
    if nplot eq 0 then begin
       self.drawView->setproperty,hide=0
       self.drawWin->draw,self.drawView
       return
    endif

    widget_control,self.tlb,update=0
    widget_control,self.plotWin,/DRAW_EXPOSE_EVENTS
    surfplot = where((*self.plotInfo)[*].type eq 2,surfcount)
    onedplot = where((*self.plotInfo)[*].type eq 0,onedcount)
    if surfcount gt 0 then cshift = [-0.5,0] else cshift = [0,0]

    if self.xlog eq 1 then xran = alog10(self.xran[*,2]) else xran = self.xran[*,0]
    if self.ylog eq 1 then yran = alog10(self.yran[*,2]) else yran = self.yran[*,0]
    if self.zlog eq 1 then zran = alog10(self.zran[*,2]) else zran = self.zran[*,0]
    if self.ilog eq 1 then iran = alog10(self.iran[*,2]) else iran = self.iran[*,0]
    if total(finite(xran)) ne 2 then xconv = [0.0,1.0] else xconv = norm_coord(xran)
    if total(finite(yran)) ne 2 then yconv = [0.0,1.0] else yconv = norm_coord(yran)
    if total(finite(zran)) ne 2 then zconv = [0.0,1.0] else zconv = norm_coord(zran)
    if total(finite(iran)) ne 2 then iconv = [0.0,1.0] else iconv = norm_coord(iran)
    if surfcount eq 0 then zconv = [0.0,1.0]

    ;set x,y coordinate conversions
    oChildArr = self.drawModel->IDL_Container::Get(/ALL, COUNT=nKids)
    for i=0,nKids-1 do begin
        if obj_isa(oChildArr[i],'IDLgrAxis') then begin   ;axis
           oChildArr[i]->getproperty,direction=dir
           if dir eq 1 then begin
              oChildArr[i]->setproperty,ycoord_conv=iconv+cshift/4.,range=self.iran[*,2*self.ilog],$
                 minor=(self.ilog eq 1)?(-1):0,log=self.ilog
           endif
           oChildArr[i]->getproperty,ticktext=tick
           tick->setproperty,font=self.font[0],recompute_dimensions=2
           oChildArr[i]->setproperty,ticktext=tick,thick=self.axisthick
        endif else if obj_isa(oChildArr[i],'IDLgrContour') then begin ;contour
           i_level = iran[0]+findgen(256)/255.0*(iran[1]-iran[0])
           oChildArr[i]->setproperty,ycoord_conv=iconv+cshift/4.,$
              data_value=transpose([[i_level],[i_level]]),c_value=i_level,geomy=i_level,shading=max((*self.plotInfo)[*].shading)
        endif
    endfor

    oChildArr = self.drawGroup->IDL_Container::Get(/ALL, COUNT=nKids)
    clipplane = [[-1,0,0,xran[0]],[1,0,0,-xran[1]],[0,-1,0,yran[0]],[0,1,0,-yran[1]]]
    for i=0,nKids-1 do begin
        if obj_isa(oChildArr[i],'IDLgrAxis') then begin
           oChildArr[i]->getproperty,direction=dir
           if dir eq 0 then begin
              oChildArr[i]->setproperty,xcoord_conv=xconv+cshift,range=self.xran[*,2*self.xlog],log=self.xlog
           endif else if dir eq 1 then begin
              oChildArr[i]->setproperty,ycoord_conv=yconv+cshift,range=self.yran[*,2*self.ylog],log=self.ylog
           endif else begin
              oChildArr[i]->setproperty,zcoord_conv=zconv,range=self.zran[*,2*self.zlog],log=self.zlog
           endelse
           oChildArr[i]->getproperty,ticktext=tick
           tick->setproperty,recompute_dimensions=2,font=self.font[0]
           oChildArr[i]->setproperty,ticktext=tick,thick=self.axisthick
        endif
    endfor
    for i=0,n_elements(*self.plotInfo)-1 do begin
        case (*self.plotInfo)[i].type of
           ;error bars,IDLgrPolyline object
           -1:  begin
                x     = (*(*self.plotInfo)[i].xPtr)
                y     = (*(*self.plotInfo)[i].yPtr)
                layer = (*(*self.plotInfo)[i].zPtr)
                if (float(!version.release) lt 5.6) then begin
                   index_x = where((x ge self.xran[0,2*self.xlog]) and (x le self.xran[1,2*self.xlog]),count_x)
                   if count_x gt 0 then begin
                      x = x[index_x]
                      y = y[index_x] & index_x=-1
                   endif else begin
                      x = (self.xran[1,2*self.xlog]+1e2)*[1.0,1.0]
                      y = (self.yran[1,2*self.ylog])*[1.0,1.0]
                   endelse
                endif
                if (float(!version.release) lt 5.6) then begin
                   index_y = where(y gt self.yran[1,2*self.ylog],count_y)
                   if count_y ne 0 then y[index_y] = self.yran[1,2*self.ylog]
                   index_y = where(y lt self.yran[0,2*self.ylog],count_y)
                   if count_y ne 0 then y[index_y] = self.yran[0,2*self.ylog] & index_y = -1
                endif
                if self.xlog then begin
                   index_x = where(x gt 0,count_x)
                   if count_x gt 0 then begin
                      x = x[index_x]
                      y = y[index_x] & index_x=-1
                   endif else begin
                      x = (self.xran[1,2*self.xlog]+1e2)*[1.0,1.0]
                      y = (self.yran[1,2*self.ylog])*[1.0,1.0]
                   endelse
                endif
                if self.ylog then begin
                   index_y = where(y le 0, count_y)
                   if count_y ne 0 then y[index_y] = self.yran[0,2]
                   index_y = -1
                endif
                nx   = n_elements(x)/2
                zpos = 0.0
                if finite((*self.plotInfo)[i].zpos) then $
                   zpos = (*self.plotInfo)[i].zpos
                if self.zlog then begin
                   if zpos gt 0 then zpos = alog10(zpos) $
                   else if finite(self.zran[1,2]) then zpos = alog10(self.zran[1,2])+1.0
                endif
                zpos = (-1.0e-4)*(0.5+layer)+zpos
                z    = fltarr(nx*2)+zpos
                con  = lonarr(nx*3)
                idx  = lindgen(nx)
                con[idx*3]   = 2
                con[idx*3+1] = 2*idx
                con[idx*3+2] = 2*idx+1
                if self.xlog eq 1 then x = alog10(x)
                if self.ylog eq 1 then y = alog10(y)
                x = transpose(x) & y = transpose(y) & z = transpose(z)
                (*self.plotInfo)[i].obj->setproperty,xcoord_conv=xconv+cshift,polylines=temporary(con),$
                    ycoord_conv=yconv+cshift,zcoord_conv=zconv,data=[temporary(x),temporary(y),temporary(z)]
                end
           ;1d plot,IDLgrPlot object
           0:   begin
                x     = (*(*self.plotInfo)[i].xPtr)
                y     = (*(*self.plotInfo)[i].yPtr)
                layer = (*(*self.plotInfo)[i].zPtr)
                if self.xlog then begin
                   index_x = where(x gt 0,count_x)
                   if count_x gt 0 then begin
                      x = x[index_x]
                      y = y[index_x] & index_x = -1
                   endif else begin
                      x = self.xran[1,2]*10 ;fake data
                      y = self.yran[1,2]*10
                   endelse
                endif
                if self.ylog then begin
                   index_y = where(y gt 0,count_y)
                   if count_y gt 0 then begin
                      x = x[index_y]
                      y = y[index_y] & index_y = -1
                   endif else begin
                      x = self.xran[1,2]*10 ;fake data
                      y = self.yran[1,2]*10
                   endelse
                endif
                if self.xlog eq 1 then x = alog10(x)
                if self.ylog eq 1 then y = alog10(y)
                zpos = 0.0
                if finite((*self.plotInfo)[i].zpos) then $
                   zpos = (*self.plotInfo)[i].zpos
                if self.zlog then begin
                   if zpos gt 0 then zpos = alog10(zpos) $
                   else if finite(self.zran[1,2]) then zpos = alog10(self.zran[1,2])+1.0
                endif
                zpos = (-1.0e-4)*(1+layer)+zpos
                (*self.plotInfo)[i].obj->setproperty,xcoord_conv=xconv+cshift,ycoord_conv=yconv+cshift,$
                    zcoord_conv=zconv,xran=xran,yran=yran,datax=temporary(x),datay=temporary(y),zvalue=zpos
                end
           ;2d plot, IDLgrContour or IDLgrPolygon object
           1:   begin
                xdat = (*(*self.plotInfo)[i].xPtr)
                ydat = (*(*self.plotInfo)[i].yPtr)
                zdat = (*(*self.plotInfo)[i].zPtr)
                if (float(!version.release) lt 5.6) or (self.xlog eq 1) or (self.ylog eq 1) then begin
                   ind_x = where((xdat ge self.xran[0,2*self.xlog]) and (xdat le self.xran[1,2*self.xlog]),count_x)
                   ind_y = where((ydat ge self.yran[0,2*self.ylog]) and (ydat le self.yran[1,2*self.ylog]),count_y)
                   if count_x le 1 or count_y le 1 then begin
                      xdat = self.xran[*,self.xlog*2]
                      ydat = self.yran[*,self.ylog*2]
                      zdat = fltarr(2,2)  & zdat[*] = !values.f_nan
                   endif else begin
                      xdat = xdat[ind_x]
                      ydat = ydat[ind_y]
                      zdat = zdat[ind_x,*] & zdat = zdat[*,ind_y]
                   endelse
                endif
                if self.xlog eq 1 then xdat = alog10(xdat)
                if self.ylog eq 1 then ydat = alog10(ydat)
                if self.ilog eq 1 then begin
                   tmp = where(finite(zdat),count)
                   if count gt 0 then index = where(zdat[tmp] le 0,count)
                   if count gt 0 then zdat[tmp[index]] = !values.f_nan
                   zdat = alog10(zdat)
                endif
                zpos = 0.0
                if finite((*self.plotInfo)[i].zpos) then $
                   zpos = (*self.plotInfo)[i].zpos
                if self.zlog then begin
                   if zpos gt 0 then zpos = alog10(zpos) $
                   else if finite(self.zran[1,2]) then zpos = alog10(self.zran[1,2])+1.0
                endif
                zpos = (-1.0e-2)+zpos
                if obj_isa((*self.plotInfo)[i].obj,'IDLgrPolygon') then begin
                   nx   = n_elements(xdat)+1
                   ny   = n_elements(ydat)+1
                   xdat = [xdat[0],(xdat[0:(0>(nx-3L))]+xdat[1:(nx-2L)])/2.,xdat[nx-2L]]
                   ydat = [ydat[0],(ydat[0:(0>(ny-3L))]+ydat[1:(ny-2L)])/2.,ydat[ny-2L]]
                   conn = lonarr(5L*(nx-1L)*(ny-1L))
                   conn_idx = lindgen((nx-1L)*(ny-1L))*5L
                   vert_idx = reform((lindgen(nx,ny))[0:(nx-2L),0:(ny-2L)],(nx-1L)*(ny-1L))
                   conn[conn_idx]   = 4L
                   conn[conn_idx+1] = 0L+vert_idx
                   conn[conn_idx+2] = 1L+vert_idx
                   conn[conn_idx+3] = 1L+vert_idx+nx
                   conn[temporary(conn_idx)+4] = 0L+temporary(vert_idx)+nx
                   dattype = max([size(xdat[0],/type),size(ydat[0],/type)])
                   if dattype eq size(0d,/type) then begin  ;double
                      xdat = xdat#(dblarr(ny)+1d) & ydat = (dblarr(nx)+1d)#ydat
                   endif else begin                         ;float
                      xdat = xdat#(fltarr(ny)+1e) & ydat = (fltarr(nx)+1e)#ydat
                   endelse
                   data = [[reform(temporary(xdat),nx*ny)],[reform(temporary(ydat),nx*ny)],[fltarr(nx*ny)+zpos]]
                   data = transpose(data)
                   zdat = [[zdat],[zdat[*,(ny-2L)]]]
                   zdat = [zdat,zdat[(nx-2L),*]]
                   vc   = intarr(n_elements(zdat))
                   ;finite index
                   index = where(finite(zdat),count)
                   if count ne 0 then begin
                      vc[index] = 1+round((zdat[index]-iran[0])/(iran[1]-iran[0])*254.)
                      index0 = where(zdat[index] ge iran[1],count)
                      if count ne 0 then vc[index[index0]]=255
                      index0 = where(zdat[index] lt iran[0],count)
                      if count ne 0 then vc[index[index0]]=1
                      index = -1 & index0=-1
                   endif
                   zdat = -1
                   (*self.plotInfo)[i].obj->setproperty,xcoord_conv=xconv+cshift,ycoord_conv=yconv+cshift,$
                      zcoord_conv=zconv,vert_colors=temporary(vc),data=temporary(data),polygons=temporary(conn)
                endif else begin    ;IDLgrContour
                   nx   = n_elements(xdat)
                   ny   = n_elements(ydat)
                   xdat = (temporary(xdat))#(fltarr(ny)+1.) & ydat=(fltarr(nx)+1.)#(temporary(ydat))
                   i_level = iran[0]+findgen(256)/255.0*(iran[1]-iran[0])
                   i_level[255] = (self.ilog eq 1)?(alog10((self.zmax gt 0)?(self.zmax):(self.iran[1,2]))):(self.zmax)
                   (*self.plotInfo)[i].obj->setproperty,xcoord_conv=xconv+cshift,ycoord_conv=yconv+cshift,zcoord_conv=zconv,$
                      c_value=i_level,geomx=temporary(xdat),geomy=temporary(ydat),data_values=temporary(zdat),geomz=zpos,/planar
                endelse
                end
           ;2d plot, IDLgrSurface object
           2:   begin
                xdat = (*(*self.plotInfo)[i].xPtr)
                ydat = (*(*self.plotInfo)[i].yPtr)
                zdat = (*(*self.plotInfo)[i].zPtr)
                if n_elements(*(*self.plotInfo)[i].iPtr) ne 0 then $
                   idat = (*(*self.plotInfo)[i].iPtr) $
                else $
                   idat = zdat
                if (float(!version.release) lt 5.6) or (self.xlog eq 1) or (self.ylog eq 1) then begin
                   ind_x = where((xdat ge self.xran[0,2*self.xlog]) and (xdat le self.xran[1,2*self.xlog]),count_x)
                   ind_y = where((ydat ge self.yran[0,2*self.ylog]) and (ydat le self.yran[1,2*self.ylog]),count_y)
                   if count_x le 1 or count_y le 1 then begin
                      xdat = self.xran[*,self.xlog*2]
                      ydat = self.yran[*,self.ylog*2]
                      zdat = fltarr(2,2) & zdat[*]=!values.f_nan
                      idat = fltarr(2,2) & idat[*]=!values.f_nan
                   endif else begin
                      xdat = xdat[ind_x]
                      ydat = ydat[ind_y]
                      zdat = zdat[ind_x,*] &zdat=zdat[*,ind_y]
                      idat = idat[ind_x,*] &idat=idat[*,ind_y]
                   endelse
                endif
                if self.xlog eq 1 then xdat = alog10(xdat)
                if self.ylog eq 1 then ydat = alog10(ydat)
                if self.zlog eq 1 then zdat = alog10(zdat)
                if self.ilog eq 1 then idat = alog10(idat)
                vc = intarr(n_elements(idat))
                ;finite index
                index = where(finite(idat),count)
                if count ne 0 then begin
                   vc[index] = 1+round((idat[index]-iran[0])/(iran[1]-iran[0])*254.)
                   index0 = where(idat[index] ge iran[1],count)
                   if count ne 0 then vc[index[index0]] = 255
                   index0 = where(idat[index] lt iran[0],count)
                   if count ne 0 then vc[index[index0]] = 1
                   index = -1 & index0 = -1
                endif
                idat = -1 ;destroy idat
                (*self.plotInfo)[i].obj->setproperty,xcoord_conv=xconv+cshift,ycoord_conv=yconv+cshift,$
                   zcoord_conv=zconv,vert_colors=temporary(vc),min_value=zran[0],max_value=zran[1],$
                   datax=temporary(xdat),datay=temporary(ydat),dataz=temporary(zdat)
                end
           ;1d polygon fill plot,IDLgrPolygon object
           3:   begin
                x     = (*(*self.plotInfo)[i].xPtr)
                y     = (*(*self.plotInfo)[i].yPtr)
                layer = (*(*self.plotInfo)[i].zPtr)
                if self.xlog then begin
                   ind_x = where(x le 0,count_x)
                   if count_x gt 0 then begin
                      x[ind_x] = 1e-16  ;assign a very small number
                      ind_x    = -1
                   endif
                endif
                if self.ylog then begin
                   ind_y = where(y le 0,count_y)
                   if count_y gt 0 then begin
                      y[ind_y] = 1e-16  ;assign a very small number
                      ind_y    = -1
                   endif
                endif
                ;tessellation
                oTess = obj_new('IDLgrTessellator')
                oTess->AddPolygon,x,y
                result = oTess->Tessellate(data,conn)
                obj_destroy,oTess
                if result eq 0 then break   ;tessellation fails
                if self.xlog eq 1 then data[0,*] = alog10(data[0,*])
                if self.ylog eq 1 then data[1,*] = alog10(data[1,*])
                zpos = 0.0
                if finite((*self.plotInfo)[i].zpos) then $
                   zpos = (*self.plotInfo)[i].zpos
                if self.zlog then begin
                   if zpos gt 0 then zpos = alog10(zpos) $
                   else if finite(self.zran[1,2]) then zpos = alog10(self.zran[1,2])+1.0
                endif
                zpos = (-1.0e-4)*(1+layer)+zpos
                tmp  = size(data,/dimension)
                data = transpose([[transpose(data)],[fltarr(tmp[1])+zpos]])
                (*self.plotInfo)[i].obj->setproperty,xcoord_conv=xconv+cshift,ycoord_conv=yconv+cshift,$
                      zcoord_conv=zconv,data=temporary(data),polygons=temporary(conn)
                end
           else:
        endcase
        if float(!version.release) ge 5.6 then $
           (*self.plotInfo)[i].obj->setproperty,clip_planes=clipplane
    endfor

    ;update the drawlegend
    self->updatelegend

    ;make grids
    self.drawxAxis[0]->getproperty,tickvalues=xticks
    self.drawyAxis[0]->getproperty,tickvalues=yticks
    if self.xlog then xticks = alog10(xticks)
    if self.ylog then yticks = alog10(yticks)
    nxtick = n_elements(xticks) & nytick = n_elements(yticks)
    if surfcount gt 0 then onedcount = -1
    xdata = fltarr(3,nxtick*2) & xconn = intarr(3*nxtick) & xdata[2,*] = (-1e-7)*(1+onedcount)
    ydata = fltarr(3,nytick*2) & yconn = intarr(3*nytick) & ydata[2,*] = (-1e-7)*(1+onedcount)
    for i=0,nxtick-1 do begin
        xdata[0,2*i:2*i+1] = xticks[i]
        xdata[1,2*i]       = (self.ylog eq 1)?alog10(self.yran[0,2]):self.yran[0,0]
        xdata[1,2*i+1]     = (self.ylog eq 1)?alog10(self.yran[1,2]):self.yran[1,0]
        xconn[3*i:3*i+2]   = [2,2*i,2*i+1]
    endfor
    for i=0,nytick-1 do begin
        ydata[1,2*i:2*i+1] = yticks[i]
        ydata[0,2*i]       = (self.xlog eq 1)?alog10(self.xran[0,2]):self.xran[0,0]
        ydata[0,2*i+1]     = (self.xlog eq 1)?alog10(self.xran[1,2]):self.xran[1,0]
        yconn[3*i:3*i+2]   = [2,2*i,2*i+1]
    endfor
    self.xgrid->setproperty,data=xdata,polyline=xconn,xcoord_conv=norm_coord(xran)+cshift,$
        ycoord_conv=norm_coord(yran)+cshift
    self.ygrid->setproperty,data=ydata,polyline=yconn,xcoord_conv=norm_coord(xran)+cshift,$
        ycoord_conv=norm_coord(yran)+cshift

    ;set boundary
    self->set_view

    ;draw it
    self.drawWin->draw,self.drawView

    widget_control,self.tlb,update=1
end

;erase everything
pro dm_plot::erase,nodraw=nodraw
    self->remove_text
    obj_destroy,self.drawxAxis[0:1]
    obj_destroy,self.drawyAxis[0:1]
    self.xgrid->setproperty,data=[0,0],polyline=-1
    self.ygrid->setproperty,data=[0,0],polyline=-1
    oChildArr = self.drawModel->IDL_Container::Get(/ALL, COUNT=nKids)
    for i=0,nKids-1 do begin
        if (not obj_isa(oChildArr[i],'IDLgrModel')) and (not obj_isa(oChildArr[i],'IDLgrLegend')) $
           and (not obj_isa(oChildArr[i],'IDLgrText')) then $
           obj_destroy,oChildArr[i]
    endfor
    oChildArr = self.drawGroup->IDL_Container::Get(/ALL, COUNT=nKids)
    for i=0,nKids-1 do begin
        if obj_isa(oChildArr[i],'IDLgrPlot') then begin
           oChildArr[i]->getproperty,symbol=tmp1
           if obj_valid(tmp1) then begin
              tmp1[0]->getproperty,data=tmp2
              if obj_valid(tmp2) then obj_destroy,tmp2
              obj_destroy,tmp1
           endif
        endif else if obj_isa(oChildArr[i],'IDLgrPolygon') or obj_isa(oChildArr[i],'IDLgrContour') or $
           obj_isa(oChildArr[i],'IDLgrSurface') then begin
           oChildArr[i]->getproperty,palette=tmp
           if obj_valid(tmp) then obj_destroy,tmp
        endif
        if (oChildArr[i] ne self.xgrid) and (oChildArr[i] ne self.ygrid) then $
           obj_destroy,oChildArr[i]
    endfor
    if n_elements(*self.plotInfo) ne 0 then ptr_free,(*self.plotInfo)[*].xPtr,(*self.plotInfo)[*].yPtr,$
         (*self.plotInfo)[*].zPtr,(*self.plotInfo)[*].iPtr
    ptr_free,self.plotInfo & self.plotInfo=ptr_new(/allocate_heap)
    self.drawGroup->reset
    self.drawModel->reset
    self.drawLegend->getproperty,item_object=item_object
    obj_destroy,item_object
    self.drawLegend->setproperty,item_object=[obj_new()],item_name=[''],item_linestyle=[6]
    if not keyword_set(nodraw) then self->draw,/view
end

;handle all events that are passed from dm_plot_event and require access to the internal variables
pro dm_plot::event,event
    bwcolor  = (['white','black'])[self.bgcol]  ;default black or white color
    if float(!version.release) ge 6.0 then v6p0_extra= {register_properties:1}  ;register_properties keyword for IDL6.0 or later
    eventname=widget_info(event.id,/uname)
    case eventname of
       'dm_tlb':      self->resize,event
       'dm_exitBut':  obj_destroy,self
       'dm_readBut':  self->readasciifile,/oned
       'dm_readSpe':  self->readasciifile,/twod
       'dm_save':     self->saveas,'ps'
       'dm_saveps':   self->saveas,'ps'
       'dm_savejpg':  self->saveas,'jpeg'
       'dm_savegif':  self->saveas,'gif'
       'dm_savetif':  self->saveas,'tiff'
       'dm_savebmp':  self->saveas,'bmp'
       'dm_savepng':  self->saveas,'png'
       'dm_saveppm':  self->saveas,'ppm'
       'dm_saveasc':  self->saveas,'ascii'
       'dm_blackbg':  self->setproperty,misscol=0
       'dm_whitebg':  self->setproperty,misscol=1
       'dm_idltick':  self->setproperty,tickstyle=0
       'dm_owntick':  self->setproperty,tickstyle=1
       'dm_bgblack':  self->setproperty,bgcolor=0
       'dm_bgwhite':  self->setproperty,bgcolor=1
       'dm_printBut': self->saveas,'printer'
       'dm_keepBut':begin
            self->setproperty,keep=1b
            sendevent = {dm_plot_keep,ID:self.tlb,TOP:self.group_leader,HANDLER:self.tlb,object:self}
            if obj_valid(self.parentobj) then $
               call_method,self.parenthandler,self.parentobj,sendevent $
            else if self.group_leader ne 0 then $
               widget_control,self.group_leader,send_event=sendevent,/no_copy
            end
       'dm_mkcrBut':begin
            self->setproperty,keep=0b
            sendevent = {dm_plot_make_current,ID:self.tlb,TOP:self.group_leader,HANDLER:self.tlb,object:self}
            if obj_valid(self.parentobj) then $
               call_method,self.parenthandler,self.parentobj,sendevent $
            else if self.group_leader ne 0 then $    ; send an event there
               widget_control,self.group_leader,send_event=sendevent,/no_copy
            end
       'dm_show_all':begin
            for i=0,n_elements(*self.plotInfo)-1 do begin
                (*self.plotInfo)[i].obj->setproperty,hide=0
                (*self.plotInfo)[i].hide = 0
            endfor
            if obj_valid(self.title) then self.title->setproperty,hide=0
            ;show all additional text objects
            oChildArr = self.drawModel->IDL_Container::Get(/ALL, COUNT=nKids)
            for i=0,nKids-1 do begin
                if obj_isa(oChildArr[i],'IDLgrText') and (oChildArr[i] ne self.cursorpos) then $
                   oChildArr[i]->setproperty,hide=0
            endfor
            self->draw
            widget_control,event.id,sensitive=0
            end
       'dm_textBut':begin
            all_col  = [bwcolor,'red','blue','magenta','green','cyan','yellow','grey','dark grey','dark red',$
                        'dark blue','dark magenta','dark green','dark cyan','dark yellow']
            all_font = ['helvetica','courier','times','symbol','monospace symbol','hershey']
            default  = ['','0','0','12','0']
            new = dm_dialog_input(['text:','orientation:','font:','font size:','color:'],title='Add text',$
                  default=default,is_droplist=[0,0,1,0,1],droplist_content=[ptr_new(all_font),ptr_new(all_col)],$
                  xsize=130,dialog_parent=self.tlb)
            if strlen(new[0]) eq 0 then break   ;null string
            xstart = 0.04 & ystart = 0.9;1.01
            if n_elements(*self.plotInfo) gt 0 then begin
               ind = where((*self.plotInfo)[*].type eq 2,nsurf)
               if nsurf ne 0 then xstart = -0.6    ;surface plot
            endif
            fsize = (8>(dm_to_number(new[3],/int)))
            orientation = dm_to_number(new[1],/float)
            if not finite(orientation) then orientationi = 0.0
            self->add_text,new[0],xstart,ystart,fontname=new[2],fontsize=fsize,orientation=orientation,color=new[4]
            end
       'dm_isoBut':     self->setproperty,iso=(1b)-self.iso
       'dm_xgridBut':   self->setproperty,showxgrid=(1b)-self.showxgrid
       'dm_ygridBut':   self->setproperty,showygrid=(1b)-self.showygrid
       'dm_showcposBut':self->setproperty,showcursorpos=(1b)-self.showcpos
       'dm_titlBut':begin
            self.title->getproperty,strings=title
            new = dm_dialog_input('title:',title='Set title',xsize=150,default=title,dialog_parent=self.tlb)
            if new ne title then self->setproperty,title=self->textadjust(new,/AA)
            end
       'dm_xranBut':begin
            new = dm_dialog_input(['from:','to:'],title='Set xrange',xsize=100,$
                default=float(self.xran[*,2*self.xlog]),/float,dialog_parent=self.tlb)
            if total(finite(new)) eq 2 then $
               if total(abs(new-self.xran[*,2*self.xlog])) ne 0 then $
            if new[1] gt new[0] then  self->setproperty,xran=new
            end
       'dm_xlogBut':self->setproperty,xlog=(1b)-self.xlog
       'dm_xtitBut':begin
            self.xtit->getproperty,strings=xtit
            new = dm_dialog_input('x title:',title='Set xtitle',xsize=150,default=xtit,dialog_parent=self.tlb)
            if new ne xtit then self->setproperty,xtit=self->textadjust(new,/AA)
            end
       'dm_yranBut':begin
            new = dm_dialog_input(['from:','to:'],title='Set yrange',xsize=100,$
                default=float(self.yran[*,2*self.ylog]),/float,dialog_parent=self.tlb)
            if total(finite(new)) eq 2 then $
               if total(abs(new-self.yran[*,2*self.ylog])) ne 0 then $
            if new[1] gt new[0] then self->setproperty,yran=new
            end
       'dm_ylogBut':self->setproperty,ylog=(1b)-self.ylog
       'dm_ytitBut':begin
            self.ytit->getproperty,strings=ytit
            new = dm_dialog_input('y title:',title='Set ytitle',xsize=150,default=ytit,dialog_parent=self.tlb)
            if new ne ytit then self->setproperty,ytit=self->textadjust(new,/AA)
            end
       'dm_ztitBut':begin
            self.ztit->getproperty,strings=ztit
            new = dm_dialog_input('z title:',title='Set ztitle',xsize=150,default=ztit,dialog_parent=self.tlb)
            if new ne ztit then self->setproperty,ztit=self->textadjust(new,/AA)
            end
       'dm_zranBut':begin
            new = dm_dialog_input(['from:','to:'],title='Set zrange',xsize=100,$
                default=float(self.zran[*,2*self.zlog]),/float,dialog_parent=self.tlb)
            if total(finite(new)) eq 2 then $
               if total(abs(new-self.zran[*,2*self.zlog])) ne 0 then $
                  if new[1] gt new[0] then self->setproperty,zran=new
            end
       'dm_zlogBut':self->setproperty,zlog=(1b)-self.zlog
       'dm_iranBut':begin
            new = dm_dialog_input(['from:','to:'],title='Set irange',xsize=100,$
                default=float(self.iran[*,2*self.ilog]),/float,dialog_parent=self.tlb)
            if total(finite(new)) eq 2 then $
               if total(abs(new-self.iran[*,2*self.ilog])) ne 0 then $
                  if new[1] gt new[0] then self->setproperty,iran=new
            end
       'dm_ilogBut':self->setproperty,ilog=(1b)-self.ilog
       'dm_psymBut':begin
            if n_elements((*self.plotInfo)) eq 0 then break ; no plots
            onedplot = where((*self.plotInfo)[*].type eq 0,count)        & if count eq 0 then break
            all_psym = ['no symbol','circle','diamond','triangle','inverted triangle','square',$
                'plus','star','dot','cross','greater','less','filled circle','filled diamond',$
                'filled triangle','filled inverted triangle','filled square']
            name = strarr(count*2) & default=fltarr(count*2) & is_droplist=bytarr(count*2) & old=strarr(count*2)
            for i=0,count-1 do begin
                name[(2*i):(2*i+1)] = ['line '+dm_to_string(i)+': symbol name','       '+'symbol size']
                default[2*i]        = 0>(where(all_psym eq (*self.plotInfo)[onedplot[i]].psym))
                default[2*i+1]      = (*self.plotInfo)[onedplot[i]].symsize
                old[2*i]            = (*self.plotInfo)[onedplot[i]].psym
                old[2*i+1]          = dm_to_string((*self.plotInfo)[onedplot[i]].symsize)
                is_droplist[(2*i):(2*i+1)] = [1,0]
            endfor
            if count eq 1 then name = ['symbol name','symbol size']
            new = dm_dialog_input(name,title='Set plot symbol',default=default,is_droplist=is_droplist,$
                droplist_content=ptr_new(all_psym),xsize=120,dialog_parent=self.tlb)
            index = where(strlen(new) eq 0,count0)
            if count0 gt 0 then new[index]=old[index]
            changeid = -1
            for i=0,count-1 do $
                if (new[2*i] ne old[2*i]) or (new[2*i+1] ne old[2*i+1]) then begin
                   (*self.plotInfo)[onedplot[i]].psym = new[2*i]
                   (*self.plotInfo)[onedplot[i]].symsize = 0.0>(dm_to_number(new[2*i+1]))<1.0
                   changeid = [changeid,onedplot[i]]
                endif
            if n_elements(changeid) gt 1 then self->setproperty,plotInfo=(*self.plotInfo),$
                changeid=changeid[1:(n_elements(changeid)-1)]
            end
       'dm_lineBut':begin
            if n_elements((*self.plotInfo)) eq 0 then break ; no plots
            onedplot  = where((*self.plotInfo)[*].type eq 0,count)        & if count eq 0 then break
            all_lines = ['solid','dotted','dashed','dash dot','dash dot dot dot','long dash','no line']
            name = strarr(count*2) & default = fltarr(count*2)
            is_droplist = bytarr(count*2)+1b & old = strarr(count*2)
            for i=0,count-1 do begin
                name[(2*i):(2*i+1)] = ['line '+dm_to_string(i)+': linestyle','       '+'thickness']
                default[2*i]        = (*self.plotInfo)[onedplot[i]].linestyle
                default[2*i+1]      = (*self.plotInfo)[onedplot[i]].thick
                old[2*i]            = dm_to_string((*self.plotInfo)[onedplot[i]].linestyle)
                old[2*i+1]          = dm_to_string((*self.plotInfo)[onedplot[i]].thick)
                is_droplist[(2*i):(2*i+1)] = [1,0]
            endfor
            if count eq 1 then name = ['linestyle','thickness']
            new = dm_dialog_input(name,title='Set line style',default=default,is_droplist=is_droplist,$
                droplist_content=ptr_new(all_lines),xsize=100,dialog_parent=self.tlb,/return_number)
            index = where(strlen(new) eq 0,count0)
            if count0 gt 0 then new[index]=old[index]
            changeid = -1
            for i=0,count-1 do $
                if (new[2*i] ne old[2*i]) or (new[2*i+1] ne old[2*i+1]) then begin
                   (*self.plotInfo)[onedplot[i]].linestyle = dm_to_number(new[2*i],/int)
                   (*self.plotInfo)[onedplot[i]].thick     = 1.0>(dm_to_number(new[2*i+1]))<10.0
                   changeid = [changeid,onedplot[i]]
                endif
            if n_elements(changeid) gt 1 then self->setproperty,plotInfo=(*self.plotInfo),$
                changeid=changeid[1:(n_elements(changeid)-1)]
            end
       'dm_pcolBut':begin
            if n_elements((*self.plotInfo)) eq 0 then break ; no plots
            onedplot = where(((*self.plotInfo)[*].type eq 0) or ((*self.plotInfo)[*].type eq 3) ,count)
            if count eq 0 then break
            all_col  = [bwcolor,'red','blue','magenta','green','cyan','yellow','grey','dark grey','dark red','dark blue',$
                        'dark magenta','dark green','dark cyan','dark yellow','user define']
            name = strarr(count) & default = intarr(count) & is_droplist = bytarr(count)+1b
            old  = self->getcolor((*self.plotInfo)[onedplot].color,/name)
            define = where(old eq 'user define',count0)
            if count0 ne 0 then define = (*self.plotInfo)[onedplot[define[0]]].color else define=[255,255,255]
            for i=0,count-1 do begin
                if (*self.plotInfo)[onedplot[i]].type eq 0 then $
                   name[i]    = 'line '+dm_to_string(i) $
                else $
                   name[i]    = 'polygon '+dm_to_string(i)
                default[i] = 0>(where(all_col eq old[i]))
            endfor
            if count eq 1 then name=['color']
            new = dm_dialog_input(name,title='Set plot color',default=default,is_droplist=is_droplist,$
                  droplist_content=ptr_new(all_col),xsize=100,dialog_parent=self.tlb)
            changeid = -1
            for i=0,count-1 do $
                if new[i] ne old[i] then begin
                   (*self.plotInfo)[onedplot[i]].color=self->getcolor(new[i],define=define)
                   changeid = [changeid,onedplot[i]]
                endif
            if n_elements(changeid) gt 1 then self->setproperty,plotInfo=(*self.plotInfo),$
                   changeid=changeid[1:(n_elements(changeid)-1)]
            end
       'dm_lgndBut':begin
            if n_elements((*self.plotInfo)) eq 0 then break ; no plots
            onedplot = where((*self.plotInfo)[*].type eq 0,count)        & if count eq 0 then break
            name = 'line '+dm_to_string(indgen(count)) & old=(*self.plotInfo)[onedplot].legend
            if count eq 1 then name=['label']
            new = dm_dialog_input(name,title='Set legend labels',default=old,xsize=100,dialog_parent=self.tlb)
            new = self->textadjust(new,/AA)
            changeid = -1
            for i=0,count-1 do $
                if strtrim(new[i],2) ne strtrim(old[i],2) then begin
                   (*self.plotInfo)[onedplot[i]].legend = ' '+strtrim(new[i],2)
                   changeid = [changeid,onedplot[i]]
                endif
            if n_elements(changeid) gt 1 then self->updatelegend,/draw
            end
       'dm_pnsetBut':ok = dialog_printersetup(self.printer,dialog_parent=self.tlb)
       'dm_plotWin':begin
            if event.type eq 4 then self.drawWin->draw,self.drawView else begin
               if n_elements(*self.plotInfo) eq 0 then break    ; no plots
               ind = where((*self.plotInfo)[*].type eq 2,nsurf)
               if event.release eq 4 then begin   ;right mouse button clicked
                  self.select = obj_new()
                  tmp = self.drawWin->select(self.drawView,[event.x,event.y])
                  if obj_valid(tmp[0]) then begin
                     if tmp[0] eq self.cursorpos then break
                     self.select = tmp[0]
                     tmp[0]->getproperty,name=name
                     if name eq 'error' then begin    ;special care to error plot
                        name  = ''
                        index = where((*self.plotInfo).obj eq self.select,count)
                        if count ne 0 then $
                           if (*self.plotInfo)[index[0]-1].type eq 0 then begin ;double check
                              name = 'plot'
                              self.select = (*self.plotInfo)[index[0]-1].obj
                           endif
                     endif
                     if strlen(name) ne 0 then begin
                        if self.select eq self.drawxAxis[1] then begin
                           name = 'titl' & self.select = self.title
                           self.title->getproperty,strings=tmp
                           if strlen(tmp) eq 0 then break
                        endif
                        menuid = widget_info(event.id, find_by_uname='dm_cs_'+name+'Menu')
                        logid  = widget_info(menuid,find_by_uname='dm_cs_logscale')
                        setlog = 0
                        case name of    ;for axis and cbar, need to set properly the log scale button
                             'axis': begin
                                     setlog = 1
                                     self.select->getproperty,direction=direction
                                     case direction of
                                          0:     log_yn = self.xlog
                                          1:     log_yn = self.ylog
                                          else:  log_yn = self.zlog
                                     endcase
                                     end
                             'cbar': begin
                                     setlog = 1
                                     log_yn = self.ilog
                                     end
                             else:
                        endcase
                        if setlog eq 1 then dm_set_button,logid,log_yn,onstring='Normal Scale',offstring='Logarithmic Scale'
                        widget_displaycontextmenu,event.id,event.x,event.y,menuid
                     endif
                  endif else begin  ;turn off zoom or show the menu bar for the compound widget
                     tmp = widget_info(self.plotWin,/geometry)
                     if (event.y gt tmp.scr_ysize*0.75) and (event.x lt tmp.scr_xsize*0.25) and (self.compound eq 1) then begin
                        menuid = widget_info(event.id,find_by_uname='dm_menu_Dir')
                        widget_displaycontextmenu,event.id,event.x,event.y,menuid
                     endif else begin
                        if nsurf ne 0 then begin
                           self.drawGroup->reset
                           self.drawModel->reset
                           self.drawGroup->rotate,[1,0,0],-90
                           self.drawGroup->rotate,[0,1,0],30
                           self.drawGroup->rotate,[1,0,0],30
                           self.drawWin->draw,self.drawView
                        endif
                        if (total(finite(self.xran[*,2*self.xlog+1])) eq 2) then begin
                           self->setproperty,xran=self.xran[*,2*self.xlog+1],yran=self.yran[*,2*self.ylog+1]
                           self.xran[*,2*self.xlog+1] = [!values.f_nan,!values.f_nan]
                           self.yran[*,2*self.ylog+1] = [!values.f_nan,!values.f_nan]
                        endif
                     endelse
                  endelse
               endif else begin
                  if nsurf gt 0 then $
                     self->rotate,event $
                  else $
                     self->zoom,event
               endelse
               if (event.type eq 2) then begin
                  ;figure out the x & y & z values of the cursor
                  xval = !values.f_nan & yval = !values.f_nan
                  if self.xlog eq 1 then xran = alog10(self.xran[*,2]) else xran = self.xran[*,0]
                  if self.ylog eq 1 then yran = alog10(self.yran[*,2]) else yran = self.yran[*,0]
                  self.drawView->getproperty,dimension=dim
                  x = self.viewplane[0]+(0>(event.x/dim[0])<1)*self.viewplane[2]
                  y = self.viewplane[1]+(0>(event.y/dim[1])<1)*self.viewplane[3]
                  if nsurf eq 0 then begin
                     if (x ge 0) and (x le 1) then begin
                        xval = xran[0]+x*(xran[1]-xran[0])
                        if self.xlog then xval = 10.0^xval
                     endif
                     if (y ge 0) and (y le 1) then begin
                        yval = yran[0]+y*(yran[1]-yran[0])
                        if self.ylog then yval = 10.0^yval
                     endif
                  endif
                  ;update the cursor position string
                  if self.showcpos and not obj_valid(self.zoombox) then begin
                     cursorpos = ''
                     if finite(xval) then cursorpos=cursorpos+'x='+dm_to_string(xval)+' '
                     if finite(yval) then cursorpos=cursorpos+'y='+dm_to_string(yval)
                     self.cursorpos->setproperty,strings=cursorpos
                     self.drawWin->draw,self.drawView,/draw_instance
                  endif
                  ;send out motion events
                  if self.motion_events then begin
                     ;patch xval and yval to the event
                     event = create_struct(event,"XVAL",xval,"YVAL",yval,name="DM_PLOT_MOTION")
                     if obj_valid(self.parentobj) then $                           ;notify parent object
                        call_method,self.parenthandler,self.parentobj,event $
                     else if widget_info(self.group_leader,/valid_id) ne 0 then $
                        widget_control,self.group_leader,send_event=event
                  endif
               endif
            endelse
            end
       'dm_cs_title':begin
            if obj_isa(self.select,'IDLgrAxis') then begin
               self.select->getproperty,title=title,direction=direction
               case direction of
                    0:    name = 'x title'
                    1:    name = 'y title'
                    else: name = 'z title'
               endcase
               if title eq self.title then name = 'title'
            endif else begin
               title = self.select
               title->getproperty,name=name
               if name eq 'titl' then name = 'title'
            endelse
            if obj_valid(title) then begin
               title->getproperty,strings=old
               new = dm_dialog_input(name+':',title='Set '+name,xsize=150,default=old,dialog_parent=self.tlb)
               if new ne old then begin
                  if name eq 'title' then self->setproperty,title=self->textadjust(new,/AA) $
                  else begin
                     if name eq 'text' and strlen(new) eq 0 then begin    ;remove it
                        title->getproperty,font=ofont
                        obj_destroy,[ofont,title]
                     endif else $
                        title->setproperty,string=self->textadjust(new,/AA)
                     self.drawWin->draw,self.drawView
                  endelse
               endif
            endif
            end
       'dm_cs_range':begin
            self.select->getproperty,name=name
            if name eq 'axis' then begin
               self.select->getproperty,direction=direction
               case direction of
                    0:     type = 'x'
                    1:     type = 'y'
                    2:     type = 'z'
                    else:  type = 'i'
               endcase
            endif else  type = 'i'
            old = call_function("dm_to_string",(type eq 'x')?(self.xran[*,2*self.xlog]):$
                  ((type eq 'y')?(self.yran[*,2*self.ylog]):((type eq 'z')?(self.zran[*,2*self.zlog]):$
                  (self.iran[*,2*self.ilog]))))
            new = dm_dialog_input(['from:','to:'],title='Set '+type+'range',xsize=100,default=old,dialog_parent=self.tlb)
            if (old[0] ne new[0]) or (old[1] ne new[1]) then begin
               new = dm_to_number(new)
               if total(finite(new)) eq 2 then $
                  if new[1] gt new[0] then begin
                     case type of
                          'x':    self->setproperty,xran=new
                          'y':    self->setproperty,yran=new
                          'z':    self->setproperty,zran=new
                          'i':    self->setproperty,iran=new
                     endcase
                  endif
            endif
            end
       'dm_cs_logscale':begin
            self.select->getproperty,name=name
            if name eq 'axis' then begin
               self.select->getproperty,direction=direction
               case direction of
                    0:    type = 'xlog'
                    1:    type = 'ylog'
                    2:    type = 'zlog'
                    else: type = 'ilog'
               endcase
            endif else  type = 'ilog'
            case type of
                 'xlog':  self->setproperty,xlog=1-self.xlog
                 'ylog':  self->setproperty,ylog=1-self.ylog
                 'zlog':  self->setproperty,zlog=1-self.zlog
                 else:    self->setproperty,ilog=1-self.ilog
            endcase
            end
       'dm_cs_axisthick':begin
            old = dm_to_string(self.axisthick)
            new = dm_dialog_input('thick:',title='Set axis thickness',xsize=100,default=old,dialog_parent=self.tlb)
            if old ne new then begin
               new = dm_to_number(new)
               if finite(new) then $
                  self->setproperty,axisthick=new
            endif
            end
       'dm_cs_textori':begin
            self.select->getproperty,baseline=baseline
            old = acos(baseline[0]/norm(baseline[0:1]))/!dtor
            if baseline[1] lt 0 then old=360-old
            old = fix(old*10)/10.   ;only accurate to the first decimal point
            new = dm_dialog_input('Orientation:',title='Set Text Orientation',default=old,$
                  xsize=100,dialog_parent=self.tlb,/float)
            if finite(new) then begin
               new = fix(new*10)/10.   ;only accurate to the first decimal point
               if new ne old then begin
                  new = new*!dtor & orie_cos = cos(new) & orie_sin = sin(new)
                  baseline = [orie_cos,orie_sin]
                  updir    = [-orie_sin,orie_cos]
                  self.select->setproperty,baseline=baseline,updir=updir
                  self.drawWin->draw,self.drawView
               endif
            endif
            end
       'dm_cs_txtcolor':begin
            if (self.select eq self.xgrid) or (self.select eq self.ygrid) then begin
               is_grid = 1
               title   = 'Set grid color'
               object  = [self.xgrid,self.ygrid]
            endif else begin
               is_grid = 0
               title   = 'Set text color'
               object  = self.select
            endelse
            self.select->getproperty,color=color
            all_col = [bwcolor,'red','blue','magenta','green','cyan','yellow','grey','dark grey','dark red','dark blue',$
                       'dark magenta','dark green','dark cyan','dark yellow','user define']
            old = self->getcolor(color,/name)
            new = dm_dialog_input('color:',title=title,default=0>(where(all_col eq old)),$
                  is_droplist=[1],droplist_content=ptr_new(all_col),xsize=100,dialog_parent=self.tlb,parentobject=self,$
                  object=object,property='color',apply=apply)
            if (apply eq 1) or (new[0] ne old[0]) then begin
               new = self->getcolor(new[0],define=color)
               if is_grid then begin
                  self.xgrid->setproperty,color=new
                  self.ygrid->setproperty,color=new
               endif else $
                  self.select->setproperty,color=new
               self.drawWin->draw,self.drawView
            endif
            end
       'dm_cs_font':begin
            index = 0 ;for ticktext
            self.select->getproperty,name=name
            if name eq 'axis' then begin
               if self.select eq self.drawxAxis[0] then index =  1  $
               else if self.select eq self.drawxAxis[1] then index = 4 $
               else if self.select eq self.drawyAxis[0] then index = 2 $
               else if self.select eq self.drawzAxis then index = 3
            endif else if name eq 'titl' then index = 4 $
            else if name eq 'legend' then index = 5 $
            else if name eq 'cursorpos' then index = 6 $
            else if name eq 'text' then index = -1
            if index eq -1 then begin
               self.select->getproperty,font=ofont
               ofont->getproperty,name=old
               help,ofont,output=id & id=strsplit(id,' ',/extract) & id=id[n_elements(id)-1]
               tmpid = where(*self.textsize eq id)
               fsize = float((*self.textsize)[tmpid[0]+1])
            endif else begin
               ofont = self.font[index]
               ofont->getproperty,name=old
               fsize = self.fsize[index]
            endelse
            old       = strlowcase(old)
            all_fonts = ['helvetica','courier','times','symbol','monospace symbol','hershey']
            default   = [0>(where(all_fonts eq old)),fsize]
            old       = [old,dm_to_string(fsize)]
            new       = dm_dialog_input(['font name:','font size:'],title='Set font',default=default,is_droplist=[1,0],$
                        droplist_content=ptr_new(all_fonts),xsize=100,dialog_parent=self.tlb)
            ind       = where(strlen(new) eq 0,count)
            if count gt 0 then new[ind]=old[ind]
            redraw    = 0
            if new[0] ne old[0] then begin
               ofont->setproperty,name=new[0],substitute='Hershey'
               ofont->getproperty,name=tmp
               if (index ge 0) then $
                  if strmid(strlowcase(tmp),0,7) eq 'hershey' then self.fscale[index]=1.2 else self.fscale[index]=1.0
               redraw = 1
            endif
            if new[1] ne old[1] then begin
               if index ge 0 then $
                  self.fsize[index]=(8>(dm_to_number(new[1],/int))) $
               else $
                  (*self.textsize)[tmpid[0]+1]=dm_to_string(8>dm_to_number(new[1],/int))
               redraw = 1
            endif
            if redraw then self->draw
            end
       'dm_cs_symbol':begin
            index    = where((*self.plotInfo)[*].obj eq self.select,count)
            if count ne 1 then break
            all_psym = ['no symbol','circle','diamond','triangle','inverted triangle','square',$
                'plus','star','dot','cross','greater','less','filled circle','filled diamond',$
                'filled triangle','filled inverted triangle','filled square']
            default  = [0>(where(all_psym eq (*self.plotInfo)[index].psym)),(*self.plotInfo)[index].symsize]
            old      = [(*self.plotInfo)[index].psym,dm_to_string((*self.plotInfo)[index].symsize)]
            new = dm_dialog_input(['symbol name:','symbol size:'],title='Set plot symbol',default=default,$
                  is_droplist=[1,0],droplist_content=ptr_new(all_psym),xsize=120,dialog_parent=self.tlb,$
                  info='0.0<symbol size<1.0')
            if (new[0] ne old[0]) or (new[1] ne old[1]) then begin
               (*self.plotInfo)[index].psym    = new[0]
               (*self.plotInfo)[index].symsize = 0.0>(dm_to_number(new[1]))<1.0
               self->setproperty,plotInfo=(*self.plotInfo),changeid=index
            endif
            end
       'dm_cs_color':begin
            index   = where((*self.plotInfo)[*].obj eq self.select,count)
            if count ne 1 then break
            all_col = [bwcolor,'red','blue','magenta','green','cyan','yellow','grey','dark grey','dark red','dark blue',$
                       'dark magenta','dark green','dark cyan','dark yellow','user define']
            old     = self->getcolor((*self.plotInfo)[index].color,/name)
            new     = dm_dialog_input('color:',title='Set plot color',default=0>(where(all_col eq old)),$
                      is_droplist=[1],droplist_content=ptr_new(all_col),xsize=100,dialog_parent=self.tlb,parentobject=self,$
                      object=self.select,property='color',apply=apply)
            if (apply eq 1) or (new[0] ne old[0]) then begin
               (*self.plotInfo)[index].color=self->getcolor(new[0],define=(*self.plotInfo)[index].color)
               self->setproperty,plotInfo=(*self.plotInfo),changeid=index
            endif
            end
       'dm_cs_linestyle':begin
            if (self.select eq self.xgrid) or (self.select eq self.ygrid) then begin
               all_lines = ['solid','dotted','dashed','dash dot','dash dot dot dot','long dash']
               is_grid   = 1
               self.select->getproperty,linestyle=old
               object = [self.xgrid,self.ygrid]
               title  = 'Set grid linestyle'
            endif else begin
               all_lines = ['solid','dotted','dashed','dash dot','dash dot dot dot','long dash','no line']
               is_grid   = 0
               index  = where((*self.plotInfo)[*].obj eq self.select,count)
               if count ne 1 then break
               old    = (*self.plotInfo)[index].linestyle
               object = self.select
               title  = 'Set plot linestyle'
            endelse
            new = dm_dialog_input('linestyle:',title=title,default=old,$
                  is_droplist=[1],droplist_content=ptr_new(all_lines),xsize=100,dialog_parent=self.tlb,parentobject=self,$
                  object=object,property='linestyle',apply=apply,/return_number)
            if (apply eq 1) or (new[0] ne old[0]) then begin
               if is_grid then begin
                  self.xgrid->setproperty,linestyle=new[0]
                  self.ygrid->setproperty,linestyle=new[0]
                  self.drawWin->draw,self.drawView
               endif else begin
                  (*self.plotInfo)[index].linestyle=new[0]
                  self->setproperty,plotInfo=(*self.plotInfo),changeid=index
               endelse
            endif
            end
       'dm_cs_linethick':begin
            if (self.select eq self.xgrid) or (self.select eq self.ygrid) then begin
               self.select->getproperty,thick=old
               old     = dm_to_string(old)
               is_grid = 1
               title   = 'Set grid thickness'
               object  = [self.xgrid,self.ygrid]
            endif else begin
               is_grid = 0
               index   = where((*self.plotInfo)[*].obj eq self.select,count)
               if count ne 1 then break
               old     = dm_to_string((*self.plotInfo)[index].thick)
               title   = 'Set plot thickness'
               object  = self.select
            endelse
            new = dm_dialog_input('thickness:',title=title,default=old,xsize=70,dialog_parent=self.tlb,$
                  info='1.0<thick<10.0',parentobj=self,object=object,property='thick',apply=apply)
            if (apply eq 1) or (new[0] ne old[0]) then begin
               new = dm_to_number(new[0])
               if not finite(new) then new=1.0
               if is_grid then begin
                  self.xgrid->setproperty,thick = 1.0>(new)<10.0
                  self.ygrid->setproperty,thick = 1.0>(new)<10.0
                  self.drawWin->draw,self.drawView
               endif else begin
                  (*self.plotInfo)[index].thick = 1.0>(new)<10.0
                  self->setproperty,plotInfo=(*self.plotInfo),changeid=index
               endelse
            endif
            end
       'dm_cs_legend':begin
            index = where((*self.plotInfo)[*].obj eq self.select,count)
            if count ne 1 then break
            old   = strtrim((*self.plotInfo)[index].legend,2)
            new   = dm_dialog_input('legend:',title='Set plot legend',default=old,xsize=100,dialog_parent=self.tlb)
            if (new[0] ne old[0]) then begin
               (*self.plotInfo)[index].legend = ' '+self->textadjust(new[0],/AA)
               self->setproperty,plotInfo=(*self.plotInfo),changeid=index
            endif
            end
       'dm_cs_layer':begin
            index = where((*self.plotInfo)[*].obj eq self.select,count)
            if count ne 1 then break
            old   = (*(*self.plotInfo)[index].zPtr)
            new   = dm_dialog_input('layer:',title='Set plot layer',default=old,xsize=60,dialog_parent=self.tlb)
            if new ne old then begin
               new = dm_to_number(new,/int)
               old = dm_to_number(old,/int)
               nplots  = n_elements(*self.plotInfo)
               ;check if the new layer is already used, if yes, switch that one to old
               onedplot= where((*self.plotInfo)[*].type eq (*self.plotInfo)[index].type ,count)
               index0  = -1
               for i=0,count-1 do if *(*self.plotInfo)[onedplot[i]].zPtr eq new then index0=onedplot[i]
               if index0 ne -1 then begin
                  *(*self.plotInfo)[index0].zPtr=old
                  changeid = [index0,index]
               endif else changeid=index
               *(*self.plotInfo)[index].zPtr = new
               self->setproperty,plotInfo=(*self.plotInfo),changeid=changeid
            endif
            end
       'dm_cs_remove': begin  ;delete a single 1D plot (with its error bars if exist) or a text object
            self.select->getproperty,name=name
            ans = dialog_message('Are you sure you want to remove this '+name+'?',/question,dialog_parent=self.tlb)
            if strlowcase(ans) eq 'yes' then begin
               index = where((*self.plotInfo)[*].obj eq self.select,count)
               if count ne 1 then begin    ;text object to be removed
                  self.select->getproperty,font=ofont
                  obj_destroy,[ofont,self.select]
                  self.drawWin->draw,self.drawView
                  break
               endif
               nplot = n_elements(*self.plotInfo)
               if (*self.plotInfo)[index].type ne 3 then begin  ;idlgrplot object
                  oned  = where((*self.plotInfo)[*].type eq 0,n_oned)
                  self.select->getproperty,symbol=tmp1
                  if obj_valid(tmp1) then begin
                     tmp1[0]->getproperty,data=tmp2
                     if obj_valid(tmp2) then obj_destroy,tmp2
                     obj_destroy,tmp1
                  endif
                  updatedrawlegend = 1b
               endif
               obj_destroy,self.select
               ptr_free,(*self.plotInfo)[index].xPtr,(*self.plotInfo)[index].yPtr,(*self.plotInfo)[index].zPtr,(*self.plotInfo)[index].iPtr
               tmp = intarr(nplot)+1 & tmp[index]=0 & index=index+1
               if index lt nplot then $
                  if (*self.plotInfo)[index].type eq -1 then begin
                     obj_destroy,(*self.plotInfo)[index].obj
                     ptr_free,(*self.plotInfo)[index].xPtr,(*self.plotInfo)[index].yPtr,(*self.plotInfo)[index].zPtr,(*self.plotInfo)[index].iPtr
                     tmp[index] = 0
                  endif
               tmp = where(tmp eq 1,count)
               if count ne 0 then $
                  (*self.plotInfo)=(*self.plotInfo)[tmp] $
               else begin
                  ptr_free,self.plotInfo & self.plotInfo=ptr_new(/allocate_heap)
               endelse
               ;update the drawlegend
               if keyword_set(updatedrawlegend) then self->updatelegend
               self.drawWin->draw,self.drawView
            endif
            end
       'dm_cs_coltable':begin
            if n_elements((*self.plotInfo)) eq 0 then break ; no plots
            twodplot= where(((*self.plotInfo)[*].type gt 0) and ((*self.plotInfo)[*].type lt 3),count)
            if count eq 0 then break
            all_ctb = ['B-W LINEAR','BLUE/WHITE','GRN-RED-BLU-WHT','RED TEMPERATURE','BLUE/GREEN/RED/YELLOW','STD GAMMA-II','PRISM',$
                'RED-PURPLE','GREEN/WHITE LINEAR','GRN/WHT EXPONENTIAL','GREEN-PINK','BLUE-RED','16 LEVEL','RAINBOW','STEPS',$
                'STERN SPECIAL','Haze','Blue-Pastel-Red','Pastels','Hue Sat Lightness 1','Hue Sat Lightness 2','Hue Sat Value 1',$
                'Hue Sat Value 2','Purple-Red+Stripes','Beach','Mac Style','Eos A','Eos B','Hardcandy','Nature','Ocean',$
                'Peppermint','plasma','Blue-Red','Rainbow','Blue Waves','Volcano','Waves','Rainbow18','Rainbow+white',$
                'Rainbow+black']
            all_ctb = dm_to_string(indgen(n_elements(all_ctb)))+'  '+all_ctb
            name    = 'plot '+dm_to_string(indgen(count)) & is_droplist=bytarr(count)+1b & old=(*self.plotInfo)[twodplot].coltable
            if count eq 1 then name=['color table']
            new     = dm_dialog_input(name,title='Set color table',default=old,is_droplist=is_droplist,$
                droplist_content=ptr_new(all_ctb),xsize=220,/return_number,/int,dialog_parent=self.tlb,parentobject=self,$
                object=(*self.plotInfo)[twodplot].obj,property='coltable',apply=apply,/coltable)
            changeid = -1
            for i=0,count-1 do begin
                if (apply eq 1) or (new[i] ne old[i]) then begin
                   (*self.plotInfo)[twodplot[i]].coltable=new[i]
                   changeid = [changeid,twodplot[i]]
                endif
            endfor
            if n_elements(changeid) gt 1 then self->setproperty,plotInfo=(*self.plotInfo),changeid=changeid[1:(n_elements(changeid)-1)]
            end
       'dm_cs_shade':begin
            if n_elements((*self.plotInfo)) eq 0 then break ; no plots
            twodplot = where(((*self.plotInfo)[*].type gt 0) and ((*self.plotInfo)[*].type lt 3),count)
            if count eq 0 then break
            choice   = ['Flat','Gouraud']
            name     = 'plot '+dm_to_string(indgen(count)) & is_droplist=bytarr(count)+1b & old=(*self.plotInfo)[twodplot].shading
            if count eq 1 then name=['shading']
            new      = dm_dialog_input(name,title='Set shading',default=old,is_droplist=is_droplist,droplist_content=ptr_new(choice),$
                xsize=100,/return_number,/int,dialog_parent=self.tlb)
            changeid = -1
            for i=0,count-1 do $
                if new[i] ne old[i] then begin
                   (*self.plotInfo)[twodplot[i]].shading = new[i]
                   changeid = [changeid,twodplot[i]]
                endif
            if n_elements(changeid) gt 1 then self->setproperty,plotInfo=(*self.plotInfo),changeid=changeid[1:(n_elements(changeid)-1)]
            end
       'dm_cs_hidecbar':  self->setproperty,hideintbar=(1b)-self.hideIntbar
       'dm_cs_hidelegend':self->setproperty,hidelegend=(1b)-self.hideLegend
       'dm_cs_hidegrid':  self->setproperty,showxgrid=0,showygrid=0
       'dm_cs_outline':begin
            widget_control,event.id,get_value=value
            if value eq 'Show Outline' then begin
               value = 'Hide Outline'
               show  = 1
            endif else begin
               value = 'Show Outline'
               show  = 0
            endelse
            widget_control,event.id,set_value=value
            self.select->setproperty,show_outline=show
            self.drawWin->draw,self.drawView
            end
       'dm_cs_lgndgap':begin
            self.select->getproperty,gap=old
            new = dm_dialog_input('legend gap:',title='Set Legend Gap',default=old,/float,dialog_parent=self.tlb,$
                info='border gap=2*gap')
            if finite(new) then $
               if new ne old then begin
                  self.select->setproperty,gap=new,border_gap=new*2
                  self.drawWin->draw,self.drawView
               endif
            end
       'dm_cs_lgndwidth':begin
            self.select->getproperty,glyph_width=old
            new = dm_dialog_input('legend glyph width:',title='Set Legend Glyph Width',default=old,/float,dialog_parent=self.tlb)
            if finite(new) then $
               if new ne old then begin
                  self.select->setproperty,glyph_width=new
                  self.drawWin->draw,self.drawView
               endif
            end
       'dm_cs_propsheet':begin
            redraw = 0
            propsheet = obj_new('dm_propsheet',self.select,parentobject=self,/view) ;a modal interactive dialog widet
            obj_destroy,propsheet
            case strlowcase(obj_class(self.select)) of
                 'idlgrplot':begin
                             self.select->getproperty,symbol=symbol,color=color,linestyle=linestyle,thick=thick,hide=hide
                             redraw = 1  ;need to reset legend
                             symbol[0]->getproperty,data=data
                             if obj_valid(data) then data->setproperty,color=color
                             symbol[0]->setproperty,color=color     ;change symbol color
                             ;change legend properties
                             onedplot = where((*self.plotInfo)[*].type eq 0)
                             show     = where((*self.plotInfo)[onedplot].hide eq 0)
                             onedplot = onedplot[show]
                             changeid = where((*self.plotInfo)[*].obj eq self.select,count)
                             if count eq 0 then break
                             (*self.plotInfo)[changeid].color     = color
                             (*self.plotInfo)[changeid].linestyle = linestyle
                             (*self.plotInfo)[changeid].thick     = thick
                             (*self.plotInfo)[changeid].hide      = hide
                             nplots = n_elements(*self.plotInfo)
                             ;change the color and thickness of the error plot if any
                             if changeid[0]+1 lt nplots then $
                                if (*self.plotInfo)[changeid[0]+1].type eq -1 then begin
                                   (*self.plotInfo)[changeid[0]+1].obj->setproperty,thick=thick,color=color,hide=hide
                                   (*self.plotInfo)[changeid[0]+1].color     = color
                                   (*self.plotInfo)[changeid[0]+1].linestyle = linestyle
                                   (*self.plotInfo)[changeid[0]+1].thick     = thick
                                   (*self.plotInfo)[changeid[0]+1].hide      = hide
                                endif
                             end
                 'idlgrlegend':begin
                             ;check if the show status has been changed
                             self.select->getproperty,hide=newhide
                             if newhide ne hide then self->setproperty,hidelegend=newhide
                             end
                 'idlgrtext':begin
                             self.select->getproperty,hide=hide
                             if hide eq 1 then self->my_widget_control,'dm_show_all',sensitive=1
                             end
                 'idlgrpolygon':begin
                             self.select->getproperty,color=color
                             changeid = where((*self.plotInfo)[*].obj eq self.select,count)
                             if count ne 0 then (*self.plotInfo)[changeid].color=color
                             end
                 else:
            endcase
            if redraw then begin
               self->draw
               self->my_widget_control,'dm_show_all',sensitive=1
            endif else $
               self->draw,/view
            end
       else:
    endcase
end

function dm_plot::getcolor,color,scalar=scalar,name=name,define=define
    ncolor = n_elements((keyword_set(name))?(color[0,*]):color)
    if keyword_set(name) then begin
       if ncolor eq 0 then return,'user define'
       result=strarr(ncolor)
       for i=0,ncolor-1 do begin
           index=color[0,i]+256L*color[1,i]+256L*256L*color[2,i]
           case index of
                0L:         name = 'black'
                16777215L:  name = 'white'
                255L:       name = 'red'
                16711680L:  name = 'blue'
                16711935L:  name = 'magenta'
                65280L:     name = 'green'
                16776960L:  name = 'cyan'
                65535L:     name = 'yellow'
                12632256L:  name = 'grey'
                8421504L:   name = 'dark grey'
                128L:       name = 'dark red'
                8388608L:   name = 'dark blue'
                8388736L:   name = 'dark magenta'
                32768L:     name = 'dark green'
                8421376L:   name = 'dark cyan'
                32896L:     name = 'dark yellow'
                else:       name = 'user define'
           endcase
           result[i] = name
       endfor
       return,(ncolor eq 1)?result[0]:result
    endif else begin
       if n_elements(define) ne 3 then define = [255b,255b,255b] else define = byte(define)
       if ncolor eq 0 then $
          if keyword_set(scalar) then return,16777215L else return,define
       if size(color,/type) ne 7 then begin
          if keyword_set(scalar) and n_elements(color) eq 3 then return,color[0]+256L*color[1]+256L*256L*color[2] $
          else return,color
       endif
       if keyword_set(scalar) then result = lonarr(ncolor) else result = bytarr(3,ncolor)
       for i=0,ncolor-1 do begin
           case strlowcase(strtrim(color[i],2)) of
                'white'   :      tmp = [255b,255b,255b]
                'red' :          tmp = [255b,0b,0b]
                'blue'    :      tmp = [0b,0b,255b]
                'magenta':       tmp = [255b,0b,255b]
                'green':         tmp = [0b,255b,0b]
                'cyan':          tmp = [0b,255b,255b]
                'yellow':        tmp = [255b,255b,0b]
                'grey':          tmp = [192b,192b,192b]
                'dark grey':     tmp = [128b,128b,128b]
                'dark red':      tmp = [128b,0b,0b]
                'dark blue':     tmp = [0b,0b,128b]
                'dark magenta':  tmp = [128b,0b,128b]
                'dark green':    tmp = [0b,128b,0b]
                'dark cyan':     tmp = [0b,128b,128b]
                'dark yellow':   tmp = [128b,128b,0b]
                'black':         tmp = [0b,0b,0b]
                'user define':   tmp = define
                else:            tmp = [255b,255b,255b]
           endcase
           if keyword_set(scalar) then result[i]=tmp[0]+256L*tmp[1]+256L*256L*tmp[2] else result[*,i]=tmp
       endfor
    endelse
    if keyword_set(scalar) or keyword_set(name) then return,(ncolor eq 1)?result[0]:result $
    else return, (ncolor eq 1)?result[*,0]:result
end

function dm_plot::getlinestyle,linestyle,name=name
    nline = n_elements(linestyle)
    if nline eq 0 then return,keyword_set(name)?'solid':0
    if keyword_set(name) then begin
       lines = strarr(nline)
       for i=0,nline-1 do begin
           case linestyle[i] of
                0:      lines[i] = 'solid'
                1:      lines[i] = 'dotted'
                2:      lines[i] = 'dashed'
                3:      lines[i] = 'dash dot'
                4:      lines[i] = 'dash dot dot dot'
                5:      lines[i] = 'long dash'
                6:      lines[i] = 'no line'
                else:   lines[i] = 'solid'
           endcase
       endfor
    endif else begin
       if size(linestyle,/type) ne 7 then return,linestyle
       lines = lonarr(nline)
       for i=0,nline-1 do begin
           case strlowcase(strtrim(linestyle[i],2)) of
                'solid':            lines[i] = 0L
                'dotted':           lines[i] = 1L
                'dashed':           lines[i] = 2L
                'dash dot':         lines[i] = 3L
                'dash dot dot dot': lines[i] = 4L
                'long dash':        lines[i] = 5L
                'no line':          lines[i] = 6L
                else:               lines[i] = 0L
           endcase
       endfor
    endelse
    return,(nline eq 1)?lines[0]:lines
end

function dm_plot::getpalette,coltable,background=background,oldpal=oldpal
    if n_elements(oldpal) ne 0 then drawPal=oldpal $
    else drawPal=obj_new('IDLgrPalette',name='palette')
    ;save the old color table and restore it later to avoid affecting other programs running at the same time
    tvlct,old_r,old_g,old_b,/get
    loadct,coltable,/silent
    stretch,1,255  ;0 left for background color
    tvlct,r,g,b,/get
    if n_elements(background) eq 3 then begin
       r[0] = fix(background[0],type=1)
       g[0] = fix(background[0],type=1)
       b[0] = fix(background[0],type=1)
    endif else begin
       r[0] = 0b
       g[0] = 0b
       b[0] = 0b
    endelse
    drawPal->setproperty,red_values=temporary(r),green_values=temporary(g),blue_values=temporary(b)
    ;restore the old color table
    tvlct,old_r,old_g,old_b
    return,drawPal
end

function dm_plot::getpsym,symbol,symsize,thick,color,oldsymbol=oldsymbol,name=name,landscape=landscape
    if keyword_set(name) then begin
       if size(symbol,/type) eq 7 then return,symbol $
       else begin
          case symbol[0] of
                0:      result = 'no symbol'
                1:      result = 'plus'
                2:      result = 'star'
                3:      result = 'dot'
                4:      result = 'diamond'
                5:      result = 'triangle'
                6:      result = 'square'
                7:      result = 'cross'
                8:      result = 'greater'
                9:      result = 'less'
                else:   result = 'no symbol'
          endcase
       endelse
       return,result
    endif
    if n_elements(oldsymbol) ne 0 then begin
       psym = oldsymbol[0]
       psym->getproperty,data=tmp
       if obj_valid(tmp) then obj_destroy,tmp
    endif else begin
       psym = obj_new('IDLgrSymbol')
    endelse
    if n_elements(symsize) eq 0 then symsize=self.default[1]
    ;modify the symbol size to achieve isotropic effect
    self.drawView->getproperty,dimensions=dim, viewplane_rect=view_rect
    view_rect = view_rect[2:3]
    if keyword_set(landscape) then begin
       dim       = dim[[1,0]]
       view_rect = view_rect[[1,0]]
    endif
    dim = dim/view_rect
    if self.xlog eq 1 then xran=alog10(self.xran[*,2]) else xran=self.xran[*,0]
    if self.ylog eq 1 then yran=alog10(self.yran[*,2]) else yran=self.yran[*,0]
    tmpsize = symsize*[xran[1]-xran[0],yran[1]-yran[0]]*mean(dim)/dim
    if n_elements(thick) eq 0  then thick = self.default[2]
    if n_elements(color) eq 0  then color = (['white','black'])[self.bgcol]
    if size(symbol,/type) ne 7 then data  = symbol[0] $
    else begin
       cos30 = cos(30*!dtor)
       cos45 = cos(45*!dtor)
       case strlowcase(strtrim(symbol,2)) of
            'circle':   data = obj_new('idlgrplot',cos(findgen(41)/40.0*!pi*2),sin(findgen(41)/40.0*!pi*2),linestyle=0,color=self->getcolor(color),thick=thick)
            'plus':     data = 1
            'star':     data = 2
            'dot':      data = 3
            'diamond':  data = 4
            'triangle': data = 5
            'square':   data = 6
            'cross':    data = 7
            'greater':  data = 8
            'less':     data = 9
            'inverted triangle': data = obj_new('idlgrplot',[-cos30,cos30,0,-cos30],[0.5,0.5,-1,0.5],linestyle=0,color=self->getcolor(color),thick=thick)
            'filled circle':     data = obj_new('idlgrpolygon',cos(findgen(41)/40.0*!pi*2),sin(findgen(41)/40.0*!pi*2),color=self->getcolor(color))
            'filled diamond':    data = obj_new('idlgrpolygon',[0,1,0,-1,0],[1,0,-1,0,1],color=self->getcolor(color))
            'filled triangle':   data = obj_new('idlgrpolygon',[0,cos30,-cos30,0],[1,-0.5,-0.5,1],color=self->getcolor(color))
            'filled square':     data = obj_new('idlgrpolygon',[cos45,cos45,-cos45,-cos45,cos45],[cos45,-cos45,-cos45,cos45,cos45],color=self->getcolor(color))
            'filled inverted triangle': data = obj_new('idlgrpolygon',[-cos30,cos30,0,-cos30],[0.5,0.5,-1,0.5],color=self->getcolor(color))
            else:       data = 0  ;no symbol
       endcase
    endelse
    psym->setproperty,data=data,size=tmpsize,thick=thick,color=self->getcolor(color)
    return,psym
end

function dm_plot::getproperty,enotebook=enotebook,error=error,group_leader=group_leader,$
    keep=keep,parenthandler=parenthandler,parentobj=parentobj,scr_xsize=scr_xsize,$
    scr_ysize=scr_ysize,title=title,tlb=tlb,xrange=xrange,xsize=xsize,xtitle=xtitle,$
    yrange=yrange,ysize=ysize,ytitle=ytitle,ztitle=ztitle
    catch, myerror
    if myerror ne 0 then begin
       catch,/cancel
       ok = dialog_message(dialog_parent=self.tlb,!error_state.msg,/error)
       error = 1  ;indicating that an error occurs
       return,0
    end
    error = 0
    if keyword_set(group_leader)  then return, self.group_leader
    if keyword_set(keep)          then return, self.keep
    if keyword_set(parentobj)     then return, self.parentobj
    if keyword_set(parenthandler) then return, self.parenthandler
    if keyword_set(tlb)           then return, self.tlb
    if keyword_set(enotebook)     then return, self.enotebook
    if widget_info(self.plotWin,/valid_id) then $
       tmp = widget_info(self.plotWin,/geometry) $
    else $
       tmp = {xsize:0,ysize:0,scr_xsize:0,scr_ysize:0}
    if keyword_set(xsize)         then return, tmp.xsize
    if keyword_set(ysize)         then return, tmp.ysize
    if keyword_set(scr_xsize)     then return, tmp.scr_xsize
    if keyword_set(scr_ysize)     then return, tmp.scr_ysize
    if keyword_set(xrange)        then return, self.xran[*,2*self.xlog]
    if keyword_set(yrange)        then return, self.yran[*,2*self.ylog]
    if keyword_set(title)         then begin
       self.title->getproperty,strings=title
       return,title
    endif
    if keyword_set(xtitle)        then begin
       self.xtit->getproperty,strings=title
       return,title
    endif
    if keyword_set(ytitle)        then begin
       self.ytit->getproperty,strings=title
       return,title
    endif
    if keyword_set(ztitle)        then begin
       self.ztit->getproperty,strings=title
       return,title
    endif
    error = 1
end

pro dm_plot::getproperty,error=error,group_leader=group_leader,keep=keep,$
    parenthandler=parenthandler,parentobj=parentobj,scr_xsize=scr_xsize,scr_ysize=scr_ysize,$
    title=title,tlb=tlb,xrange=xrange,xsize=xsize,xtitle=xtitle,yrange=yrange,ysize=ysize,$
    ytitle=ytitle,ztitle=ztitle
    catch, myerror
    if myerror ne 0 then begin
       catch,/cancel
       ok = dialog_message(dialog_parent=self.tlb,!error_state.msg,/error)
       error = 1  ;indicating that an error occurs
       return
    end
    error = 0
    if arg_present(group_leader)  then group_leader  = self.group_leader
    if arg_present(keep)          then keep          = self.keep
    if arg_present(parenthandler) then parenthandler = self.parenthandler
    if arg_present(parentobj)     then parentobj     = self.parentobj
    if arg_present(tlb)           then tlb           = self.tlb
    if arg_present(title)         then self.title->getproperty,strings=title
    if arg_present(xtitle)        then self.xtit->getproperty,strings=xtitle
    if arg_present(ytitle)        then self.ytit->getproperty,strings=ytitle
    if arg_present(ztitle)        then self.ztit->getproperty,strings=ztitle
    if widget_info(self.plotWin,/valid_id) then $
       tmp = widget_info(self.plotWin,/geometry) $
    else $
       tmp = {xsize:0,ysize:0,scr_xsize:0,scr_ysize:0}
    if arg_present(xsize)         then xsize         = tmp.xsize
    if arg_present(ysize)         then ysize         = tmp.ysize
    if arg_present(scr_xsize)     then scr_xsize     = tmp.scr_xsize
    if arg_present(scr_ysize)     then scr_ysize     = tmp.scr_ysize
    if arg_present(xrange)        then xrange        = self.xran[*,2*self.xlog]
    if arg_present(yrange)        then yrange        = self.yran[*,2*self.ylog]
end

pro dm_plot::my_widget_control,uname,base,_extra=extra
    if n_elements(base)  eq 0 then base = (self.compound?self.plotWin:self.tlb)
    if n_elements(extra) ne 0 then begin
       for i=0,n_elements(uname)-1 do begin
           wid = widget_info(base,find_by_uname=uname[i])
           if wid ne 0 then widget_control,wid,_extra=extra
       endfor
    endif
end

function dm_plot::my_widget_id,uname
    return,widget_info((self.compound?self.plotWin:self.tlb),find_by_uname=uname)
end

;read in a 1D 2 or 3-column file or a 2D spe file and add it to the plot
pro dm_plot::readasciifile,oned=oned,twod=twod
    widget_control,/hourglass
    type = (keyword_set(twod)?'spe':'*')
    file = dm_choose_file(type,dialog_parent=self.tlb,/read,/must_exist)
    if strlen(file) eq 0 then return
    openr,unit,file,/get_lun,error=error
    if error ne 0 then begin
       ok = dialog_message("Can't read file "+file+'.',dialog_parent=self.tlb)
       return
    endif

    mesg  = widget_base(title='Loading data ...',/col,/base_align_center,group_leader=self.tlb)
    label = widget_label(mesg,value='Loading '+file[0]+'. Please wait ...',/align_center)
    dm_center_kid,mesg,self.tlb
    widget_control,mesg,/realize,map=1

    ;catch and clear possible io errors
    catch, myerror
    if myerror ne 0 then begin
       catch,/cancel
       ok = dialog_message(dialog_parent=self.tlb,!error_state.msg,/error)
       if n_elements(unit) ne 0 then free_lun,unit
       if widget_info(mesg,/valid_id) then widget_control,mesg,/destroy
       return
    end

    if keyword_set(oned) then begin
       bwcolor = (['white','black'])[self.bgcol]
       all_col = [bwcolor,'red','blue','magenta','green','cyan','yellow','grey','dark grey','dark red',$
                  'dark blue','dark magenta','dark green','dark cyan','dark yellow']
       n_col   = n_elements(all_col)
       all_sym = ['circle','bullet','plus','star','dot','diamond','triangle','square','cross','greater','less']
       n_sym   = n_elements(all_sym)
       legend  = strsplit(file,':\/',/extract)
       legend  = legend[n_elements(legend)-1]
       tmp = '' & line = 0
       while not eof(unit) do begin
            readf,unit,tmp & tmp = strtrim(tmp,2)
            if strlen(tmp) eq 0 then continue
            tmp1 = strsplit(tmp,' ,'+string(9b),/extract)
            tmp1 = dm_to_number(tmp1,/float,count=count)
            if total(finite(tmp1)) eq count then $
               if n_elements(data) eq 0 then data=tmp1 else data=[[data],[tmp1]] $
            else begin
               if n_elements(data) ne 0 then begin
                  color  = all_col[line mod n_col]
                  symbol = all_sym[line mod n_sym]
                  if n_elements(data[*,0]) eq 2 then $
                    self->add_plot,reform(data[0,*]),reform(data[1,*]),legend=legend,psym=symbol,color=color $
                  else if n_elements(data[*,0]) ge 3 then $
                    self->add_plot,reform(data[0,*]),reform(data[1,*]),yerr=reform(data[2,*]),legend=legend,$
                         psym=symbol,color=color
                  tmp2 = temporary(data)    ;destroy data
                  line = line+1
               endif
               legend = tmp
            endelse
       endwhile
       free_lun,unit
       if n_elements(data) ne 0 then begin
          widget_control,label,set_value='drawing ...'
          color  = all_col[line mod n_col]
          symbol = all_sym[line mod n_sym]
          if n_elements(data[*,0]) eq 2 then $
             self->add_plot,reform(data[0,*]),reform(data[1,*]),legend=legend,psym=symbol,color=color $
          else if n_elements(data[*,0]) ge 3 then $
             self->add_plot,reform(data[0,*]),reform(data[1,*]),yerr=reform(data[2,*]),legend=legend,$
                   psym=symbol,color=color
       endif
    endif else if keyword_set(twod) then begin
       dm_load_spe,unit,zdat=data,err=err,xdat=xdat,ydat=ydat
       widget_control,label,set_value='drawing ...'
       if n_elements(data) ne 0 then self->add_plot,xdat,ydat,data,/usepolygon,shading=1
    endif
    self->draw
    widget_control,mesg,/destroy
end

pro dm_plot::rotate,event
    if self.moveLegend eq 0 then begin
       haveTransform=self.trackBall->update(event,transform=qmat)
       if (haveTransform ne 0) then begin
          self.drawGroup->getproperty,transform=t
          self.drawGroup->setproperty,transform=t#qmat
          self.drawWin->draw,self.drawView
       endif
    endif
    case event.type of
       0:   begin  ;button press
            case event.press of
                1:  begin    ;left button down
                    widget_control,self.plotWin,draw_motion_events=1
                    self.drawView->getproperty,dimension=dim
                    xstart = self.viewplane[0]+(0>(event.x/dim[0])<1)*self.viewplane[2]
                    ystart = self.viewplane[1]+(0>(event.y/dim[1])<1)*self.viewplane[3]
                    tmp = self.drawWin->select(self.drawView,[event.x,event.y])
                    if obj_valid(tmp[0]) then $
                       if obj_isa(tmp[0],'IDLgrLegend') or obj_isa(tmp[0],'IDLgrText') then begin
                          self.select     = tmp[0]
                          self.moveLegend = 1b
                          self.select->getproperty,xcoord_conv=x,ycoord_conv=y
                          self.legdOffset = [x[0]-xstart,y[0]-ystart]
                          break
                       endif
                    end
                else:
            endcase
            end
       1:   begin   ;button release
            if n_elements(*self.plotInfo) ne 0 then $
               ind = where((*self.plotInfo)[*].type eq 2,nsurf) $
            else $
               nsurf = 0
            widget_control,self.plotWin,draw_motion_events=(self.motion_events or (self.showcpos and (nsurf eq 0)))
            self.moveLegend=0b
            end
       2:   if self.moveLegend then begin
            self.drawView->getproperty,dimension=dim
            xend = self.viewplane[0]+(0>(event.x/dim[0])<1)*self.viewplane[2]
            yend = self.viewplane[1]+(0>(event.y/dim[1])<1)*self.viewplane[3]
            self.select->getproperty,ycoord_conv=old_yconv,xcoord_conv=old_xconv
            new_yconv = [yend+self.legdOffset[1],1]
            new_xconv = [xend+self.legdOffset[0],1]
            if obj_isa(self.select,'IDLgrLegend') then begin
               self.legdpos[0] = self.legdpos[0]+new_xconv[0]-old_xconv[0]
               self.legdpos[1] = self.legdpos[1]+new_yconv[0]-old_yconv[0]
            endif
            self.select->setproperty,xcoord_conv=new_xconv,ycoord_conv=new_yconv
            self.drawWin->draw,self.drawView
            endif
       else:
    endcase
end

pro dm_plot::resize,event
    widget_control,self.tlb,update=0
    mbar_y = 0
    if widget_info(self.mbarSep,/valid_id) then begin
       widget_control,self.mbarSep,xsize=event.x
       mbar_y = widget_info(self.mbarSep,/geometry)
       mbar_y = mbar_y.ysize
    endif
    widget_control,self.plotWin,xsize=event.x,ysize=event.y-mbar_y
    self.drawWin->setproperty,dimension=[event.x,event.y-mbar_y]
    self.drawView->setproperty,dimension=[event.x,event.y-mbar_y]
    self.tranView->setproperty,dimension=[event.x,event.y-mbar_y]
    nplot = n_elements(*self.plotInfo)
    if nplot ne 0 then self->set_view
    widget_control,self.tlb,update=1
    self.drawWin->draw,self.drawView
end

;save plot as images or print
pro dm_plot::saveas,type,filename=filename
    type = strlowcase(strtrim(type,2))
    self.drawView->getproperty,dimension=dim
    resolution = [0.018,0.018]
    if (type ne 'printer') and (type ne 'ps') and (type ne 'ascii') then begin
       newdim = [!values.f_nan,!values.f_nan]
       while total(finite(newdim)) ne 2 do begin
          newdim = dm_dialog_input(['xsize','ysize'],title='Set pixel size',xsize=100,$
            default=self.default[5:6],dialog_parent=self.tlb,/int)
       endwhile
       self.drawView->setproperty,dimension=newdim
       self->set_view,/save   ;reverse black and white color
       buffer = obj_new('IDLgrBuffer',dimension=newdim,color_model=0,resolution=resolution)
       buffer->draw,self.drawView
       buffer->getproperty,image_data=image
       obj_destroy,buffer
    endif
    case type of
       'printer':   begin
          ok = dialog_printersetup(self.printer,dialog_parent=self.tlb)
          if not ok then break
          self.printer->getproperty,dimensions=printerDim
          windowAspect  = float(dim[1])/dim[0]
          printerAspect = float(printerDim[1])/printerDim[0]
          margin = 0.0  ;0.1
          if windowAspect le printerAspect then begin
             xstart = margin
             ystart = 0.5-(0.5-margin)*(windowAspect/printerAspect)
             xend   = 1.0-margin
             yend   = 1.0-ystart
          endif else begin
             xstart = 0.5-(0.5-margin)*(printerAspect/windowAspect)
             ystart = margin
             xend   = 1.0-xstart
             yend   = 1.0-margin
          endelse
          self->set_view,/save   ;reverse black and white color
          self.drawView->setproperty,dimensions=[xend-xstart,yend-ystart],$
             location=[xstart,ystart],units=3
          self.printer->newpage
          self.printer->draw,self.drawView
          self.printer->newdocument
         end
       'ps': begin
          if n_elements(filename) ne 0 then begin
             file = filename
             tmp  = obj_new('FSC_PSCONFIG')
             deviceKeywords = tmp->getkeywords()
             obj_destroy,tmp
          endif else $
             file = dm_choose_file('ps',/write,dialog_parent=self.tlb,deviceKeywords=deviceKeywords)
          widget_control,/hourglass  ;busy signal
          if strlen(file) ne 0 then begin
             if deviceKeywords.inches eq 0 then begin
                deviceKeywords.inches  = 1
                deviceKeywords.xsize   = deviceKeywords.xsize/2.54   ;cm->inch
                deviceKeywords.xoffset = deviceKeywords.xoffset/2.54
                deviceKeywords.ysize   = deviceKeywords.ysize/2.54   ;cm->inch
                deviceKeywords.yoffset = deviceKeywords.yoffset/2.54
             endif
             if deviceKeywords.landscape then begin
                tmp = deviceKeywords.ysize
                deviceKeywords.ysize   = deviceKeywords.xsize
                deviceKeywords.xsize   = tmp
                deviceKeywords.yoffset = deviceKeywords.yoffset-deviceKeywords.ysize
             endif
             if deviceKeywords.encapsulated eq 1 then begin
                deviceKeywords.xoffset = 0.0
                deviceKeywords.yoffset = 0.0
             endif
             dimensions = [deviceKeywords.xsize+deviceKeywords.xoffset,$
                      deviceKeywords.ysize+deviceKeywords.yoffset]*2.54/resolution
             border = [deviceKeywords.xoffset,deviceKeywords.yoffset]*2.54/resolution
             if deviceKeywords.landscape then begin
                transl = -[0.5,0.5,0]
                self.drawModel->translate,transl[0],transl[1],transl[2]
                self.drawModel->rotate,[0,0,1],-90
                self.drawModel->translate,-transl[0],-transl[1],-transl[2]
             endif
             maxdim = 2048.
             if dimensions[0] gt maxdim then begin
                factor     = maxdim/dimensions[0]
                dimensions = dimensions*factor
                border     = border*factor
             endif
             if dimensions[1] gt maxdim then begin
                factor     = maxdim/dimensions[1]
                dimensions = dimensions*factor
                border     = border*factor
             endif
             self.drawView->setproperty,dimension=dimensions-border,unit=0,location=border
             self->set_view,/save,landscape=deviceKeywords.landscape
             buffer = obj_new('IDLgrClipboard',quality=2,dimensions=dimensions,resolution=resolution)
             buffer->draw,self.drawView,/vector,/postscript,filename=file
             obj_destroy,buffer
             if deviceKeywords.landscape then begin
                self.drawModel->translate,transl[0],transl[1],transl[2]
                self.drawModel->rotate,[0,0,1],90
                self.drawModel->translate,-transl[0],-transl[1],-transl[2]
             endif
          endif
         end
       'ascii': begin ;ascii file
          onedplot = where((*self.plotInfo)[*].type eq 0,count1)
          twodplot = where(((*self.plotInfo)[*].type gt 0) and ((*self.plotInfo)[*].type lt 3),count2)
          nplots   = n_elements(*self.plotInfo)
          if count1 ne 0 then begin
             file = dm_choose_file('txt',/write,dialog_parent=self.tlb,title='Save 1D plot data as an ASCII file.')
             if strlen(file) eq 0 then break
             openw,unit,file,/get_lun,error=openerr
             if openerr ne 0 then begin
                ok = dialog_message("Can't write in "+file[0],/error,dialog_parent=self.tlb)
             endif else begin
                widget_control,/hourglass  ;busy signal
                for i=0L,count1-1 do begin
                    if count1 gt 1 then printf,unit,'##line ',dm_to_string(i),': ', (*self.plotInfo)[onedplot[i]].legend
                    x  = *(*self.plotInfo)[onedplot[i]].xPtr
                    y  = *(*self.plotInfo)[onedplot[i]].yPtr
                    nx = n_elements(x)
                    if onedplot[i]+1 lt nplots then $
                       if (*self.plotInfo)[onedplot[i]+1].type eq -1 then $
                          yerr = ((*(*self.plotInfo)[onedplot[i]+1].yPtr)[2*lindgen(nx)+1]-$
                                 (*(*self.plotInfo)[onedplot[i]+1].yPtr)[2*lindgen(nx)])/2.
                    for j=0L,nx-1 do begin
                        if n_elements(yerr) eq nx then $
                           printf,unit,x[j],' ',y[j],' ',yerr[j]  $
                        else $
                           printf,unit,x[j],' ',y[j]
                    endfor
                    yerr = 0 & tmp = temporary(yerr)  ;clear yerr
                endfor
                free_lun,unit
             endelse
          endif
          if count2 eq 1 then begin
             file = dm_choose_file('spe',/write,dialog_parent=self.tlb,title='Save 2D plot data as a SPE file.')
             if strlen(file) eq 0 then break
             openw,unit,file,/get_lun,error=openerr
             if openerr ne 0 then begin
                ok = dialog_message("Can't write in "+file[0],/error,dialog_parent=self.tlb)
             endif else begin
                x  = *((*self.plotInfo)[twodplot[0]]).xPtr
                y  = *((*self.plotInfo)[twodplot[0]]).yPtr
                z  = *((*self.plotInfo)[twodplot[0]]).zPtr
                itmp = where(finite(z) eq 0,count)
                if count ne 0 then z[itmp]=0.0
                dz = z*0.05
                widget_control,/hourglass  ;busy signal
                dm_write_spe,unit,x,y,z,dz
             endelse
          endif
         end
       else: begin
          if n_elements(filename) ne 0 then $
             file = filename $
          else $
             file = dm_choose_file(type,/write,dialog_parent=self.tlb)
          if strlen(file) eq 0 then break
          id = where(['bmp','gif','jpeg','png','ppm','srf','tiff'] eq type,count)
          widget_control,/hourglass   ;busy signal
          if type eq 'tiff' then image=transpose(image,[0,2,1])
          if count ne 0 then write_image,file,type,image
         end
    endcase
    if type ne 'ascii' then begin
       self.drawView->setproperty,dimension=dim,unit=0,location=[0,0]
       self->set_view
    endif
end

;set property
;usage:
;   dm_plot->setproperty,property=value
;     or
;   dm_plot->setproperty,object=object,property=property,value=value
;parameters:
;   NONE
;keyword:
;   axisthick:           axis thickness for all axes
;   bgcolor:             0-black background   1-white background
;   changeid:            changed id of plotinfo,internal call
;   color:               plot color or polygon filled color
;   coltable:            color table
;   error:               1 if error occurs    0 operation successful
;   font:                font name
;   fsize:               font size
;   showcursorpos:       if set, show the cursor position status string
;   hideintnbar:         if set, hide the intensity bar
;   hidelegend:          if set, plot legends are not shown
;   iso:                 1:isotropic plot 0:ratioed to window
;   keep:                1 or 0
;   layer:               layer of 1d plot
;   legend:              legend for the current plot
;   linestyle:           linestyle for the current plot
;   misscol:             missing data color for saving 2d plots 0:black, 1:white
;   no_copy:             to save memory
;   nodraw:              if set, don't draw the view
;   object:              for setting properties from dm_dialog_input apply button
;   plotInfo:            plot inforamtion,internal call
;   psym:                symbol number or symbol object
;   shading:             shading for object graphics
;   surfplot:            if set, 2d data are plot as surface rather than contour
;   symsize:             symbol size
;   thick:               line thickness for plots and symbols
;   title:               title of the plot
;   tickstyle:           0-idl default tick string format 1-use dm_to_string
;   usepolygon:          if set, use idlgrpolygon to draw contour plots instead of idlgrcontour
;                        or use filled polygon to plot connected points
;   xdat,ydat,zdat,idat: x,y,z,i data
;   xlog,ylog,zlog,ilog: log10 scale x,y,z,i respectively
;   xran,yran,zran,iran: x,y,z,i range
;   xtit,ytit,ztit:      x,y,z axis title string
;   yerr:                error bar of y
;   zmin,zmax:           zmin, zmax for contour plots
;   zoom:                in conjuction with [xyz]ran to show the set range is from zoom
pro dm_plot::setproperty,axisthick=axisthick,bgcolor=bgcolor,changeid=changeid,color=color,coltable=coltable,font=font,$
    fsize=fsize,showcursorpos=showcursorpos,hideintbar=hideintbar,hideLegend=hideLegend,idat=idat,irange=irange,ilog=ilog,$
    iso=iso,keep=keep,layer=layer,legend=legend,linestyle=linestyle,misscol=misscol,no_copy=no_copy,nodraw=nodraw,object=object,$
    plotInfo=plotInfo,psym=psym,shading=shading,showxgrid=showxgrid,showygrid=showygrid,surfplot=surfplot,symsize=symsize,thick=thick,$
    tickstyle=tickstyle,title=title,usepolygon=usepolygon,xdat=xdat,ydat=ydat,zdat=zdat,yerr=yerr,xlog=xlog,$
    ylog=ylog,zlog=zlog,xrange=xrange,yrange=yrange,zrange=zrange,xtitle=xtitle,ytitle=ytitle,ztitle=ztitle,zmin=zmin,$
    zmax=zmax,zoom=zoom,error=error,_extra=extra

    error  = 0.0
    redraw = 1
    ;catch and ignore all errors in this program
    catch, myerror
    if myerror ne 0 then begin
       catch,/cancel
       ok = dialog_message(!error_state.msg,/error)
       error = 1
       return
    end
    widget_control,/hourglass
    if (n_elements(object) ne 0) then begin
       if n_elements(coltable) ne 0 then begin
          for i=0,n_elements(object)-1 do begin
              object[i]->getproperty,palette=drawPal
              drawPal = self->getpalette(dm_to_number(coltable[0],/int),oldpal=drawPal)
          endfor
       endif
       if n_elements(color) ne 0 then begin
          for i=0,n_elements(object)-1 do $
              object[i]->setproperty,color=self->getcolor(color)
       endif
       if n_elements(linestyle) ne 0 then begin
          for i=0,n_elements(object)-1 do $
              object[i]->setproperty,linestyle=self->getlinestyle(linestyle)
       endif
       if n_elements(thick) ne 0 then begin
          thick = dm_to_number(thick[0])
          if not finite(thick) then thick=1
          for i=0,n_elements(object)-1 do $
              object[i]->setproperty,thick=thick
       endif
       self.drawWin->draw,self.drawView
       return
    endif
    if n_elements(bgcolor) ne 0 then begin
       blackbut = self->my_widget_id('dm_bgblack')
       whitebut = self->my_widget_id('dm_bgwhite')
       self.bgcol = 0>(bgcolor)<1
       if self.bgcol eq 0 then dm_toggle_menubut,blackbut,whitebut $
       else dm_toggle_menubut,whitebut,blackbut
       redraw = 2
    endif
    if n_elements(keep) ne 0 then begin
       self.keep = (0b)>(fix(keep,type=1))<(1b)
       if self.keep then begin
          self->my_widget_control,['dm_keepBut','dm_keepmenu'],sensitive=0
          self->my_widget_control,['dm_mkcrmenu','dm_mkcrBut'],sensitive=1
       endif else begin
          self->my_widget_control,['dm_keepBut','dm_keepmenu'],sensitive=1
          self->my_widget_control,['dm_mkcrmenu','dm_mkcrBut'],sensitive=0
       endelse
       redraw = 0  ;no need to redraw
    end
    if n_elements(misscol) ne 0 then begin
       blackbut = self->my_widget_id('dm_blackbg')
       whitebut = self->my_widget_id('dm_whitebg')
       self.misscol = 0>(misscol)<1
       if self.misscol eq 0 then dm_toggle_menubut,blackbut,whitebut $
       else dm_toggle_menubut,whitebut,blackbut
       redraw = 0  ;no need to redraw
    endif
    if n_elements(showxgrid) eq 1 then begin
       self.showxgrid = (0b)>(showxgrid)<(1b)
       self.xgrid->setproperty,hide=1-self.showxgrid
       logid = self->my_widget_id('dm_xgridBut')
       if logid gt 0 then dm_set_button,logid,self.showxgrid,onstring='Hide X Grid',offstring='Show X Grid'
       redraw = 1
    endif
    if n_elements(showygrid) eq 1 then begin
       self.showygrid = (0b)>(showygrid)<(1b)
       self.ygrid->setproperty,hide=1-self.showygrid
       logid = self->my_widget_id('dm_ygridBut')
       if logid gt 0 then dm_set_button,logid,self.showygrid,onstring='Hide Y Grid',offstring='Show Y Grid'
       redraw = 1
    endif
    if n_elements(showcursorpos) eq 1 then begin
       self.showcpos = (0b)>(showcursorpos)<(1b)
       self.cursorpos->setproperty,hide=1-self.showcpos
       if n_elements(*self.plotInfo) ne 0 then $
          ind = where((*self.plotInfo)[*].type eq 2,nsurf) $
       else $
          nsurf = 0
       widget_control,self.plotWin,draw_motion_events=(self.motion_events or (self.showcpos and (nsurf eq 0)))
       logid = self->my_widget_id('dm_showcposBut')
       if logid gt 0 then dm_set_button,logid,self.showcpos,onstring='Hide Cursor Position Status',$
          offstring='Show Cursor Position Status'
    endif
    if n_elements(tickstyle) ne 0 then begin
       idltick = self->my_widget_id('dm_idltick')
       owntick = self->my_widget_id('dm_owntick')
       self.tickstyle = 0>(tickstyle)<1
       if self.tickstyle eq 0 then dm_toggle_menubut,idltick,owntick $
       else dm_toggle_menubut,owntick,idltick
       self->set_view
       redraw = 1
    endif
    if n_elements(xlog) ne 0 then begin
       new = (0b>(byte(xlog))<1b)
       if self.xlog ne new then begin
          self.xlog = new
          logid     = self->my_widget_id('dm_xlogBut')
          if logid gt 0 then dm_set_button,logid,new,onstring='X Normal Scale',offstring='X Logarithmic Scale'
          redraw    = 2 ;need to reset view
       endif
    endif
    if n_elements(ylog) ne 0 then begin
       new = (0b>(byte(ylog))<1b)
       if self.ylog ne new then begin
          self.ylog = new
          logid     = self->my_widget_id('dm_ylogBut')
          if logid gt 0 then dm_set_button,logid,new,onstring='Y Normal Scale',offstring='Y Logarithmic Scale'
          redraw    = 2 ;need to reset view
       endif
    endif
    if n_elements(zlog) ne 0 then begin
       new = (0b>(byte(zlog))<1b)
       if self.zlog ne new then begin
          self.zlog = new
          logid     = self->my_widget_id('dm_zlogBut')
          if logid gt 0 then dm_set_button,logid,new,onstring='Z Normal Scale',offstring='Z Logarithmic Scale'
          redraw    = 2 ;need to reset view
       endif
    endif
    if n_elements(ilog) ne 0 then begin
       new = (0b>(byte(ilog))<1b)
       if self.ilog ne new then begin
          self.ilog = new
          logid     = self->my_widget_id('dm_ilogBut')
          if logid gt 0 then dm_set_button,logid,new,onstring='I Normal Scale',offstring='I Logarithmic Scale'
          redraw    = 2 ;need to reset view
       endif
    endif
    if n_elements(plotInfo) ne 0 then begin
       nplots   = n_elements(plotInfo)
       onedplot = where(plotInfo[*].type eq 0)
       if n_elements(changeid) eq 0 then changeid=indgen(nplots)
       for i=0,n_elements(changeid)-1 do begin
           switch plotInfo[changeid[i]].type of
            ;error plot
            -1: begin
                plotInfo[changeid[i]].obj->setproperty,thick=plotInfo[changeid[i]].thick,$
                    color=plotInfo[changeid[i]].color
                break
                end
            ;1d plot
            0:  begin
                zpos = 0
                if finite(plotInfo[changeid[i]].zpos) then $
                   zpos = plotInfo[changeid[i]].zpos
                if self.zlog then begin
                   if zpos gt 0 then zpos = alog10(zpos) $
                   else if finite(self.zran[1,2]) then zpos = 1.+alog10(self.zran[1,2])
                endif
                zpos = (-1.0e-4)*(1+(*plotInfo[changeid[i]].zPtr))+zpos
                plotInfo[changeid[i]].obj->getproperty,symbol=drawPsym
                newcolor   = plotInfo[changeid[i]].color
                newlinesty = plotInfo[changeid[i]].linestyle
                drawPsym   = self->getpsym(plotInfo[changeid[i]].psym,plotInfo[changeid[i]].symsize,plotInfo[changeid[i]].thick,$
                    newcolor,old=drawPsym)
                plotInfo[changeid[i]].obj->setproperty,color=newcolor,thick=plotInfo[changeid[i]].thick,linestyle=newlinesty,$
                    zvalue=zpos
                ;update the legend
                self->updatelegend
                ;change the color and thickness of the error plot if any
                if changeid[i]+1 lt nplots then $
                   if plotInfo[changeid[i]+1].type eq -1 then begin
                      (*plotInfo[changeid[i]+1].zPtr) = (*plotInfo[changeid[i]].zPtr)
                      plotInfo[changeid[i]+1].color   = newcolor
                      plotInfo[changeid[i]+1].thick   = plotInfo[changeid[i]].thick
                      plotInfo[changeid[i]+1].obj->getproperty,data=data
                      data[2,*] = zpos
                      plotInfo[changeid[i]+1].obj->setproperty,thick=plotInfo[changeid[i]+1].thick,color=newcolor,data=data
                   endif
                break
                end
            ;2d plot
            1:
            2:  begin
                plotInfo[changeid[i]].obj->getproperty,palette=drawPal
                drawPal=self->getpalette(plotInfo[changeid[i]].coltable,oldpal=drawPal)
                plotInfo[changeid[i]].obj->setproperty,shading=plotInfo[changeid[i]].shading
                break
                end
            ;filled polygon
            3:  begin
                zpos = 0.0
                if finite(plotInfo[changeid[i]].zpos) then $
                   zpos = plotInfo[changeid[i]].zpos
                if self.zlog then begin
                   if zpos gt 0 then zpos = alog10(zpos) $
                   else if finite(self.zran[1,2]) then zpos = 1.+alog10(self.zran[1,2])
                endif
                zpos = (-1.0e-4)*(1+(*plotInfo[changeid[i]].zPtr))+zpos
                plotInfo[changeid[i]].obj->getproperty,data=data
                data[2,*] = zpos
                plotInfo[changeid[i]].obj->setproperty,color=plotInfo[changeid[i]].color,data=data
                end
           endswitch
       endfor
       (*self.plotInfo) = temporary(plotInfo)
    endif
    if n_elements(iso) ne 0 then begin
       self.iso = 0>(iso)<1
       logid  = self->my_widget_id('dm_isoBut')
       if logid gt 0 then dm_set_button,logid,self.iso,onstring='Disable Isotropic Scaling',offstring='Enable Isotropic Scaling'
       redraw = 2  ;need to reset view
    endif
    if n_elements(hideLegend) ne 0 then begin
       self.hideLegend = 0b>(fix(hideLegend[0],type=1))<1b
       self.drawLegend->setproperty,hide=self.hideLegend
       id = self->my_widget_id('dm_cs_hidelegend')
       dm_set_button,id,self.hideLegend,onstring='Show Legend',offstring='Hide Legend'
    endif
    if n_elements(hideintbar) ne 0 then begin
       redraw = 2  ;need to reset view
       self.hideIntbar=0b>(fix(hideintbar[0],type=1))<1b
       id = self->my_widget_id('dm_cs_hidecbar')
       dm_set_button,id,self.hideIntbar,onstring='Show Colorbar',offstring='Hide Colorbar'
       if obj_valid(self.colBar) then begin
          self.drawxAxis[2]->setproperty,hide=self.hideIntbar
          self.drawxAxis[3]->setproperty,hide=self.hideIntbar
          self.drawyAxis[2]->setproperty,hide=self.hideIntbar
          self.drawyAxis[3]->setproperty,hide=self.hideIntbar
          self.colBar->setproperty,hide=self.hideIntbar
       end
    endif
    if n_elements(xdat) ne 0 then begin
       tmp_xmax = max(xdat,min=tmp_xmin,/nan)
       self.xran[*,0] = [temporary(tmp_xmin),temporary(tmp_xmax)]
       if self.xran[0,0] eq self.xran[1,0] then begin
          tmp = (self.xran[0,0] eq 0)? 0.5:abs(self.xran[0,0]/2.)
          self.xran[0,0] = self.xran[0,0]-tmp
          self.xran[1,0] = self.xran[1,0]+tmp
       endif
       poselts = where(xdat gt 0,count)
       if count gt 0 then begin
          tmp_xmax = max(xdat[temporary(poselts)],min=tmp_xmin)
       endif else begin
          tmp_xmin = 1.0 & tmp_xmax = 10.0
       endelse
       self.xran[0,2] = (tmp_xmin gt self.xran[0,0])?((self.xran[0,0] gt 0)?(self.xran[0,0]):(tmp_xmin)):(self.xran[0,0])
       self.xran[1,2] = (tmp_xmax gt self.xran[1,0])?((self.xran[1,0] gt 0)?(self.xran[1,0]):(tmp_xmax)):(self.xran[1,0])
       if self.xran[1,2] le self.xran[0,2] then self.xran[1,2]=self.xran[0,2]*10.0
    endif
    if n_elements(ydat) ne 0 then begin
       if n_elements(yerr) eq n_elements(ydat) then begin
          tmp_ymin = min(ydat-yerr,/nan)
          tmp_ymax = max(ydat+yerr,/nan)
       endif else $
          tmp_ymax = max(ydat,min=tmp_ymin,/nan)
       self.yran[*,0] = [temporary(tmp_ymin),temporary(tmp_ymax)]
       if self.yran[0,0] eq self.yran[1,0] then begin
          tmp = (self.yran[0,0] eq 0)? 0.5:abs(self.yran[0,0]/2.)
          self.yran[0,0] = self.yran[0,0]-tmp
          self.yran[1,0] = self.yran[1,0]+tmp
       endif
       poselts = where(ydat gt 0,count)
       if count gt 0 then begin
          ymax = max(ydat[temporary(poselts)],min=ymin)
       endif else begin
          ymin = 1.0 & ymax = 10.0
       endelse
       self.yran[0,2] = (ymin gt self.yran[0,0])?((self.yran[0,0] gt 0)?(self.yran[0,0]):(ymin)):(self.yran[0,0])
       self.yran[1,2] = (ymax gt self.yran[1,0])?((self.yran[1,0] gt 0)?(self.yran[1,0]):(ymax)):(self.yran[1,0])
       if self.yran[1,2] le self.yran[0,2] then self.yran[1,2]=self.yran[0,2]*10.0
    endif
    if (n_elements(zdat) eq 0) and (n_elements(idat) ne 0) then zdat=temporary(idat)
    if n_elements(zdat) ne 0 then begin
       tmp_zmax = max(zdat,min=tmp_zmin,/nan)
       self.zran[*,0] = [temporary(tmp_zmin),temporary(tmp_zmax)]
       if self.zran[0,0] eq self.zran[1,0] then begin
          tmp = (self.zran[0,0] eq 0)? 0.5:abs(self.zran[0,0]/2.)
          self.zran[0,0] = self.zran[0,0]-tmp
          self.zran[1,0] = self.zran[1,0]+tmp
       endif
       finelts = where(finite(zdat),count)
       if count gt 0 then poselts = where(zdat[finelts] gt 0,count)
       if count gt 0 then begin
          tmp_zmax = max(zdat[finelts[poselts]],min=tmp_zmin)
       endif else begin
          tmp_zmin = 1 & tmp_zmax = 10.0
       endelse
       finelts = -1 & poselts = -1
       self.zran[0,2] = (tmp_zmin gt self.zran[0,0])?((self.zran[0,0] gt 0)?(self.zran[0,0]):(tmp_zmin)):(self.zran[0,0])
       self.zran[1,2] = (tmp_zmax gt self.zran[1,0])?((self.zran[1,0] gt 0)?(self.zran[1,0]):(tmp_zmax)):(self.zran[1,0])
       if self.zran[1,2] le self.zran[0,2] then self.zran[1,2]=self.zran[0,2]*10.0
       self.zmin = self.zran[0,2*self.zlog]
       self.zmax = self.zran[1,2*self.zlog]
    endif
    if n_elements(idat) ne 0 then begin
       tmp_imax = max(idat,min=tmp_imin,/nan)
       self.iran[*,0] = [temporary(tmp_imin),temporary(tmp_imax)]
       if self.iran[0,0] eq self.iran[1,0] then begin
          tmp = (self.iran[0,0] eq 0)? 0.5:abs(self.iran[0,0]/2.)
          self.iran[0,0] = self.iran[0,0]-tmp
          self.iran[1,0] = self.iran[1,0]+tmp
       endif
       finelts=where(finite(idat),count)
       if count gt 0 then poselts=where(idat[finelts] gt 0,count)
       if count gt 0 then begin
          tmp_imax = max(idat[finelts[poselts]],min=tmp_imin)
       endif else begin
          tmp_imin = 1 & tmp_imax = 10.0
       endelse
       finelts = -1 & poselts = -1
       self.iran[0,2] = (tmp_imin gt self.iran[0,0])?((self.iran[0,0] gt 0)?(self.iran[0,0]):(tmp_imin)):(self.iran[0,0])
       self.iran[1,2] = (tmp_imax gt self.iran[1,0])?((self.iran[1,0] gt 0)?(self.iran[1,0]):(tmp_imax)):(self.iran[1,0])
       if self.iran[1,2] le self.iran[0,2] then self.iran[1,2]=self.iran[0,2]*10.0
       self.zmin = self.iran[0,2*self.ilog]
       self.zmax = self.iran[1,2*self.ilog]
    endif
    if n_elements(xtitle) ne 0 then self.xtit->setproperty,strings=xtitle[0]
    if n_elements(ytitle) ne 0 then self.ytit->setproperty,strings=ytitle[0]
    if n_elements(ztitle) ne 0 then self.ztit->setproperty,strings=ztitle[0]
    if n_elements(title) ne 0 then begin
       self.title->getproperty,strings=old
       self.title->setproperty,strings=title[0]
       if strlen(old) eq 0 or strlen(title[0]) eq 0 then redraw=2
       if self.compound eq 0 then widget_control,self.tlb,base_set_title=(strlen(title) eq 0?'plot':title)
    endif
    if n_elements(xrange) eq 2 then $
       if (total(finite(xrange)) eq 2) then $
          if xrange[1] gt xrange[0] then begin
             redraw = 2
             if keyword_set(zoom) then begin
                if total(finite(self.xran[*,2*self.xlog+1])) ne 2 then self.xran[*,2*self.xlog+1]=self.xran[*,2*self.xlog]
                if total(finite(self.yran[*,2*self.ylog+1])) ne 2 then self.yran[*,2*self.ylog+1]=self.yran[*,2*self.ylog]
             endif
             if self.xlog eq 1 then begin
                if xrange[0] gt 0 then self.xran[0,2] = xrange[0]
                if xrange[1] gt 0 then self.xran[1,2] = xrange[1]
             endif else self.xran[*,0] = xrange
          endif
    if n_elements(yrange) eq 2 then $
       if (total(finite(yrange)) eq 2) then $
          if yrange[1] gt yrange[0] then begin
             redraw = 2
             if keyword_set(zoom) then begin
                if total(finite(self.xran[*,2*self.xlog+1])) ne 2 then self.xran[*,2*self.xlog+1]=self.xran[*,2*self.xlog]
                if total(finite(self.yran[*,2*self.ylog+1])) ne 2 then self.yran[*,2*self.ylog+1]=self.yran[*,2*self.ylog]
             endif
             if self.ylog eq 1 then begin
                if yrange[0] gt 0 then self.yran[0,2] = yrange[0]
                if yrange[1] gt 0 then self.yran[1,2] = yrange[1]
             endif else self.yran[*,0] = yrange
          endif
    if n_elements(zrange) eq 2 then $
       if (total(finite(zrange)) eq 2) then $
          if zrange[1] gt zrange[0] then begin
             redraw = 2
             if self.zlog eq 1 then begin
                if zrange[0] gt 0 then self.zran[0,2] = zrange[0]
                if zrange[1] gt 0 then self.zran[1,2] = zrange[1]
             endif else self.zran[*,0] = zrange
          endif
    if (n_elements(idat) eq 0) and (n_elements(zdat) ne 0) then self.iran[*,[0,2]]=self.zran[*,[0,2]]
    if n_elements(irange) eq 2 then $
       if (total(finite(irange)) eq 2) then $
          if irange[1] gt irange[0] then begin
             redraw = 2
             if self.ilog eq 1 then begin
                if irange[0] gt 0 then self.iran[0,2] = irange[0]
                if irange[1] gt 0 then self.iran[1,2] = irange[1]
             endif else self.iran[*,0]=irange
          endif
    if n_elements(zmin) ne 0 then self.zmin = zmin[0]
    if n_elements(zmax) ne 0 then self.zmax = zmax[0]
    if n_elements(axisthick) ne 0 then begin
       self.axisthick = 1.0>(axisthick)<10.0
       for i=0,3 do begin
           if obj_valid(self.drawxAxis[i]) then self.drawxAxis[i]->setproperty,thick=self.axisthick
           if obj_valid(self.drawyAxis[i]) then self.drawyAxis[i]->setproperty,thick=self.axisthick
       endfor
       if obj_valid(self.drawzAxis) then self.drawzAxis->setproperty,thick=self.axisthick
    endif
    if (n_elements(xdat) ne 0) and (n_elements(ydat) ne 0) then begin
       redraw=2  ;need to reset view
       self.xran[*,[1,3]] = !values.f_nan
       self.yran[*,[1,3]] = !values.f_nan
       self.zran[*,[1,3]] = !values.f_nan
       self.iran[*,[1,3]] = !values.f_nan
       self->erase,/nodraw
       if n_elements(zdat) ne 0 then $
          self->add_plot,xdat,ydat,zdat,idat,no_copy=no_copy,surfplot=surfplot,coltable=coltable,$
                shading=shading,usepolygon=usepolygon $
       else $
          self->add_plot,xdat,ydat,yerr=yerr,no_copy=no_copy,legend=legend,thick=thick,color=color,$
                psym=psym,linestyle=linestyle,symsize=symsize,layer=layer,usepolygon=usepolygon
       ;cursor position string
       widget_control,self.plotWin,draw_motion_events=(self.motion_events or (self.showcpos and not keyword_set(surfplot)))
    endif
    if keyword_set(nodraw) then return
    if redraw eq 1 then begin
       self.drawView->setproperty,hide=0
       self.drawWin->draw,self.drawView
    endif else if redraw eq 2 then $
       self->draw
end

;setup correct viewing plane rectangle
;and suppress xaxis[1]'s tickname
;keyword
;   save:       if set, change white color to black color for saving purpose
;   landscape:  if set, the image is rotated
pro dm_plot::set_view,save=save,landscape=landscape
    if keyword_set(save) then bgcolor=[255b,255b,255b] else bgcolor=[255b,255b,255b]*self.bgcol
    if obj_valid(self.drawxAxis[1]) then begin
       self.drawxAxis[1]->getproperty,ticktext=xtick
       xtick->getproperty,strings=tmp
       for i=0,n_elements(tmp)-1 do tmp[i]=''
       xtick->setproperty,strings=tmp
       self.drawxAxis[1]->setproperty,ticktext=xtick
    endif
    self.drawView->getproperty,dimensions=dim       ;viewport size
    xsize = dim[0]
    ysize = dim[1]
    fsize = self.fsize
    if not keyword_set(save) then $
       fsize = fix((1>min(dim/self.default[5:6]))*fsize[*])
    for i=0,n_elements(fsize)-1 do $
        self.font[i]->setproperty,size=fsize[i]     ;modify fontsize

    if keyword_set(landscape) then begin
       yoffset = [0.0,0.0]
       xoffset = [(fsize[0]*self.fscale[0]*1.8+fsize[1]*self.fscale[1]*2.4+20),self.fscale[0]*fsize[0]*0.6+40]
    endif else begin
       xoffset = [0.0,0.0]
       yoffset = [(fsize[0]*self.fscale[0]*1.8+fsize[1]*self.fscale[1]*2.4+10),self.fscale[0]*fsize[0]*0.6+10]
    endelse
    ;get the axis tickmarks to figure out the offset of the viewplane
    self.drawxAxis[0]->setproperty,ticktext=obj_new()
    self.drawxAxis[0]->getproperty,ticktext=xtick,tickvalues=xtickvalue
    xtick->getproperty,strings=xticktext
    if self.tickstyle then begin
       xticktext = dm_to_string(xtickvalue)
       xtick->setproperty,strings=xticktext
    endif
    if keyword_set(landscape) then $
       yoffset[0] = (dm_strlen(xticktext[n_elements(xticktext)-1])/2.+0.3)*fsize[0]*self.fscale[0]+5 $
    else $
       xoffset[1] = (dm_strlen(xticktext[n_elements(xticktext)-1])/2.+0.3)*fsize[0]*self.fscale[0]+5
    self.drawyAxis[0]->setproperty,ticktext=obj_new()
    self.drawyAxis[0]->getproperty,ticktext=ytick,tickvalues=ytickvalue
    ytick->getproperty,strings=yticktext
    if self.tickstyle then begin
       yticktext = dm_to_string(ytickvalue)
       ytick->setproperty,strings=yticktext
    endif
    if keyword_set(landscape) then $
       yoffset[1] = (max(dm_strlen(yticktext)))*fsize[0]*self.fscale[0]*1.25+fsize[2]*self.fscale[2]*3.2+15 $
    else $
       xoffset[0] = (max(dm_strlen(yticktext)))*fsize[0]*self.fscale[0]*1.25+fsize[2]*self.fscale[2]*3.2+15
    self.title->getproperty,strings=title
    title = strlowcase(strtrim(title,2))
    if dm_strlen(title) ne 0 then begin
       if keyword_set(landscape) then $
          xoffset[1] = xoffset[1]+2.5*fsize[4]*self.fscale[4]  $
       else $
          yoffset[1] = yoffset[1]+2.5*fsize[4]*self.fscale[4]
    endif

    nplot = n_elements(*self.plotInfo)
    xran  = [0.,1.]
    yran  = [0.,1.]
    if nplot ne 0 then begin
       onedplot = where((*self.plotInfo)[*].type le 0,onedcount)
       twodplot = where(((*self.plotInfo)[*].type gt 0) and ((*self.plotInfo)[*].type lt 3),twodcount)
       surfplot = where((*self.plotInfo)[*].type eq 2,surfcount)
       polyplot = where((*self.plotInfo)[*].type eq 3,polycount)
       if (self.hideIntbar eq 0b) and (twodcount ne 0) then begin
          if keyword_set(landscape) then $
             yran = [-0.2,1] $
          else $
             xran = [0.,1.2]
          self.drawyAxis[3]->setproperty,ticktext=obj_new()
          self.drawyAxis[3]->getproperty,ticktext=cytick,tickvalues=ytickvalue
          cytick->getproperty,strings=yticktext
          if self.tickstyle then begin
             yticktext = dm_to_string(ytickvalue)
             cytick->setproperty,strings=yticktext
          endif
          if keyword_set(landscape) then $
             yoffset[0] = (0.5+max(dm_strlen(yticktext)))*fsize[0]*self.fscale[0]*1.25+15 $
          else $
             xoffset[1] = (0.5+max(dm_strlen(yticktext)))*fsize[0]*self.fscale[0]*1.25+15
       endif
       if surfcount ne 0 then begin
          if keyword_set(landscape) then begin
             yran[0] = 1-((yran[1]-yran[0])-0.25)
             yran[1] = 1.7
             xran[0] = -0.3
          endif else begin
             xran[0] = -0.7
             xran[1] = xran[1]-0.25
             yran[0] = -0.3
          endelse
          if keyword_set(save) then begin    ;make sure the clipped off image is visible when saved
             self.drawGroup->getproperty,transform=newt
             newt = newt[0:2,0:2]
             tmp0 = [-0.5,0.5,1]#newt
             tmp1 = [-0.5,-0.5,0]#newt
             tmp2 = [-0.5,0.5,0]#newt
             tmp3 = [0.5,-0.5,0]#newt
             if keyword_set(landscape) then begin
                yran[1] = 1-fix(min([tmp0[0],tmp1[0],tmp2[0],tmp3[0]])*10.5)/10.0
                xran[0] = fix(min([tmp0[1],tmp1[1],tmp2[1],tmp3[1]])*10.5)/10.0
             endif else begin
                xran[0] = fix(min([tmp0[0],tmp1[0],tmp2[0],tmp3[0]])*10.5)/10.0
                yran[0] = fix(min([tmp0[1],tmp1[1],tmp2[1],tmp3[1]])*10.5)/10.0
             endelse
          endif
          self.drawzAxis->setproperty,ticktext=obj_new()
          self.drawzAxis->getproperty,ticktext=ztick,tickvalues=ztickvalue
          ztick->getproperty,strings=zticktext
          if self.tickstyle then begin
             zticktext = dm_to_string(ztickvalue)
             ztick->setproperty,strings=zticktext
          endif
          if keyword_set(landscape) then begin
             yoffset[1] = (max(dm_strlen(zticktext)))*fsize[0]*self.fscale[0]*1.+fsize[3]*self.fscale[3]*3+15
             xoffset[0] = fsize[0]*self.fscale[0]*0.9+fsize[1]*self.fscale[1]*1.0+20
             xoffset[1] = xoffset[1]+30
          endif else begin
             xoffset[0] = (max(dm_strlen(zticktext)))*fsize[0]*self.fscale[0]*1.+fsize[3]*self.fscale[3]*3+15
             yoffset[0] = fsize[0]*self.fscale[0]*0.9+fsize[1]*self.fscale[1]*2.2+10
             yoffset[1] = yoffset[1]+10
          endelse
       endif
    endif

    viewplane_rect    = [xran[0],yran[0],xran[1]-xran[0],yran[1]-yran[0]]  ;viewing volume
    xoffset1          = xoffset/(xsize-total(xoffset))*viewplane_rect[2]
    yoffset1          = yoffset/(ysize-total(yoffset))*viewplane_rect[3]
    viewplane_rect[0] = viewplane_rect[0]-xoffset1[0]
    viewplane_rect[1] = viewplane_rect[1]-yoffset1[0]
    viewplane_rect[2] = viewplane_rect[2]+xoffset1[0]+xoffset1[1]
    viewplane_rect[3] = viewplane_rect[3]+yoffset1[0]+yoffset1[1]

    if self.iso then begin ;isotropic scaling
       xoff = 0.0 & yoff = 0.0
       if self.xlog then xran = alog10(self.xran[*,2]) else xran = self.xran[*,0]
       if self.ylog then yran = alog10(self.yran[*,2]) else yran = self.yran[*,0]
       if keyword_set(landscape) then begin
          tmp  = xran
          xran = yran
          yran = tmp
       endif
       aspect = (yran[1]-yran[0])/(xran[1]-xran[0])
       ratio  = float(ysize)/float(xsize)
       ;(y0+dy)/(x0+dx)==ratio/Aspect
       yoff = viewplane_rect[2]*ratio/aspect-viewplane_rect[3]
       xoff = viewplane_rect[3]*aspect/ratio-viewplane_rect[2]
       if xoff lt 0 then xoff = 0.
       if yoff lt 0 then yoff = 0.
       viewplane_rect[0] = viewplane_rect[0]-xoff/2.
       viewplane_rect[1] = viewplane_rect[1]-yoff/2.
       viewplane_rect[2] = viewplane_rect[2]+xoff
       viewplane_rect[3] = viewplane_rect[3]+yoff
    endif
    ;the cursor position status string is always at the lower left corner
    self.cursorpos->setproperty,xcoord_conv=[viewplane_rect[0]*0.9,1],ycoord_conv=[viewplane_rect[1]*0.9,1],$
        zcoord_conv=[1,1]
    self.drawView->setproperty,viewplane_rect=viewplane_rect,color=bgcolor,hide=0
    self.tranView->setproperty,viewplane_rect=viewplane_rect
    self.viewplane = viewplane_rect
    ;reverse black and white color of the axis if necessary
    for i=0,3 do begin
        if obj_valid(self.drawxAxis[i]) then begin
           self.drawxAxis[i]->getproperty,color=color
           if total(abs(color-bgcolor)) eq 0 then self.drawxAxis[i]->setproperty,color=[255b,255b,255b]-color
        endif
        if obj_valid(self.drawyAxis[i]) then begin
           self.drawyAxis[i]->getproperty,color=color
           if total(abs(color-bgcolor)) eq 0 then self.drawyAxis[i]->setproperty,color=[255b,255b,255b]-color
        endif
    endfor
    if obj_valid(self.drawzAxis) then begin
       self.drawzAxis->getproperty,color=color
       if total(abs(color-bgcolor)) eq 0 then self.drawzAxis->setproperty,color=[255b,255b,255b]-color
    endif
    ;reverse black and white for the grids if necessary
    if self.showxgrid then begin
       self.xgrid->getproperty,color=color
       if total(abs(color-bgcolor)) eq 0 then self.xgrid->setproperty,color=[255b,255b,255b]-color
    endif
    if self.showygrid then begin
       self.ygrid->getproperty,color=color
       if total(abs(color-bgcolor)) eq 0 then self.ygrid->setproperty,color=[255b,255b,255b]-color
    endif
    ;reverse black and white for text objects and modify their font sizes
    oChildArr = self.drawModel->IDL_Container::Get(/ALL, COUNT=nKids)
    for i=0,nKids-1 do begin
        if obj_isa(oChildArr[i],'IDLgrText') then begin
           oChildArr[i]->getproperty,color=color,font=ofont,name=name
           if total(abs(color-bgcolor)) eq 0 then oChildArr[i]->setproperty,color=[255b,255b,255b]-color
           if name eq 'text' then begin
              help,ofont,output=id & id=strsplit(id,' ',/extract) & id=id[n_elements(id)-1]
              index = where(*self.textsize eq id,count)
              if count eq 1 then begin
                 tmp_fsize = fix((1>min(dim/self.default[5:6]))*float((*self.textsize)[index+1]))
                 ofont->setproperty,size=tmp_fsize
              endif
           endif
        endif
    endfor
    ;update symbol size and color
    if nplot ne 0 then begin
       for i=0,onedcount-1 do begin
           (*self.plotInfo)[onedplot[i]].obj->getproperty,symbol=drawPsym,color=color
           if total(abs(color-bgcolor)) eq 0 then (*self.plotInfo)[onedplot[i]].obj->setproperty,color=[255b,255b,255b]-color
           if obj_valid(drawPsym) then begin
              drawPsym = self->getpsym((*self.plotInfo)[onedplot[i]].psym,(*self.plotInfo)[onedplot[i]].symsize,$
                  (*self.plotInfo)[onedplot[i]].thick,(*self.plotInfo)[onedplot[i]].color,old=drawPsym,landscape=landscape)
              drawPsym->getproperty,data=tmp,color=color
              if total(abs(color-bgcolor)) eq 0 then drawPsym->setproperty,color=[255b,255b,255b]-color
              if obj_valid(tmp) then begin
                 tmp->getproperty,color=color
                 if total(abs(color-bgcolor)) eq 0 then tmp->setproperty,color=[255b,255b,255b]-color
              endif
           endif
       endfor
       if onedcount ne 0 then begin
          ;reverse black and white color if necessary
          self.drawLegend->getproperty,item_color=item_color
          for i=0,n_elements(item_color[0,*])-1 do $
              if total(abs(item_color[*,i]-bgcolor)) eq 0 then item_color[*,i]=[255b,255b,255b]-bgcolor
          self.drawLegend->setproperty,item_color=item_color,text_color=[255b,255b,255b]-bgcolor,outline_color=[255b,255b,255b]-bgcolor
          ;update the drawlegend position
          show = where((*self.plotInfo)[onedplot].hide eq 0,count)
          if count gt 0 then begin
             legend = (*self.plotInfo)[onedplot[show]].legend
             show = where(strlen(strcompress(legend,/remove_all)) gt 0,count)
             if count gt 0 then begin
                self.drawLegend->getproperty,gap=gap
                if keyword_set(landscape) then $
                   tmp = self.legdpos[1]-(count+(count-1)*gap+4*gap)*fsize[5]/xsize*self.viewplane[2] $
                else $
                   tmp = self.legdpos[1]-(count+(count-1)*gap+4*gap)*fsize[5]/ysize*self.viewplane[3]
                new_yconv = [tmp,1]
                new_xconv = [self.legdpos[0]+((surfcount gt 0)?(-0.5):(0.0)),1]
                self.drawLegend->setproperty,ycoord_conv=new_yconv,xcoord_conv=new_xconv
             endif
          endif
       endif
       for i=0,polycount-1 do begin
           (*self.plotInfo)[polyplot[i]].obj->getproperty,color=color
           if total(abs(color-bgcolor)) eq 0 then $
              (*self.plotInfo)[polyplot[i]].obj->setproperty,color=[255b,255b,255b]-color
       endfor
       if keyword_set(save) then tmpcolor=[255b,255b,255b]*self.misscol else tmpcolor=bgcolor
       if twodcount gt 0 then $
          for i=0,twodcount-1 do begin
              if not obj_isa((*self.plotInfo)[twodplot[i]].obj,'IDLgrImage') then begin
                 (*self.plotInfo)[twodplot[i]].obj->getproperty,color=color
                 if total(abs(color-bgcolor)) eq 0 then $
                    (*self.plotInfo)[twodplot[i]].obj->setproperty,color=[255b,255b,255b]-bgcolor
              endif
              (*self.plotInfo)[twodplot[i]].obj->getproperty,palette=drawPal
              drawPal->getproperty,red_values=r,green_values=g,blue_values=b
              r[0]=tmpcolor[0] & g[0]=tmpcolor[1] & b[0]=tmpcolor[2]
              drawPal->setproperty,red_values=temporary(r),green_values=temporary(g),blue_values=temporary(b)
          endfor
    endif
end

;special treatment of strings
;keywords:
;   AA  :if set AA->anstrom string('c5'xb)
function dm_plot::textadjust,text,AA=AA
    ntext = n_elements(text)
    if ntext eq 0 then return,''
    tmp0  = text

    ;replace AA with angstrom letter string('c5'XB)
    if keyword_set(AA) then begin
       for i=0,ntext-1 do begin
           tmp1 = strpos(tmp0[i],'AA')
           while(tmp1 ne -1) do begin
                tmp0[i] = strmid(tmp0[i],0,tmp1)+string('c5'XB)+strmid(tmp0[i],tmp1+2,strlen(tmp0[i])-tmp1-2)
                tmp1    = strpos(tmp0[i],'AA')
           endwhile
       endfor
    endif

    return, (ntext eq 1)?tmp0[0]:tmp0
end

;push the plot window on top of other applications
pro dm_plot::totop
    widget_control,self.tlb,/show,iconify=0
    widget_control,self.plotWin,/input_focus
end

;update the draw legend
pro dm_plot::updatelegend,draw=draw
    nplot   = n_elements(*self.plotInfo)
    keyword = {item_object:[obj_new()],item_name:[''],item_linestyle:[6]}
    if nplot gt 0 then begin
       onedplot = where((*self.plotInfo)[*].type eq 0,onedcount)
       if onedcount gt 0 then begin
          keyw = {item_name:[''],item_linestyle:[6],item_object:[obj_new()]}
          show = where((*self.plotInfo)[onedplot].hide eq 0,count)
          if count gt 0 then begin
             item_name    = (*self.plotInfo)[onedplot[show]].legend
             item_thick   = (*self.plotInfo)[onedplot[show]].thick
             item_linesty = (*self.plotInfo)[onedplot[show]].linestyle
             item_color   = (*self.plotInfo)[onedplot[show]].color
             item_object  = (*self.plotInfo)[onedplot[show]].obj
             for i=0,count-1 do begin
                 item_object[i]->getproperty,symbol=tmp
                 item_object[i] = tmp
             endfor
             show = where(strlen(strcompress(item_name,/remove_all)) gt 0,count)
             if count ne 0 then $
                keyword = {item_name:item_name[show],item_type:intarr(count),item_linestyle:item_linesty[show],$
                  item_thick:item_thick[show],item_color:item_color[*,show],item_object:item_object[show]}
          endif
       endif
    endif
    self.drawLegend->setproperty,_extra=keyword
    if keyword_set(draw) then self.drawWin->draw,self.drawView
end

;mouse events in the plotwin
pro dm_plot::zoom,event
    if self.xlog eq 1 then xran = alog10(self.xran[*,2]) else xran = self.xran[*,0]
    if self.ylog eq 1 then yran = alog10(self.yran[*,2]) else yran = self.yran[*,0]
    case event.type of
       0:   begin  ;mouse button down
            case event.press of
               1:   begin    ;left button down
                    widget_control,self.plotWin,draw_motion_events=1
                    ;initialize the zoom box
                    self.drawView->getproperty,dimension=dim
                    xstart = self.viewplane[0]+(0>(event.x/dim[0])<1)*self.viewplane[2]
                    ystart = self.viewplane[1]+(0>(event.y/dim[1])<1)*self.viewplane[3]
                    tmp = self.drawWin->select(self.drawView,[event.x,event.y])
                    if obj_valid(tmp[0]) then $
                       if obj_isa(tmp[0],'IDLgrLegend') or $
                       (obj_isa(tmp[0],'IDLgrText') and (tmp[0] ne self.cursorpos)) then begin
                          self.moveLegend = 1b
                          self.select = tmp[0]
                          self.select->getproperty,xcoord_conv=x,ycoord_conv=y
                          self.legdOffset = [x[0]-xstart,y[0]-ystart]
                       break
                    endif
                    xstart = xran[0]+(0.0>(xstart)<1.0)*(xran[1]-xran[0])
                    ystart = yran[0]+(0.0>(ystart)<1.0)*(yran[1]-yran[0])
                    self.zoomBox = obj_new('IDLgrPolyline',replicate(xstart,5),replicate(ystart,5),replicate(0.02,5),$
                        color=self->getcolor('green'),xcoord_conv=norm_coord(xran),ycoord_conv=norm_coord(yran))
                    self.tranModel = obj_new('IDLgrModel')
                    self.tranModel->add,self.zoomBox
                    ;take a snap shot of current image
                    self.drawWin->draw,self.drawView,create_instance=2
                    self.tranView->add,self.tranModel
                    end
               else:
            endcase
            end
       1:   begin  ;mouse button up
            if n_elements(*self.plotInfo) ne 0 then $
               ind = where((*self.plotInfo)[*].type eq 2,nsurf) $
            else $
               nsurf = 0
            widget_control,self.plotWin,draw_motion_events=(self.motion_events or (self.showcpos and (nsurf eq 0)))
            widget_control,self.plotWin,/clear_events
            self.moveLegend = 0b
            if obj_valid(self.zoomBox) then begin
               self.zoomBox->getproperty,data=data
               xran = [min(data[0,[0,1]]),max(data[0,[0,1]])]
               yran = [min(data[1,[1,2]]),max(data[1,[1,2]])]
               obj_destroy,self.zoomBox
               obj_destroy,self.tranModel
               self.drawWin->draw,self.tranView,/draw_instance
               if (xran[1]-xran[0] ne 0) and (yran[1]-yran[0] ne 0) then $
                  self->setproperty,yran=(self.ylog eq 1)?(10.0^yran):yran,xran=(self.xlog eq 1)?(10.0^xran):xran,/zoom
            endif
            end
       2:   begin ;mouse motion
            self.drawView->getproperty,dimension=dim
            xend = self.viewplane[0]+(0>(event.x/dim[0])<1)*self.viewplane[2]
            yend = self.viewplane[1]+(0>(event.y/dim[1])<1)*self.viewplane[3]
            if self.moveLegend eq 1b then begin
               self.select->getproperty,ycoord_conv=old_yconv,xcoord_conv=old_xconv
               new_yconv = [yend+self.legdOffset[1],1]
               new_xconv = [xend+self.legdOffset[0],1]
               if obj_isa(self.select,'IDLgrLegend') then begin
                  self.legdpos[0] = self.legdpos[0]+new_xconv[0]-old_xconv[0]
                  self.legdpos[1] = self.legdpos[1]+new_yconv[0]-old_yconv[0]
               endif
               self.select->setproperty,xcoord_conv=new_xconv,ycoord_conv=new_yconv
               self.drawWin->draw,self.drawView
            endif else begin
               if not obj_valid(self.zoomBox) then break
               xend = xran[0]+(0.0>(xend)<1.0)*(xran[1]-xran[0])
               yend = yran[0]+(0.0>(yend)<1.0)*(yran[1]-yran[0])
               self.zoomBox->getproperty,data=data
               data[0,[1,2]] = [xend,xend]
               data[1,[2,3]] = [yend,yend]
               self.zoomBox->setproperty,data=data
               self.drawWin->draw,self.tranView,/draw_instance
            endelse
            end
       else:
    endcase
end

;cleanup, life cycle method
pro dm_plot::Cleanup
    if self.compound eq 1 then begin
       if widget_info(self.plotWin,/valid_id) then widget_control,self.plotWin,/destroy
    endif else begin
       if widget_info(self.tlb,/valid_id) then widget_control,self.tlb,/destroy
    endelse
    ;destroy all possible text objects
    oChildArr = self.drawModel->IDL_Container::Get(/ALL, COUNT=nKids)
    for i=0,nKids-1 do begin
        if obj_isa(oChildArr[i],'IDLgrText') then begin
           oChildArr[i]->getproperty,font=ofont
           obj_destroy,ofont
        endif
    endfor
    ;destroy all the plot symbols
    oChildArr = self.drawGroup->IDL_Container::Get(/ALL, COUNT=nKids)
    for i=0,nKids-1 do begin
        if obj_isa(oChildArr[i],'IDLgrPlot') then begin
           oChildArr[i]->getproperty,symbol=tmp1
           if obj_valid(tmp1) then begin
              tmp1[0]->getproperty,data=tmp2
              if obj_valid(tmp2) then obj_destroy,tmp2
              obj_destroy,tmp1
           endif
        endif
    endfor
    if n_elements(*self.plotInfo) ne 0 then begin
       ;destroy the draw palettes
       twodplot = where(((*self.plotInfo)[*].type gt 0) and ((*self.plotInfo)[*].type gt 0),count1)
       for i=0,count1-1 do begin
           (*self.plotInfo)[twodplot[i]].obj->getproperty, palette=tmp
           if obj_valid(tmp) then obj_destroy,tmp
       endfor
       ptr_free,(*self.plotInfo)[*].xPtr,(*self.plotInfo)[*].yPtr,(*self.plotInfo)[*].zPtr,(*self.plotInfo)[*].iPtr
    endif
    ptr_free,self.plotInfo,self.textsize
    obj_destroy,[self.drawView,self.tranView]
    obj_destroy,[self.font,self.printer,self.trackBall]
    obj_destroy,[self.xtit,self.ytit,self.ztit,self.title]
end

;initialization, life cycle method
;usage:
;   newplot=obj_new('dm_plot')
;parameters:
;   NONE
;keyword:
;   see the definition for most of the keywords
;   background: 'white' or 'black', the default background color for standalone plot window is black
;               and white for compound widget plot window
;   compound:   if set, dm_plot behaves like a compound widget, see test_plot_compound for an example
;   draw_motion_events: if set, allow draw motion event and the events will be passed out
;               event structure is the same as WIDGET_DRAW event except for xval & yval
;               {DM_PLOT_MOTION, ID:0L, TOP:0L, HANDLER:0L, TYPE: 0, X:0L, Y:0L,
;                PRESS:0B, RELEASE:0B, CLICKS:0L, MODIFIERS:0L, CH:0B, KEY:0L, XVAL:0E, YVAL:0E}
;               xval & yval are the converted x & y values of the current cursor
;   layer:      for layering of plots, 0 is the top level
;   shading:    0-flat  1-gouraud
;   surfplot:   if set, the 2D data is plotted as a surface plot
;   usepolygon: if all xdat,ydat,and zdat are present, settting this keyword will use idlgrpolygon to
;               draw the contour plot
;               if only xdat and ydat are present, setting this keyword will creat a filled polygon
function dm_plot::Init,xdat,ydat,zdat,idat,yerr=yerr,axisthick=axisthick,background=background,coltable=coltable,$
    color=color,compound=compound,draw_motion_events=draw_motion_events,font=font,fsize=fsize,group_leader=group_leader,$
    hideintbar=hideintbar,hidelegend=hidelegend,iso=iso,irange=irange,ilog=ilog,layer=layer,$
    legend=legend,linestyle=linestyle,misscol=misscol,no_copy=no_copy,parentobj=parentobj,parenthandler=parenthandler,psym=psym,$
    shading=shading,showcursorpos=showcursorpos,showxgrid=showxgrid,showygrid=showygrid,surfplot=surfplot,symsize=symsize,thick=thick,title=title,$
    usepolygon=usepolygon,widgetbase=widgetbase,xlog=xlog,xrange=xrange,xtitle=xtitle,xsize=xsize,ysize=ysize,$
    ylog=ylog,yrange=yrange,ytitle=ytitle,zlog=zlog,zmax=zmax,zmin=zmin,zrange=zrange,ztitle=ztitle

    if keyword_set(compound) and (n_elements(widgetbase) eq 0) and (n_elements(group_leader) eq 0) then begin
       ok = dialog_message("To be used as a compound widget, compound, widgetbase or group_leader keywords need to be set.",/error)
       return,0
    endif
    self.compound = keyword_set(compound)
    self.bgcol    = self.compound
    if n_elements(background) ne 0 then begin
       if strlowcase(background) eq 'black' then self.bgcol=0
       if strlowcase(background) eq 'white' then self.bgcol=1
    endif
    if float(!version.release) ge 6.0 then v6p0_extra= {register_properties:1}  ;register_properties keyword for IDL6.0 or later
    catch, myerror
    if myerror ne 0 then begin
       catch,/cancel
       ok = dialog_message(!error_state.msg,/error)
       return,0  ;indicating that an error occurs
    end
    if n_elements(xsize) eq 0 then xsize = 600
    if n_elements(ysize) eq 0 then ysize = 400
    ;default values for [ticklength,symsize,thick,shading,coltable,xsize,ysize,legend gap]
    self.default = [0.02,0.008,1.5,0.0,13.0,fix(xsize),fix(ysize),0.2]
    self.xran[*] = !values.f_nan
    self.yran[*] = !values.f_nan
    self.zran[*] = !values.f_nan
    self.iran[*] = !values.f_nan
    self.zmin    = !values.f_nan & self.zmax=!values.f_nan
    self.tickstyle = 0b
    self.legdpos = [0.65,0.85]
    ;check keywords
    if n_elements(parentobj) ne 0 then $
       if obj_valid(parentobj) then begin
          if n_elements(group_leader) eq 0 then parentobj->getproperty,tlb=group_leader
          if n_elements(parenthandler) eq 0 then parenthandler='event'
          self.parentobj     = parentobj
          self.parenthandler = parenthandler
       endif
    if n_elements(group_leader) ne 0 then self.group_leader=group_leader else self.group_leader=0
    if n_elements(xtitle) ne 0 then xtitle = self->textadjust(strtrim(xtitle[0],2),/AA) else xtitle = 'X'
    if n_elements(ytitle) ne 0 then ytitle = self->textadjust(strtrim(ytitle[0],2),/AA) else ytitle = 'Y'
    if n_elements(ztitle) ne 0 then ztitle = self->textadjust(strtrim(ztitle[0],2),/AA) else ztitle = 'Z'
    if n_elements(zmin)   ne 0 then self.zmin = zmin[0]
    if n_elements(zmax)   ne 0 then self.zmax = zmax[0]
    if n_elements(title)  ne 0 then title = self->textadjust(strtrim(title[0],2),/AA) else title = ''
    if n_elements(fsize)  ne 0 then self.fsize[*]=(8>(fix(fsize[0]))) else begin
       self.fsize[*] = 12 & self.fsize[6] = 8
    endelse
    if n_elements(axisthick) ne 0 then self.axisthick=1.0>(axisthick[0])<10.0 else self.axisthick=self.default[2]
    self.xlog = keyword_set(xlog)
    self.ylog = keyword_set(ylog)
    self.zlog = keyword_set(zlog)
    self.ilog = keyword_set(ilog)
    self.iso  = keyword_set(iso)
    self.showxgrid  = keyword_set(showxgrid)
    self.showygrid  = keyword_set(showygrid)
    self.showcpos   = keyword_set(showcursorpos)
    self.hideIntbar = keyword_set(hideintbar)
    self.hideLegend = keyword_set(hidelegend)
    self.misscol    = keyword_set(misscol)
    if not keyword_set(font) then font='Helvetica'
    self.textsize = ptr_new(/allocate_heap)
    for i=0,n_elements(self.font)-1 do $
        self.font[i] = obj_new('IDLgrFont',font,size=self.fsize[i],substitute='Hershey')
    self.font[0]->getproperty,name=tmp
    if strmid(strlowcase(tmp),0,7) eq 'hershey' then self.fscale[*]=1.2 else self.fscale[*]=1.0

    self.xtit  = obj_new('IDLgrText',xtitle,recompute_dimensions=2,font=self.font[1],/enable,_extra=v6p0_extra,name='xtitle')
    self.ytit  = obj_new('IDLgrText',ytitle,recompute_dimensions=2,font=self.font[2],/enable,_extra=v6p0_extra,name='ytitle')
    self.ztit  = obj_new('IDLgrText',ztitle,recompute_dimensions=2,font=self.font[3],/enable,_extra=v6p0_extra,name='ztitle')
    self.title = obj_new('IDLgrText',title,recompute_dimensions=2,font=self.font[4],/enable,color=self->getcolor('white'),$
                  name='titl',_extra=v6p0_extra)
    self.motion_events = keyword_set(draw_motion_events)
    ;create the widgets
    if keyword_set(compound) then begin
       if n_elements(group_leader) eq 0 then self.group_leader = widgetbase
       if n_elements(widgetbase) eq 0   then widgetbase = group_leader
       self.tlb = self.group_leader
       widget_control,self.tlb,/tlb_size_events
       ;draw widget
       self.plotWin = widget_draw(widgetbase,/button_events,uname='dm_plotWin',graphics_level=2,scr_xsize=self.default[5],$
                    scr_ysize=self.default[6],xsize=self.default[5],ysize=self.default[6],renderer=1,retain=0,/no_copy,$
                    motion_events=(self.motion_events or self.showcpos),event_pro='dm_plot_event')
       bar      = widget_base(self.plotWin,/CONTEXT_MENU,UNAME='dm_menu_Dir')
       filemenu = widget_button(bar,value='File',/menu)
       editmenu = widget_button(bar,value='Edit',/menu)
       widget_control,self.plotWin,set_uvalue=self
    endif else begin
       self.tlb = widget_base(uname='dm_tlb',mbar=bar,group_leader=self.group_leader,/tlb_size_events,/col,$
                  ypad=0,xpad=0,/align_center,map=0,space=0,title=(strlen(title) eq 0?'Plot':title))
       filemenu = widget_button(bar,value='File',/menu)
       editmenu = widget_button(bar,value='Edit',/menu)
       if self.group_leader ne 0 then begin
          keepmenu = widget_button(bar,value='Keep',/menu,uname='dm_keepmenu')
          mkcrmenu = widget_button(bar,value='Make Current',/menu,uname='dm_mkcrmenu',sensitive=0)
          ;keep menu
          keepBut  = widget_button(keepmenu,value='Keep',uname='dm_keepBut')
          mkcrBut  = widget_button(mkcrmenu,value='Make Current',uname='dm_mkcrBut',sensitive=0)
       endif
       ;menu bar separator for Windows operating system
       if !version.os_family eq 'Windows' then $
          self.mbarSep = widget_label(self.tlb,sensitive=0,/dynamic_resize,xsize=1)
       ;draw widget
       self.plotWin = widget_draw(self.tlb,/button_events,uname='dm_plotWin',graphics_level=2,scr_xsize=self.default[5],$
                    scr_ysize=self.default[6],xsize=self.default[5],ysize=self.default[6],renderer=1,retain=0,/no_copy,$
                    motion_events=(self.motion_events or self.showcpos))
       widget_control,self.tlb,set_uvalue=self
    endelse
    ;file menu
    saveBut  = widget_button(filemenu,value='Save',uname='dm_save')
    savemenu = widget_button(filemenu,value='Save As...',uname='dm_savemenu',/menu)
    bgclmenu = widget_button(filemenu,value='Color of Missing Data',/menu)
    readBut  = widget_button(filemenu,value='Read 2 or 3-Column 1D Data File...',uname='dm_readBut',/separator)
    readBut  = widget_button(filemenu,value='Read 2D SPE File...',uname='dm_readSpe')
    printBut = widget_button(filemenu,value='Print',uname='dm_printBut',/separator)
    pnsetBut = widget_button(filemenu,value='Printer Setup...',uname='dm_pnsetBut')
    if self.compound eq 0 then $    ;exit button not allowed in compound widget
    exitBut  = widget_button(filemenu,value='Exit',uname='dm_exitBut',/separator)
    saveps   = widget_button(savemenu,value='ps file',uname='dm_saveps')
    savejpeg = widget_button(savemenu,value='jpeg file',uname='dm_savejpg')
    savegif  = widget_button(savemenu,value='gif file',uname='dm_savegif')
    savebmp  = widget_button(savemenu,value='bmp file',uname='dm_savebmp')
    savepng  = widget_button(savemenu,value='png file',uname='dm_savepng')
    saveppm  = widget_button(savemenu,value='ppm file',uname='dm_saveppm')
    savetiff = widget_button(savemenu,value='tiff file',uname='dm_savetif')
    saveascii= widget_button(savemenu,value='ascii file',uname='dm_saveasc',/separator)
    blackbg  = dm_widget_button(bgclmenu,value='Black',uname='dm_blackbg')
    whitebg  = dm_widget_button(bgclmenu,value='White',uname='dm_whitebg')
    if self.misscol eq 0 then dm_toggle_menubut,blackbg,whitebg $
    else dm_toggle_menubut,whitebg,blackbg
    ;edit menu
    bgclmenu = widget_button(editmenu,value='Background Color',/menu)
    textBut  = widget_button(editmenu,value='Add Text',uname='dm_textBut',/separator)
    isotBut  = dm_widget_button(editmenu,value='Isotropic Scaling',uname='dm_isoBut',set_button=self.iso,$
                    onstring='Disable Isotropic Scaling',offstring='Enable Isotropic Scaling',/separator)
    gridBut  = dm_widget_button(editmenu,value='Show X Grid',uname='dm_xgridBut',set_button=self.showxgrid,$
                    onstring='Hide X Grid',offstring='Show X Grid')
    gridBut  = dm_widget_button(editmenu,value='Show Y Grid',uname='dm_ygridBut',set_button=self.showygrid,$
                    onstring='Hide Y Grid',offstring='Show Y Grid')
    cposBut  = dm_widget_button(editmenu,value='Show Cursor Position Status',uname='dm_showcposBut',$
                    set_button=self.showcpos,onstring='Hide Cursor Position Status',offstring='Show Cursor Position Status')
    if float(!version.release) ge 6.0 then $
    vallBut  = widget_button(editmenu,value='Show All Plots',uname='dm_show_all',sensitive=0)
    titlBut  = widget_button(editmenu,value='Title',uname='dm_titlBut',/separator)
    xtitBut  = widget_button(editmenu,value='X Title',uname='dm_xtitBut')
    xranBut  = widget_button(editmenu,value='X Range',uname='dm_xranBut')
    xlogBut  = dm_widget_button(editmenu,value='X Logarithmic Scale',uname='dm_xlogBut',set_button=self.xlog,$
                    onstring='X Normal Scale',offstring='X Logarithmic Scale')
    ytitBut  = widget_button(editmenu,value='Y Title',uname='dm_ytitBut')
    yranBut  = widget_button(editmenu,value='Y Range',uname='dm_yranBut')
    ylogBut  = dm_widget_button(editmenu,value='Y Logarithmic Scale',uname='dm_ylogBut',set_button=self.ylog,$
                    onstring='Y Normal Scale',offstring='Y Logarithmic Scale')
    ztitBut  = widget_button(editmenu,value='Z Title',uname='dm_ztitBut',sensitive=0)
    zranBut  = widget_button(editmenu,value='Z Range',uname='dm_zranBut',sensitive=0)
    zlogBut  = dm_widget_button(editmenu,value='Z Logarithmic Scale',uname='dm_zlogBut',sensitive=0,set_button=self.zlog,$
                    onstring='Z Normal Scale',offstring='Z Logarithmic Scale')
    iranBut  = widget_button(editmenu,value='I Range',uname='dm_iranBut',sensitive=0)
    ilogBut  = dm_widget_button(editmenu,value='I Logarithmic Scale',uname='dm_ilogBut',sensitive=0,set_button=self.zlog,$
                    onstring='I Normal Scale',offstring='I Logarithmic Scale')
    tickmenu = widget_button(editmenu,value='Tick Format',/menu)
    psymBut  = widget_button(editmenu,value='Plot Symbol',uname='dm_psymBut',sensitive=0,/separator)
    lineBut  = widget_button(editmenu,value='Plot Linestyle',uname='dm_lineBut',sensitive=0)
    pcolBut  = widget_button(editmenu,value='Plot Color',uname='dm_pcolBut',sensitive=0)
    lgndBut  = widget_button(editmenu,value='Legend Label',uname='dm_lgndBut',sensitive=0)
    hideBut  = dm_widget_button(editmenu,value='Hide Legend',uname='dm_cs_hidelegend',sensitive=0,set_button=self.hideLegend,$
                    onstring='Show Legend',offstring='Hide Legend')
    ctabBut  = widget_button(editmenu,value='Color Table',uname='dm_cs_coltable',sensitive=0,/separator)
    shadBut  = widget_button(editmenu,value='Shading',uname='dm_cs_shade',sensitive=0)
    hideBut  = dm_widget_button(editmenu,value='Hide Colorbar',uname='dm_cs_hidecbar',sensitive=0,set_button=self.hideIntbar,$
                    onstring='Show Colorbar',offstring='Hide Colorbar')
    bgblack  = dm_widget_button(bgclmenu,value='Black',uname='dm_bgblack')
    bgwhite  = dm_widget_button(bgclmenu,value='White',uname='dm_bgwhite')
    if self.bgcol eq 0 then dm_toggle_menubut,bgblack,bgwhite $
    else dm_toggle_menubut,bgwhite,bgblack
    idltick  = dm_widget_button(tickmenu,value='Default',uname='dm_idltick')
    owntick  = dm_widget_button(tickmenu,value='Abbreviated',uname='dm_owntick')
    if self.tickstyle eq 0 then dm_toggle_menubut,idltick,owntick $
    else dm_toggle_menubut,owntick,idltick

    ;context senstive menu
    cs_axisMenu  = widget_base(self.plotWin,/CONTEXT_MENU,UNAME='dm_cs_axisMenu')  ;axis object
       titlbut   = widget_button(cs_axisMenu,value='Title',uname='dm_cs_title')
       rangebut  = widget_button(cs_axisMenu,value='Range',uname='dm_cs_range')
       thickbut  = widget_button(cs_axisMenu,value='Thick',uname='dm_cs_axisthick')
       fontbut   = widget_button(cs_axisMenu,value='Font', uname='dm_cs_font')
       logbut    = dm_widget_button(cs_axisMenu,value='Logarithmic Scale',uname='dm_cs_logscale')
    cs_titlMenu  = widget_base(self.plotWin,/CONTEXT_MENU,UNAME='dm_cs_titlMenu')  ;title text object
       titlbut   = widget_button(cs_titlMenu,value='Title',uname='dm_cs_title')
       fontbut   = widget_button(cs_titlMenu,value='Font', uname='dm_cs_font')
       if float(!version.release) ge 6.0 then $
       propsheet = widget_button(cs_titlMenu,value='Property Sheet',uname='dm_cs_propsheet',/separator)
    cs_plotMenu  = widget_base(self.plotWin,/CONTEXT_MENU,UNAME='dm_cs_plotMenu')  ;1-d plot object
       symbbut   = widget_button(cs_plotMenu,value='Symbol',uname='dm_cs_symbol')
       colbut    = widget_button(cs_plotMenu,value='Color', uname='dm_cs_color')
       linebut   = widget_button(cs_plotMenu,value='Linestyle',uname='dm_cs_linestyle')
       thickbut  = widget_button(cs_plotMenu,value='Thick', uname='dm_cs_linethick')
       legndbut  = widget_button(cs_plotMenu,value='Legend',uname='dm_cs_legend')
       layerbut  = widget_button(cs_plotMenu,value='Layer',uname='dm_cs_layer',/separator)
       removebut = widget_button(cs_plotMenu,value='Remove',uname='dm_cs_remove')
       if float(!version.release) ge 6.0 then $
       propsheet = widget_button(cs_plotMenu,value='Property Sheet',uname='dm_cs_propsheet',/separator)
    cs_twodMenu  = widget_base(self.plotWin,/CONTEXT_MENU,UNAME='dm_cs_twodMenu')  ;2-d plot object
       coltbut   = widget_button(cs_twodMenu,value='Color table',uname='dm_cs_coltable')
       shadbut   = widget_button(cs_twodMenu,value='Shading',uname='dm_cs_shade')
    cs_legendMenu= widget_base(self.plotWin,/CONTEXT_MENU,UNAME='dm_cs_legendMenu')  ;legend object
       lablbut   = widget_button(cs_legendMenu,value='Labels',uname='dm_lgndBut')
       fontbut   = widget_button(cs_legendMenu,value='Font',uname='dm_cs_font')
       lgapbut   = widget_button(cs_legendMenu,value='Gap',uname='dm_cs_lgndgap')
       gwidbut   = widget_button(cs_legendMenu,value='Glyph Width',uname='dm_cs_lgndwidth')
       oulnbut   = widget_button(cs_legendMenu,value='Show Outline',uname='dm_cs_outline')
       hidebut   = widget_button(cs_legendMenu,value='Hide',uname='dm_cs_hidelegend',/separator)
       if float(!version.release) ge 6.0 then $
       propsheet = widget_button(cs_legendMenu,value='Property Sheet',uname='dm_cs_propsheet',/separator)
    cs_cbarMenu  = widget_base(self.plotWin,/CONTEXT_MENU,UNAME='dm_cs_cbarMenu')  ;color bar object
       zranbut   = widget_button(cs_cbarMenu,value='Range',uname='dm_cs_range')
       coltbut   = widget_button(cs_cbarMenu,value='Color table',uname='dm_cs_coltable')
       shadbut   = widget_button(cs_cbarMenu,value='Shading',uname='dm_cs_shade')
       fontbut   = widget_button(cs_cbarMenu,value='Font', uname='dm_cs_font')
       logbut    = dm_widget_button(cs_cbarMenu,value='Logarithmic Scale',uname='dm_cs_logscale')
       hidebut   = widget_button(cs_cbarMenu,value='Hide',uname='dm_cs_hidecbar',/separator)
    cs_textMenu  = widget_base(self.plotWin,/CONTEXT_MENU,UNAME='dm_cs_textMenu')  ;title text object
       titlbut   = widget_button(cs_textMenu,value='String',uname='dm_cs_title')
       fontbut   = widget_button(cs_textMenu,value='Font', uname='dm_cs_font')
       colbut    = widget_button(cs_textMenu,value='Color',uname='dm_cs_txtcolor')
       oribut    = widget_button(cs_textMenu,value='Orientation',uname='dm_cs_textori')
       removebut = widget_button(cs_textMenu,value='Remove',uname='dm_cs_remove',/separator)
       if float(!version.release) ge 6.0 then $
       propsheet = widget_button(cs_textMenu,value='Property Sheet',uname='dm_cs_propsheet',/separator)
    cs_gridMenu  = widget_base(self.plotWin,/CONTEXT_MENU,uname='dm_cs_gridMenu')  ;grids
       colbut    = widget_button(cs_gridMenu,value='Color',uname='dm_cs_txtcolor')
       linebut   = widget_button(cs_gridMenu,value='Linestyle',uname='dm_cs_linestyle')
       thickbut  = widget_button(cs_gridMenu,value='Thick', uname='dm_cs_linethick')
       hideBut   = widget_button(cs_gridMenu,value='Hide',uname='dm_cs_hidegrid',/separator)
    cs_polyMenu  = widget_base(self.plotWin,/CONTEXT_MENU,uname='dm_cs_polyMenu')  ;filled polygon
       colbut    = widget_button(cs_polyMenu,value='Color',uname='dm_cs_color')
       layerbut  = widget_button(cs_polyMenu,value='Layer',uname='dm_cs_layer',/separator)
       removebut = widget_button(cs_polyMenu,value='Remove',uname='dm_cs_remove')
       if float(!version.release) ge 6.0 then $
       propsheet = widget_button(cs_polyMenu,value='Property Sheet',uname='dm_cs_propsheet',/separator)

    if not keyword_set(compound) then begin
       dm_center_kid,self.tlb
       widget_control,self.tlb,/realize
    endif else $
       widget_control,self.plotWin,/realize
    widget_control,self.plotWin,get_value=oWindow
    self.drawWin   = oWindow
    self.drawView  = obj_new('IDLgrView',location=[0,0],dimensions=self.default[5:6],viewplane_rect=[0,0,1,1],$
                        color=self->getcolor((['black','white'])[self.bgcol]),zclip=[1.1,-1.1])
    self.tranView  = obj_new('IDLgrView',/transparent,location=[0,0],dimensions=self.default[5:6])
    self.drawModel = obj_new('IDLgrModel',lighting=0)
    self.drawGroup = obj_new('IDLgrModel',lighting=0)
    self.drawModel->add,self.drawGroup
    self.drawView->add,self.drawModel
    self.xgrid = obj_new('IDLgrPolyline',color=self->getcolor('grey'),hide=1-self.showxgrid,name='grid')
    self.ygrid = obj_new('IDLgrPolyline',color=self->getcolor('grey'),hide=1-self.showygrid,name='grid')
    self.drawGroup->add,self.xgrid
    self.drawGroup->add,self.ygrid
    bwcolor    = self->getcolor((['white','black'])[self.bgcol])
    self.drawLegend = obj_new('IDLgrLegend',text_color=bwcolor,xcoord_conv=[self.legdpos[0],1],$
       ycoord_conv=[self.legdpos[1],1],zcoord_conv=[1.0,1.0],font=self.font[5],name='legend',$
       gap=self.default[7],border_gap=2*self.default[7],outline_color=bwcolor,glyph_width=1.5,_extra=v6p0_extra)
    if float(!version.release) ge 6.0 then begin    ;register some properties
       self.drawLegend->registerproperty,'border_gap',3,    name='border gap'
       self.drawLegend->registerproperty,'fill_color',5,    name='fill color'
       self.drawLegend->registerproperty,'gap',3
       self.drawLegend->registerproperty,'glyph_width',3,   name='glyph width'
       self.drawLegend->registerproperty,'outline_color',5, name='outline color'
       self.drawLegend->registerproperty,'outline_thick',3, name='outline thick'
       self.drawLegend->registerproperty,'show_fill',1,     name='show fill'
       self.drawLegend->registerproperty,'show_outline',1,  name='show outline'
       self.drawLegend->registerproperty,'text_color',5,    name='text color'
    endif
    self.drawModel->add,self.drawLegend
    self.cursorpos = obj_new('IDLgrText','',font=self.font[6],color=bwcolor,$
            zcoord_conv=[1.0,1.0],recompute_dimensions=2,/enable,_extra=v6p0_extra,$
            hide=1-self.showcpos,name='cursorpos')
    self.drawModel->add,self.cursorpos
    self.trackBall = obj_new('Trackball',(self.default[5:6])/2,self.default[6]/2)
    self.printer   = obj_new('IDLgrPrinter',units=1,print_quality=2)
    self.plotInfo  = ptr_new(/allocate_heap)
    if self.bgcol then  self.drawWin->draw,self.drawView    ;white background

    if n_params() eq 2  then $
       self->setproperty,xdat=xdat,ydat=ydat,yerr=yerr,no_copy=no_copy,legend=legend,symsize=symsize,$
             linestyle=linestyle,thick=thick,psym=psym,color=color,xrange=xrange,yrange=yrange,$
             layer=layer,usepolygon=usepolygon,/nodraw $
    else if n_params() ge 3 then $
       self->setproperty,xdat=xdat,ydat=ydat,zdat=zdat,idat=idat,no_copy=no_copy,surfplot=surfplot,shading=shading,coltable=coltable,$
             usepolygon=usepolygon,xrange=xrange,yrange=yrange,zrange=zrange,irange=irange,/nodraw
    ;show the horizontal bar style menu bar separator
    if widget_info(self.mbarsep,/valid_id) then begin
       sep = bytarr(1000) & sep[*] = byte(175) & sep = string(sep)
       widget_control,self.mbarSep,set_value=temporary(sep),xsize=self.default[5]
    endif

    if not keyword_set(compound) then begin
       if xregistered('dave',/noshow) and (self.group_leader ne 0) then begin
          self.enotebook = 1b
          RET = DAVE_SET_FOCUS(self.tlb)
       endif
       xmanager,'dm_plot',self.tlb,cleanup='dm_plot_Exit',event_handler='dm_plot_event',/no_block
    endif
    return,1
end

;class definition
pro dm_plot__define
    struct={dm_plot,        $   ;class name
      group_leader:     0L, $   ;group leader of this object
      parentobj: obj_new(), $   ;parent object
      parenthandler:    '', $   ;event handler of parent object,default is 'event'
      tlb:              0L, $   ;identifier of top level base
      compound:         0b, $   ;1-compound widget 0-stand-alone plot window
      mbarSep:          0L, $   ;menu bar separator
                            $   ;ranges: [*,0]-current range [*,1]-original range  [*,2]-current log range [*,3]-original log range
      xran:    fltarr(2,4), $   ;xrange for the axis
      yran:    fltarr(2,4), $   ;yrange
      zran:    fltarr(2,4), $   ;zrange
      iran:    fltarr(2,4), $   ;irange for 2d plots, shown in color bar
      zmin:             0e, $   ;zmin for contour plot and surface plot
      zmax:             0e, $   ;zmax
      plotWin:          0L, $   ;draw widget
      motion_events:    0b, $   ;0-doesn't allow draw motion events 1-allow
      font:      objarr(7), $   ;font  0:for axis ticks 1:for xtitle 2:for ytitle 3:ztitle 4:title 5:legend 6:cursorpos
      fsize:     intarr(7), $   ;font size
      fscale:    fltarr(6), $   ;scaling factor
      axisthick:      1.5e, $   ;axis thickness
      title:     obj_new(), $   ;title
      xtit:      obj_new(), $   ;xtitle
      ytit:      obj_new(), $   ;ytitle
      ztit:      obj_new(), $   ;ztitle
      xlog:             0b, $   ;log10 scale x flag
      ylog:             0b, $   ;log10 scale y flag
      zlog:             0b, $   ;log10 scale z flag
      ilog:             0b, $   ;log 10 scale i flag    shown in colorbar
      drawWin:   obj_new(), $   ;draw window object
      drawView:  obj_new(), $   ;draw view object
      drawModel: obj_new(), $   ;draw model object
      drawGroup: obj_new(), $   ;contains all moveable graphic atoms, for surface rotation
      xgrid:     obj_new(), $   ;xgrid lines
      ygrid:     obj_new(), $   ;ygrid lines
      showxgrid:        0b, $   ;show xgrid flag
      showygrid:        0b, $   ;show ygrid flag
      cursorpos: obj_new(), $   ;cursor position status text object
      showcpos:         0b, $   ;flag for showing cursor position status text
      drawLegend:obj_new(), $   ;legends
      moveLegend:       0b, $   ;flag for legend movement
      hideLegend:       0b, $   ;hide legend flag
      legdOffset:fltarr(2), $   ;offset for legend movement
      legdpos:   fltarr(2), $   ;position of the legend
      hideIntbar:       0b, $   ;flag for showing the intensity bar in 2d contour plot
      plotInfo:  ptr_new(), $   ;plot informations
      tranView:  obj_new(), $   ;transparent view for zoom box
      tranModel: obj_new(), $   ;model object for zoom box
      drawxAxis: objarr(4), $   ;x axis
      drawyAxis: objarr(4), $   ;y axis
      drawzAxis: obj_new(), $   ;z axis
      colBar:    obj_new(), $   ;color bar
      zoomBox:   obj_new(), $   ;zoom box, a polyline object
      trackBall: obj_new(), $   ;trackall object for rotation
      iso:              0b, $   ;1-isotropic 0-aspect
      keep:             0b, $   ;1: keep this plot  0:open to new plots
      viewplane: fltarr(4), $   ;view plane rectangle
      printer:   obj_new(), $   ;printer
      select:    obj_new(), $   ;selected object
      default:   fltarr(8), $   ;default values for [ticklength,symsize,thick,shading,coltable,xsize,ysize,legend gap]
      misscol:          0b, $   ;flag for missing data color in saved file, default is black:0
      bgcol:            0b, $   ;flag for background color, default is black(0) for stand alone and white(1) for widget
      textsize:  ptr_new(), $   ;to store the actual size of the text fonts, point to a string array
      tickstyle:        0b, $   ;0-idl default tick string format 1-use dm_to_string
      enotebook:        0b  $   ;use Rob's enotebook
    }
end

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;examples: test,/oned & test,/twod & test,/surfplot
pro test,oned=oned,twod=twod,surfplot=surfplot,xdat=xdat,ydat=ydat,zdat=zdat,idat=idat,$
    xr=xr,yr=yr,zr=zr,data=data,_extra=_extra
    if (not keyword_set(oned)) and (not keyword_set(twod)) and (not keyword_set(surfplot)) then begin
       test_plot_compound
       return
    endif

    if keyword_set(oned) then begin
       nx   = 111
       xdat = sin(findgen(nx)*3)*10
       ydat = cos(findgen(nx)*2)*10
       xr   = [-10.2,10.2] & yr = xr
    endif
    if keyword_set(twod) then begin
       nx   = 201
       r    = (nx-1.)/2. & rsq = (r)^2
       xdat = findgen(nx)-r
       ydat = findgen(nx)-r
       zdat = fltarr(nx,nx)
       zdat[*] = !values.f_nan
       for i=0,nx-1 do begin
           xsq = xdat[i]*xdat[i]
           for j=0,nx-1 do begin
               tmp = r^2-xsq-ydat[j]*ydat[j]
               if tmp ge 0 then zdat[i,j] = sqrt(tmp)
           endfor
       endfor
       r   = r*1.05
       zr  = [-r,r] & xr = zr & yr = zr
    endif
    if keyword_set(surfplot) then begin
       rx    = 100 & rz   = 20
       nth   = 180 & nphi = 360
       theta = findgen(nth+1)*!dtor*360./nth
       phi   = findgen(nphi+1)*!dtor*360./nphi
       xdat  = fltarr(nth+1,nphi+1)
       ydat  = xdat & zdat = xdat
       for i=0,nth do begin
           for j=0,nphi do begin
               tmp = rx+rz*cos(phi[j])
               xdat[i,j] = tmp*cos(theta[i])*1.3
               ydat[i,j] = tmp*sin(theta[i])*1.3
               zdat[i,j] = rz*sin(phi[j])/1.5
           endfor
       endfor
       idat = (sin(xdat*!dtor)+sin(ydat*!dtor*2)+cos(zdat*!dtor*3))
       idat = idat + abs(min(idat))*1.5
       xr   = [-rx-rz,rx+rz]*1.5
       yr   = xr & zr = [-rz,rz]*3
    endif

    if keyword_set(data) then return

    current = systime(/sec)

    if keyword_set(oned)then begin
       tmp = obj_new('dm_plot',xdat,ydat,title='1d plot',color='white',linestyle='solid',$
             psym='circle',_extra=_extra,xtit='X axis', ytit='Y axis',xr=xr,yr=yr)
       tmp->draw
    endif else $
       tmp = obj_new('dm_plot',xdat,ydat,zdat,title='2d plot',zr=zr,xr=xr,yr=yr,surfplot=surfplot,usepolygon=twod,iso=twod,_extra=_extra)
    tmp->draw
    print,systime(/sec)-current,'seconds'
end
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;the following is a demonstration of using dm_plot as a compound widget
;example: test_plot_compound
pro test_plot_compound_Exit,tlb
    widget_control,tlb,get_uvalue=self
    if obj_valid(self) then obj_destroy,self
end

;widget event handler
pro test_plot_compound_event,event
    widget_control,event.handler,get_uvalue=self
    if obj_valid(self) then self->event,event
end

;object event handler
pro test_plot_compound::event,event
    widget_control,/hourglass

    ;catch and ignore all errors in this program
    catch, myerror
    if myerror ne 0 then begin
       ok = dialog_message(dialog_parent=self.tlb,!error_state.msg,/error)
       catch,/cancel
       return
    end

    case event.id of
        self.tlb:   begin   ;resize event
                    event.x = event.x-self.xoffset
                    event.y = event.y-self.yoffset
                    self.plotWin->resize,event
                    end
        self.plot1But: begin
                    self.plotWin->remove_text
                    test,xdat=xdat,ydat=ydat,xr=xr,yr=yr,/oned,/data
                    self.plotWin->setproperty,xdat=xdat,ydat=ydat,color='red',linestyle='solid',$
                        psym='circle',xr=xr,yr=yr,iso=0
                    self.plotWin->draw
                    widget_control,self.saveBut,/sensitive
                    widget_control,self.printBut,/sensitive
                    end
        self.plot2But: begin
                    self.plotWin->remove_text
                    off   = 0;1.5
                    xdat1 = [1,2,1,2]-off & ydat1=[1,2,2,1]-off & xr=[0.5,2.5]-off & yr=[0.5,2.5]-off
                    xdat2 = [0.75,2.25,2.25,0.75]-off & ydat2=[1.25,1.25,1.75,1.75]-off
                    self.plotWin->setproperty,xdat=xdat1,ydat=ydat1,color=[0,0,153],xr=xr,yr=yr,$
                        /usepolygon,iso=0,/nodraw,/hidelegend
                    self.plotWin->add_plot,xdat2,ydat2,color='blue',/usepolygon
                    self.plotWin->draw
                    widget_control,self.saveBut,/sensitive
                    widget_control,self.printBut,/sensitive
                    end
        self.plot3But: begin
                    self.plotWin->remove_text
                    test,xdat=xdat,ydat=ydat,zdat=zdat,xr=xr,yr=yr,zr=zr,/twod,/data
                    self.plotWin->setproperty,xdat=xdat,ydat=ydat,zdat=zdat,zr=zr,xr=xr,yr=yr,$
                        /usepolygon,iso=1
                    self.plotWin->draw
                    widget_control,self.saveBut,/sensitive
                    widget_control,self.printBut,/sensitive
                    end
        self.plot4But: begin
                    self.plotWin->remove_text
                    test,xdat=xdat,ydat=ydat,zdat=zdat,idat=idat,xr=xr,yr=yr,zr=zr,/surfplot,/data
                    self.plotWin->setproperty,xdat=xdat,ydat=ydat,zdat=zdat,idat=idat,zr=zr,xr=xr,yr=yr,$
                        /surfplot,iso=0,shading=1
                    self.plotWin->draw
                    widget_control,self.saveBut,/sensitive
                    widget_control,self.printBut,/sensitive
                    end
        self.saveBut:  self.plotWin->saveas,'ps'
        self.printBut: self.plotWin->saveas,'printer'
        self.exitBut:  widget_control,self.tlb,/destroy
        else:
    endcase
end

;cleanup
pro test_plot_compound::Cleanup
    if widget_info(self.tlb,/valid_id) then widget_control,self.tlb,/destroy
    obj_destroy,self.plotWin
end

;initialization
function test_plot_compound::Init,group_leader=group_leader
    registerName = 'test_plot_compound'
    if xregistered(registerName) then return,0    ;only allow one copy to be running at one time

    self.tlb = widget_base(title='Test dm_plot as a compound widget',/row,$
               kill_notify='test_plot_compound_Exit',group_leader=group_leader,map=0)

    left = widget_base(self.tlb,/col)
    self.plot1But = widget_button(left,value='Plot 1')
    self.plot2But = widget_button(left,value='Plot 2')
    self.plot3But = widget_button(left,value='Plot 3')
    self.plot4But = widget_button(left,value='Plot 4')
    self.saveBut  = widget_button(left,value='Save',sensitive=0)
    self.printBut = widget_button(left,value='Print',sensitive=0)
    self.exitBut  = widget_button(left,value='Exit')
    self.plotWin  = obj_new('dm_plot',xsize=400,ysize=300,/compound,widgetbase=self.tlb,group_leader=self.tlb)
        ;widgetbase is the base where the plotWin is placed, group_leader is the tlb for the resize event
        ;you don't need to specify tlb_size_event in creating the tlb
    dm_center_kid,self.tlb ;centering the top level base
    widget_control,self.tlb,/realize,/map

    ;the following codes are for the offset of the sizes in resize event
    tmp = widget_info(self.tlb,/geometry)
    self.plotWin->getproperty,xsize=xsize,ysize=ysize
    self.xoffset = tmp.xsize-xsize
    self.yoffset = tmp.ysize-ysize
    self.plotWin->add_text,'Welcome to DM_PLOT !C!C    Window is resizable',0.25,0.45,fontsize=16
    widget_control,self.tlb,set_uvalue=self
    xmanager,registerName,self.tlb,cleanup='test_plot_compound_Exit',/no_block
    return,1
end

;object definition
pro test_plot_compound__define
    void = {test_plot_compound,     $
            tlb:        0L,         $   ;top level base
            plot1But:   0L,         $   ;plot button
            plot2But:   0L,         $   ;plot button
            plot3But:   0L,         $   ;plot button
            plot4But:   0L,         $   ;plot button
            printBut:   0L,         $   ;print button
            saveBut:    0L,         $   ;save button
            exitBut:    0L,         $   ;exit button
            plotWin:    obj_new(),  $   ;plot window
            xoffset:    0L,         $   ;for resize event
            yoffset:    0L          $   ;for resize event
           }
end

pro test_plot_compound,event
    if n_elements(event) ne 0 then $
       void = obj_new('test_plot_compound',group_leader=event.top) $
    else $
       void = obj_new('test_plot_compound')
end
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++