;$Id: db_display2di__define.pro,v 1.34 2006/08/03 15:46:50 azuah Exp $
;###############################################################################
;
; CLASS NAME:
;   DB_Display2DI
;
; PURPOSE:
;   A widget object class responsible for displaying a DaveGr2D
;   object as an interactive color image.
;
; CATEGORY:
;   Data Browser
;
; SUPERCLASSES:
;
; PUBLIC METHODS:
;   AddText
;   CbarLabelEvent
;   DefLimEvent
;   DefXYLimEvent
;   DefZLimEvent
;   DispConSenMenu
;   DispTitleEvent
;   DisplayEvent
;   DrawEvent
;   ExitEvent
;   HandleConSenMenuEvent
;   NoRenew
;   NormAspectEvent
;   Print
;   Refresh
;   Renew
;   SetZrange
;   TlbEvent
;   ToggleZLog
;
; AUTHOR:
;   Richard Tumanjong Azuah
;   NIST Center for Neutron Research
;   100 Bureau Drive, Gaithersburg, MD 20899
;   United States
;   azuah@nist.gov; (301) 9755604
;   May, 2003
;
; 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.
;
;###############################################################################



;===============================================================================
; DB_Display2DI::Cleanup
;
; PURPOSE:
;   Cleanup procedure for DB_Display2DI
;
; PARAMETERS:
;
; KEYWORDS:
;
pro DB_Display2DI::Cleanup

; store/save current GUI/widget settings in the DaveGr2D object
void = (self.oDaveGr)->get(guiAttribsPtr=guiAttribsPtr)
(*guiAttribsPtr) = {winDim:self.winDim, $
                    xrangeFlag:self.xrangeFlag, $
                    xrange:self.xrange, $
                    yrangeFlag:self.yrangeFlag, $
                    yrange:self.yrange, $
                    zrangeFlag:self.zrangeFlag, $
                    zrange:self.zrange, $
                    cbarLabel:self.cbarLabel, $
                    normAspect:self.normAspect, $
                    dispTitle:self.dispTitle $
                   }

obj_destroy, self.oScene
obj_destroy, self.oDest
(self.o_registry)->remove,self  ; unregister self from Object Registry
(self.oActive2DCont)->remove, self.oDaveGr ; unregister DaveGr object from the active view list
ptr_free,self.ctableIDsPtr

; remove this widget object as the visualization object ref of the gr object
void = (self.oDaveGr)->set(visRef=obj_new())

device, decomposed=self.old_dec

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::Refresh
;
; PURPOSE:
;   Refresh the graphics window
;
; PARAMETERS
;   
;
; KEYWORDS:
;   
;
pro DB_Display2DI::Refresh, _EXTRA=etc

; require color decomposition (for using rgb colors directly)
; return to previous setting at end of this procedure
device, get_decomposed = old_dec
device, decompose=1

switch self.renewScene of

    0: begin
        self.renewScene = 1  ; reset to default value of 1
        objArr = (self.oScene)->get(/all, count=nObj)
        ;; if Scene is empty, proceed to case '1' by not 'breaking'
        if (nObj gt 0) then begin
            (self.oDest)->draw, self.oScene
            break
        endif
    end

    1: begin
        ;; Modify tlb widget title so it includes the current name tag
        ;; for the DaveGr object being viewed
        void = (self.oDaveGr)->get(nameTag=title)
        widget_control, self.tlb,tlb_set_title='DATABROWSER - '+title

        ;; create etc with dummy variable
        if (n_elements(etc) le 0) then etc = {dummyRefresh:0}

        ;; Set display mode
        ;case self.dispType of
        ;    0: etc = create_struct(etc,'dispType','POINTS')
        ;    1: etc = create_struct(etc,'dispType','HISTOGRAMS')
        ;endcase

        ;; Title
        etc = create_struct(etc,'dispTitle',self.dispTitle)

        ;; Annotate colorbar
        etc = create_struct(etc,'cbarLabel',self.cbarLabel)

        ;; Use normalized aspect ratio that is linked to the x,y-axis
        ;; data values
        etc = create_struct(etc,'normAspect',self.normAspect)

        ;; x-axis limits
        if (self.xrangeFlag) then begin
            etc = create_struct(etc,'xrange',self.xrange)
        endif
        ;; y-axis limits
        if (self.yrangeFlag) then begin
            etc = create_struct(etc,'yrange',self.yrange)
        endif
        ;; z-axis limits
        if (self.zrangeFlag) then begin
            etc = create_struct(etc,'zrange',self.zrange)
        endif

        ;Swap axes labels if data has just been transposed
        res1 = (self.oDaveGr)->get(xLabel=xLabel,yLabel=yLabel,dataRef=dataRef,transpose=grTrans)
        res2 = dataRef->get(transpose=datTrans)
        if (res1 && res2 && datTrans ne grTrans) then $
          void = (self.oDaveGr)->set(xLabel=yLabel,yLabel=xLabel,transpose=datTrans)

        ;; display data
        (self.oDaveGr)->display, self.oDest, self.oScene, _EXTRA=etc

        ; update data-range widgets
        if (self.zrangeFlag eq 0) then begin
            if (not (self.oDaveGr)->get(zmin=zmin,zmax=zmax)) then return
            self.zrange = [zmin,zmax]
            wid = widget_info(self.tlb, find_by_uname='ZMIN')
            widget_control, wid, set_value=self.zrange[0]
            wid = widget_info(self.tlb, find_by_uname='ZMAX')
            widget_control, wid, set_value=self.zrange[1]
        endif

    end

endswitch

; return color decomposition to previous setting
device, decompose=old_dec

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::HandleConSenMenuEvent
;
; PURPOSE:
;   Handle all events generated by widgets in context-sensitive
;   pop-up dialogs.
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::HandleConSenMenuEvent, event

;widget_control, event.top, get_uvalue = sPtr

; Get the selected CSM's name and value
uname = widget_info(event.id,/uname)
widget_control, event.id, get_uvalue=newValue
;newValue = newValueStr.val
;newIndex = newValueStr.ind

; Get the atom/model for which the CSM should act on
objRef = self.csmObjRef

switch uname of
    'INTERP': begin
        validAtomNames = ['IMAGE'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    objArr[nObj]->getProperty, uvalue=atomUval
                    daveGrRef = atomUval.objRef
                    objArr[nObj]->setProperty,interpolate=newValue
                    if (not daveGrRef->set(interpFlag=newValue)) then return
                    ;; Put a check mark against the selected value
                    interpIDs = self.interpIDs
                    case newValue of
                        0: begin
                            widget_control, interpIDs[0], set_button=1
                            widget_control, interpIDs[1], set_button=0
                        end
                        1: begin
                            widget_control, interpIDs[0], set_button=0
                            widget_control, interpIDs[1], set_button=1
                        end
                    endcase
                    self.renewScene = 0
                endif
            endwhile
        endif
        break
    end


    'CTABLE': begin
        validAtomNames = ['IMAGE'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    objArr[nObj]->getProperty, uvalue=atomUval
                    daveGrRef = atomUval.objRef
                    if (not daveGrRef->set(colorIndex=newValue)) then return
                    ctableIDs = *(self.ctableIDsPtr)
                    for i=0,n_elements(ctableIDs)-1 do begin
                        if (ctableIDs[i] eq event.id) then $
                          widget_control, ctableIDs[i], set_button=1 else $
                          widget_control, ctableIDs[i], set_button=0
                    endfor
                    self.renewScene = 0
                endif
            endwhile
        endif
        break
    end


    'THICK': begin
        validAtomNames = ['AXIS'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    objArr[nObj]->setProperty,thick=newValue
                    objArr[nObj]->getProperty, uvalue=atomUval
                    daveGrRef = atomUval.objRef
                    datInd = atomUval.datInd
                    case datInd of
                        0: kw_val = {xLineSize:newValue} ; x-axis
                        1: kw_val = {yLineSize:newValue} ; y-axis
                        else: kw_val = {dummy:0}
                    endcase
                    if (not daveGrRef->set(_EXTRA=kw_val)) then return
                    self->noRenew
                endif
            endwhile
        endif
        break
    end

    'COLOR': begin
        validAtomNames = ['AXIS','LABEL'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    objArr[nObj]->setProperty,color=newValue
                    objArr[nObj]->getProperty, uvalue=atomUval
                    daveGrRef = atomUval.objRef
                    datInd = atomUval.datInd
                    case atomName of
                        'AXIS': begin
                            case datInd of
                                0: kw_val = {xColor:newValue} ; x-axis
                                1: kw_val = {yColor:newValue} ; y-axis
                            endcase
                            if (not daveGrRef->set(_EXTRA=kw_val)) then return
                        end

                        'LABEL': begin
                            case datInd of
                                -1: begin ; title
                                    if (not daveGrRef->get(title=title)) then return
                                    title.color = newValue
                                    if (not daveGrRef->set(title=title)) then return
                                end
                                else: begin ; misc label
                                    if (not daveGrRef->get(label=label)) then return
                                    label[datInd].color = newValue
                                    if (not daveGrRef->set(label=label)) then return
                                end
                            endcase
                        end
                    endcase
                    self->noRenew
                endif
            endwhile
        endif
        break
    end

    'FONT': begin
        validAtomNames = ['AXIS','LABEL'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    case atomName of
                        'AXIS': begin
                            objArr[nObj]->getProperty, title=titleRef, uvalue=atomUval
                            if (obj_valid(titleRef)) then begin
                                titleRef->GetProperty, font=fontRef
                                fontRef->GetProperty, name=curValue
                                tokens = strtok(curValue,'*',/extract) ; are there font modifiers present?
                                ntokens = n_elements(tokens)
                                if (ntokens gt 1) then $ ; include current font modifiers
                                  newValue = strjoin([newValue,tokens[1:ntokens-1]],'*',/single)
                                fontRef->setProperty, name=newValue
                                case atomUval.datInd of
                                    0: void = atomUval.objRef->set(xFontVal=newValue) ; x-axis
                                    1: void = atomUval.objRef->set(yFontVal=newValue) ; y-axis
                                    else:
                                endcase
                            endif
                        end
                        'LABEL': begin
                             objArr[nObj]->getProperty, font=fontRef, uvalue=atomUval
                             datInd = atomUval.datInd
                             daveGrRef = atomUval.objRef
                             fontRef->GetProperty, name=curValue
                             tokens = strtok(curValue,'*',/extract) ; are there font modifiers present?
                             ntokens = n_elements(tokens)
                             if (ntokens gt 1) then $ ; include current font modifiers
                               newValue = strjoin([newValue,tokens[1:ntokens-1]],'*',/single)
                             fontRef->setProperty, name=newValue
                             case datInd of
                                 -1: begin ; title
                                     if (not daveGrRef->get(title=title)) then return
                                     title.font = newValue
                                     if (not daveGrRef->set(title=title)) then return
                                 end
                                 else: begin ; misc label
                                     if (not daveGrRef->get(label=label)) then return
                                     label[datInd].font = newValue
                                     if (not daveGrRef->set(label=label)) then return
                                 end
                             endcase
                        end
                    endcase
                    self->noRenew
                endif
            endwhile
        endif 
        break
    end

    'PRECISION': begin
        validAtomNames = ['AXIS'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    objArr[nObj]->getProperty, uvalue=atomUval, range=curRange
                    objArr[nObj]->SetProperty, tickformat=getFormatCode(curRange[0],curRange[1],newValue)
                    case atomUval.datInd of
                        0: begin ; x-axis
                            void = atomUval.objRef->get(xMiscAttrib=miscAttribs)
                            miscAttribs.decimalPlaces = newValue
                            void = atomUval.objRef->set(xMiscAttrib=miscAttribs) 
                        end
                        1: begin ; y-axis
                            void = atomUval.objRef->get(yMiscAttrib=miscAttribs)
                            miscAttribs.decimalPlaces = newValue
                            void = atomUval.objRef->set(yMiscAttrib=miscAttribs) 
                        end
                        else:
                    endcase
                    self->noRenew
                endif
            endwhile
        endif 
        break
    end

    'TICKDIR': begin
        validAtomNames = ['AXIS'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    objArr[nObj]->getProperty, uvalue=atomUval
                    objArr[nObj]->setProperty, tickDir=newValue
                    case atomUval.datInd of
                        0: begin ; x-axis
                            void = atomUval.objRef->get(xMiscAttrib=miscAttribs)
                            miscAttribs.tickDir = newValue
                            void = atomUval.objRef->set(xMiscAttrib=miscAttribs) 
                        end
                        1: begin ; y-axis
                            void = atomUval.objRef->get(yMiscAttrib=miscAttribs)
                            miscAttribs.tickDir = newValue
                            void = atomUval.objRef->set(yMiscAttrib=miscAttribs) 
                        end
                        else:
                    endcase
                    self->noRenew
                endif
            endwhile
        endif 
        break
    end

    'MINOR': begin
        validAtomNames = ['AXIS'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    objArr[nObj]->getProperty, uvalue=atomUval
                    objArr[nObj]->setProperty, minor=newValue
                    case atomUval.datInd of
                        0: begin ; x-axis
                            void = atomUval.objRef->get(xMiscAttrib=miscAttribs)
                            miscAttribs.minorTicks = newValue
                            void = atomUval.objRef->set(xMiscAttrib=miscAttribs) 
                        end
                        1: begin ; y-axis
                            void = atomUval.objRef->get(yMiscAttrib=miscAttribs)
                            miscAttribs.minorTicks = newValue
                            void = atomUval.objRef->set(yMiscAttrib=miscAttribs) 
                        end
                        else:
                    endcase
                    self->noRenew
                endif
            endwhile
        endif 
        break
    end

    'FONTSZ': begin
        validAtomNames = ['AXIS','LABEL'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    case atomName of
                        'AXIS': begin
                            objArr[nObj]->getProperty, title=titleRef, uvalue=atomUval, ticktext=ttRef
                            datInd = atomUval.datInd
                            case datInd of
                                0: kw_val = {xFontSize:newValue} ; x-axis
                                1: kw_val = {yFontSize:newValue} ; y-axis
                                else: kw_val = {dummy:0}
                            endcase
                            if (obj_valid(titleRef)) then begin
                                titleRef->getProperty, font=fontRef
                                fontRef->setProperty, size=newValue
                                ;ttRef->setProperty, size=newValue
                                daveGrRef = atomUval.objRef
                                if (not daveGrRef->set(_EXTRA=kw_val)) then return
                            endif
                        end
                        'LABEL': begin
                            objArr[nObj]->getProperty, font=fontRef, uvalue=atomUval
                            datInd = atomUval.datInd
                            daveGrRef = atomUval.objRef
                            fontRef->setProperty, size=newValue
                            case datInd of
                                -1: begin ; title
                                    if (not daveGrRef->get(title=title)) then return
                                    title.fontsize = newValue
                                    if (not daveGrRef->set(title=title)) then return
                                end
                                else: begin ; misc label
                                    if (not daveGrRef->get(label=label)) then return
                                    label[datInd].fontsize = newValue
                                    if (not daveGrRef->set(label=label)) then return
                                end
                            endcase
                        end
                    endcase
                    self->noRenew
                endif
            endwhile
        endif
        break
    end

    'EDITLABLE' : begin
        validAtomNames = ['LABEL'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    objArr[nObj]->getProperty, uvalue=atomUval
                    daveGrRef = atomUval.objRef
                    datInd = atomUval.datInd
                    DB_TxtLabel, datInd,objArr[nObj],daveGrRef,self,group_leader=event.top
                    self->noRenew
                endif
            endwhile
        endif
        break
    end

    'REMOVELABEL' : begin
        validAtomNames = ['LABEL'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    objArr[nObj]->getProperty, uvalue=atomUval
                    daveGrRef = atomUval.objRef
                    datInd = atomUval.datInd

                    if (~daveGrRef->get(label=labelArray,nlabel=nLabel)) then return
                    if (datInd eq -1) then begin
                        message = 'Cannot delete the main title!'
                        message = [message,"Uncheck the 'Display Title' option instead"]
                        void = dialog_message(message,dialog_parent=event.top)
                        return
                    endif
                    if ((datInd lt 0) || (datInd ge nlabel)) then return ; shouldn't happen but check anyway
                    if (datInd eq nLabel - 1) then begin
                        ;; Removing the last valid entry, simply
                        ;; decreement the nos of labels by 1
                        if (~daveGrRef->set(nlabel=nLabel-1)) then return
                    endif else begin
                        ;; Overwrite the entry to be removed by shifting
                        ;; valid ones down by an index
                        ind2Bmoved = indgen(nlabel-1-datind) + (datind + 1)
                        labelArray[ind2Bmoved-1] = labelArray[ind2Bmoved]
                        if (~daveGrRef->set(label=labelArray[0:nLabel-2])) then return
                    endelse
                    self->Renew
                endif
            endwhile
        endif
        break
    end

    'EDITAXIS' : begin
        validAtomNames = ['AXIS'] ; ==> only atoms with name matching these will be affected
        objRefType = vartype(objRef) ; IDLgrModels will have multiple atoms
        if (objRefType eq 'IDLGRMODEL') then begin
            ;; loop through atoms in model and make changes
            objArr = objRef->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                objArr[nObj]->getProperty, name=atomName
                res = where(validAtomNames eq atomName,valid)
                if (valid) then begin
                    objArr[nObj]->getProperty, uvalue=atomUval, notext=emptyTitle
                    if (not emptyTitle) then begin
                        daveGrRef = atomUval.objRef
                        datInd = atomUval.datInd
                        ;datInd = (atomUval.datInd eq 0)? atomUval.datInd : 2 ; for 1D, zaxis == yaxis!!!
                        DB_AxisProp, datInd,objArr[nObj],daveGrRef,self,group_leader=event.top
                        self->noRenew
                    endif
                endif
            endwhile
        endif
        break
    end

    else: begin
        break
    end

endswitch

self->refresh      ;db_dispData, sPtr

return

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::DispConSenMenu
;
; PURPOSE:
;   Display context-sentive dialog menus when requested
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::DispConSenMenu, event

objArr = (self.oScene)->get(/all, count=nObj) ; get nos of objects in scene
while (nObj gt 0) do begin      ; loop through and
    nObj = nObj - 1
    if (vartype(objArr[nObj]) ne 'IDLGRVIEW') then continue
    oView = objArr[nObj]
    dims = [10,10]
    compArr = (self.oDest)->Select(oView,[event.x, event.y],dimensions = dims) ; grab model/atoms in view at mouse loc
    if (obj_valid(compArr[0]) ne 1) then continue
    count = n_elements(compArr)
    missionNotAccomplished = 1  ; don't want to display MORE THAN ONE CSM
    while ((count gt 0) && (missionNotAccomplished)) do begin
        count = count - 1
        ;; Analyse components
        (compArr[count])->getProperty, name=name
        self.csmObjRef = compArr[count]
        case name of
            'IMAGEMODEL': begin
                csm = widget_info(event.top,find_by_uname='CSBIMAGE')
                widget_displaycontextmenu, event.id, event.x, event.y, csm
                missionNotAccomplished = 0
            end
            'LABMODEL': begin
                csm = widget_info(event.top,find_by_uname='CSBTITLE')
                widget_displaycontextmenu, event.id, event.x, event.y, csm
                missionNotAccomplished = 0
            end
            'AMODEL': begin
                csm = widget_info(event.top,find_by_uname='CSBAXES')
                widget_displaycontextmenu, event.id, event.x, event.y, csm
                missionNotAccomplished = 0
            end
            'COLORBAR':

            else:
        endcase
    endwhile
endwhile


end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::Print
;
; PURPOSE:
;   Print current graphics window to printer or export it to various
;   image formats + postscript.
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::Print, event, _EXTRA=etc
uname = widget_info(event.id,/uname)

switch uname of
    'TIFF':
    'BMP':
    'PNG':
    'JPEG': begin
        ;; force a window refresh before capturing image
        self.renewScene = 0
        self->refresh
        ;; capture destination window contents
        oImage = (self.oDest)->read()
        ;oImage->setProperty, order=1b
        oImage->getProperty, data=image, order=order
        obj_destroy, oImage
        title = 'DATABROWSER - Export '+uname+' Image'
        defFile = 'output2d.'+strlowcase(uname)
        if (uname eq 'TIFF') then image = reverse(image,3,/overwrite) ; top-to-bottom -> bottom-to-top
        result = dialog_write_image(image,dialog_parent=event.top,path=self.workDir, $
                                    title=title,/warn_exist,type=uname,file=defFile)
        break
    end
    'POST': begin
        defFile = 'output2d.ps'
        title = 'DATABROWSER - Export Postscript'
        oPSC = obj_new("FSC_PSCONFIG",directory=self.workDir,filename=defFile)
        options = PSConfig(oPSC,cancel=cancelled,group_leader=event.top)
        if (not cancelled) then begin
            if (options.landscape eq 1) then begin
                yoff = options.xoffset
                xoff = options.yoffset - options.xsize
            endif else begin
                xoff = options.xoffset
                yoff = options.yoffset
            endelse
            pageDimensions = oPSC->pagedimensions()
            units = (options.inches eq 1)? 1 : 2

            ;; Create a clipboard
            oClip = obj_new('IDLgrClipboard',units=units,dimensions=pageDimensions)


            ;; Get the scene/view that is being displayed.
            oView = (self.oScene)->get(/all,isa='IDLgrView')
            ;oImage = (self.oScene)->get(/all,isa='IDLgrImage')
            ;oImage = oView->getByName('DG2DMODEL/IMAGEMODEL/IMAGE')
            oView->getProperty, location=winLoc,dimensions=winDim,units=winUnits
            ;oImage->getProperty, location=iwinLoc,dimensions=iwinDim
            oView->setProperty, units=units, $
                                dimensions=[options.xsize,options.ysize];, $
                                ;location=[xoff,yoff]

            ;oImage->setProperty, location=[xoff,yoff]


            ;; Render the scene to the clipboard
            oClip->draw, self.oScene, file=options.filename,/postscript,/vector

            ;; Cleapup and revert view to previous settings
            obj_destroy, [oClip,oPSC]
            oView->setProperty, location=winLoc,dimensions=winDim,units=winUnits
            ;oImage->setProperty, location=iwinLoc
        endif

        break
    end
    'PRINT': begin
        oPrint = obj_new('IDLgrPrinter')
        title = 'DATABROWSER - Printer Setup'
        valid = dialog_printersetup(oPrint,dialog_parent=event.top,title=title)
        if (valid) then begin
            oPrint->draw, (self.oScene)
            oPrint->newDocument ; forces current document to be sent to printer
        endif
        obj_destroy, oPrint
        break
    end
endswitch


end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::DrawEvent
;
; PURPOSE:
;   Handle events from the graphics window
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::DrawEvent, event

uname = widget_info(event.id,/uname)

possibleEventTypes = ['DOWN','UP','MOTION','SCROLL','EXPOSE']
eventType = possibleEventTypes[event.type]

case eventType of
    'DOWN': begin               ; Button press event
        self.renewScene = 0     ; ==> don't re-construct Scene
        if (event.press eq 4) then self->dispConSenMenu, event ; Right Mouse button was pressed; display Con Sen Menu
        if (event.press eq 1) then begin ;Left mouse button was pressed; zoomin functionality is required

            self.rbStart = [event.x,event.y] ; register the mouse location
            widget_control, event.id, draw_motion_events=1 ; switch on motion events
            ;self.LMBisDown = 1  ; LMB is down

            ;; get properties of view which contains current plot
            objArr = (self.oScene)->get(/all, count=nObj)
            while (nObj gt 0) do begin
                nObj = nObj - 1
                if (vartype(objArr[nObj]) ne 'IDLGRVIEW') then continue
                (self.oDest)->getProperty, dimensions = winDims ; dimensions of destination window
                (objArr[nObj])->getProperty, all=allViewProps ; properties of view gr object
                ;; create a rubberband obj gr atom
                rbandColor = [255,0,0];255 - allViewProps.color ; set rub band color to reverse of view color
                vprect = allViewProps.viewplane_rect ; dimensions of viewplane
                vprect[2] = vprect[2]/float(winDims[0])
                vprect[3] = vprect[3]/float(winDims[1])
                self.rbScale = vprect
                rbandModel = obj_new('IDLgrModel',name='RBANDMODEL')
                self.oRband = obj_new('IDLgrPolyline',name='RBAND',color=rbandColor)
                (objArr[nObj])->add, rbandModel
                rbandModel->add, self.oRband
                nObj = 0
            endwhile
        endif
    end
    'UP': begin                 ; Button release event
        if (event.release eq 1) then begin ; Left mouse button released
            ;; cleanup rubberband obj gr model and atom
            if (obj_valid(self.oRband)) then begin
                (self.oRband)->getProperty, parent=rbandModel
                rbandModel->getProperty, parent=oView
                oView->remove, rbandModel
                obj_destroy, rbandModel ; should destroy rub band atom as well
            endif

            widget_control, event.id, draw_motion_events=0 ; switch off motion events
            widget_Control, event.id, /clear_events ; clear any motion events that may have occurred.
            ;self.LMBisDown = 0

            if (not self.mouseMoved) then break ; Exit now if releasing from same spot that mouse was pressed

            ;; rubberband box is new zoom region
            self.xrangeFlag = 1
            xmin = self.rbStart[0]*self.rbScale[2] + self.rbScale[0]
            xmax = event.x*self.rbScale[2] + self.rbScale[0]
            self.xrange = (xmax gt xmin)? [xmin,xmax] : [xmax,xmin]
            self.yrangeFlag = 1
            ymin = self.rbStart[1]*self.rbScale[3] + self.rbScale[1]
            ymax = event.y*self.rbScale[3] + self.rbScale[1]
            self.yrange = (ymax gt ymin)? [ymin,ymax] : [ymax,ymin]

            ;self.renewScene = 0 ; ==> don't re-construct Scene
            self->refresh ; refresh plot scene via self

        endif
    end
    'MOTION': begin             ; Motion event
        self.mouseMoved = 1     ; register mouse move

        ;; determine rubber band box dimensions and modify the rub
        ;; band obj gr atom
        start = self.rbStart
        boxVertices = fltarr(2,5)
        boxVertices[0,*] = [start[0],event.x,event.x,start[0],start[0]]*self.rbScale[2] + self.rbScale[0]
        boxVertices[1,*] = [start[1],start[1],event.y,event.y,start[1]]*self.rbScale[3] + self.rbScale[1]
        (self.oRband)->setProperty, data=boxVertices

        ;(self.oRband)->getProperty, parent=rbandModel
        ;rbandModel->getProperty, parent=rbandView
        self.renewScene = 0     ; ==> don't re-construct Scene
        self->refresh ; refresh plot scene via self
        ;(self.oDest)->draw, rbandView ; draw rubber band
    end
    'SCROLL':
    'EXPOSE': begin             ; Expose event, so repaint window
        ;print,'Exposed Event generated...'
        self.renewScene = 0     ; ==> don't re-construct Scene
        self->refresh ; refresh via self
    end
endcase

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::DefXYLimEvent
;
; PURPOSE:
;   Reset x and y axes limits to their default values (these are
;   detrmined by the data).
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::DefXYLimEvent, event

self.xrangeFlag = 0
self.yrangeFlag = 0

self->refresh      ; refresh via self

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::DefZLimEvent
;
; PURPOSE:
;   Reset z axis limits to their default values (these are
;   detrmined by the data).
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::DefZLimEvent, event

self.zrangeFlag = 0

if (not (self.oDaveGr)->get(zmin=zmin,zmax=zmax,zMiscAttribs=zMiscAttribs)) then return

; using log scale so can't have -ve ranges
if (zMiscAttribs.logFlag and (zmin le 0.0 )) then begin
    self.zrangeFlag = 1
    zmin = 0.00001*(zmax - zmin) ; set something sensible
endif

self.zrange=[zmin,zmax]
wid = widget_info(event.top, find_by_uname='ZMIN')
widget_control, wid, set_value=zmin
wid = widget_info(event.top, find_by_uname='ZMAX')
widget_control, wid, set_value=zmax

self->refresh      ; refresh via self

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::ToggleZlog
;
; PURPOSE:
;   Toggle between linear/log scaling for intensity
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::ToggleZLog, event

if (not (self.oDaveGr)->get(zmin=zmin,zmax=zmax,zMiscAttribs=zMiscAttribs)) then return
if (~zMiscAttribs.logFlag)  then begin
    ;; make sure zrange is all +ve
    if (self.zrange[1] le 0.0) then begin
        message = 'Cannot set log scale for negative intensity'
        res = dialog_message(message,dialog_parent=event.top)
        return
    endif
    if (self.zrange[0] le 0.0 ) then begin  
        self.zrange[0] = 0.00001*(zmax - zmin) ; then set zmin to a sensible +ve value
        self.zrangeFlag = 1
        wid = widget_info(event.top,find_by_uname='ZMIN')
        widget_control, wid, set_value=self.zrange[0]
    endif
endif

zMiscAttribs.logFlag = 1 - zMiscAttribs.logFlag
if (not (self.oDaveGr)->set(zMiscAttribs=zMiscAttribs)) then return

self->refresh                   ; refresh via self

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::SetZrange
;
; PURPOSE:
;   Set minimum/maximum limits of data to be displayed
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::SetZrange, event

uname = widget_info(event.id,/uname)
wid = widget_info(event.top, find_by_uname='ZLOG')
widget_control, wid, get_value=zlogflag

case uname of
    'ZMIN': begin
        if (event.value lt self.zrange[1]) then begin
            if (zlogflag[0] and (event.value le 0.0)) then begin
                message = 'Zero or negative values are not allowed when using log scale is on'
                void = dialog_message(message,dialog_parent=event.top)
                widget_control, event.id, set_value=self.zrange[0]
                return
            endif
            self.zrange[0] = event.value
            self.zrangeFlag = 1
        endif else widget_control, event.id, set_value=self.zrange[0]
    end
    'ZMAX': begin
        if (zlogflag[0] and (event.value le 0.0)) then begin
            message = 'Zero or negative values are not allowed when using log scale is on'
            void = dialog_message(message,dialog_parent=event.top)
            widget_control, event.id, set_value=self.zrange[1]
            return
        endif
        if (event.value gt self.zrange[0]) then begin
            self.zrange[1] = event.value
            self.zrangeFlag = 1
        endif else widget_control, event.id, set_value=self.zrange[1]
    end
endcase

self->refresh      ; refresh via self

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::AddText
;
; PURPOSE:
;   Add text annotation to the plot
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::AddText, event, _EXTRA=etc

; Retrieve required objects from the IDL object graphics heirarchy
oView = (self.oScene)->get(/all,isa='IDLgrView')
oMiscCont = (self.oScene)->get(isa='IDL_Container')
oModel = oView->getByName('DG2DMODEL')

; Get the viewplane rectangle
oView->getProperty, viewplane_rect=vprect

; Get nos of existing labels
if (not (self.oDaveGr)->get(nlabel=nlabel,label=labelArray)) then return

; New Label
newLabel = {annotate}
newLabel.text = 'New text'
newLabel.position = [0.05,0.05,0.0]
newLabel.alignment = 0.5
newLabel.color = [0,0,0]
newLabel.font = 'HELVETICA'
newLabel.fontsize = 10

; Create graphic atom using label
oLabelModel = obj_new('IDLgrModel',name='LABMODEL',/select_target) ; make it selectable
oModel->add, oLabelModel
xs = scale_coord([0,1],[vprect[0],vprect[0]+vprect[2]])
ys = scale_coord([0,1],[vprect[1],vprect[1]+vprect[3]])
oLabelFont = obj_new('IDLgrFont',name=newLabel.font,size=newLabel.fontsize)
oMiscCont->add,oLabelFont       ; so it can be properly cleaned up
oLabel = obj_new('IDLgrText',newLabel.text,name='LABEL',font=oLabelFont,/enable_formatting $
                 ,location=newLabel.position,alignment=newLabel.alignment,color=newLabel.color $
                 ,xcoord_conv=xs,ycoord_conv=ys,uvalue={objRef:(self.oDaveGr),datInd:nlabel})
oLabelModel->add,oLabel

; Add the new label to the DaveGr object
labelArray = (nlabel gt 0)? [labelArray,newLabel] : newLabel
void = (self.oDaveGr)->set(label=labelArray)

; Refresh display
self->noRenew
self->refresh

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::TlbEvent
;
; PURPOSE:
;   Handle TLB events (mainly resize events)
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::TlbEvent, event
if dave_set_focus(event) then return
res = widget_info(event.top,/geometry)
new_x = event.x - self.dialog_x - 2*res.xpad
new_y = event.y - 2*res.ypad
new_x = new_x > self.min_draw_x
new_y = new_y > self.min_draw_y
(self.oDest)->setProperty, dimensions=[new_x,new_y]
(self.oDest)->getProperty, dimensions=dim
self.winDim = dim

self->noRenew

self->refresh      ; refresh via self

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::DispTitleEvent
;
; PURPOSE:
;   Toggle display of main title on/off
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::DispTitleEvent, event

self.dispTitle = 1 - self.dispTitle ; swap setting (0 <--> 1)

self->refresh

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::CbarLabelEvent
;
; PURPOSE:
;   Toggle colorbar annotation on/off
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::CbarLabelEvent, event

self.cbarLabel = 1 - self.cbarLabel ; swap setting (0 <--> 1)

self->refresh

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::NormAspectEvent
;
; PURPOSE:
;   Toggle normalized aspect ratio on/off. When it is on, both the x
;   and y axes will use the same resolution (data units/pixel)
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::NormAspectEvent, event

self.normAspect = 1 - self.normAspect ; swap setting (0 <--> 1)

self->refresh

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::ExitEvent
;
; PURPOSE:
;   Exit application
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::ExitEvent, event

widget_control,event.top,/destroy

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::Displayevent
;
; PURPOSE:
;   Refresh graphics window
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::DisplayEvent, event

self->refresh      ; refresh via self

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::NoRenew
;
; PURPOSE:
;   Switch off reconstruction of entire object graphic scene
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::NoRenew, event

self.renewScene = 0

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::Renew
;
; PURPOSE:
;   Switch on reconstruction of entire object graphic scene
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI::Renew, event

self.renewScene = 1

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::GetTLB
;
; PURPOSE:
;   Get the top level base id.
;
; PARAMETERS
;
; KEYWORDS:
;
; RETURN VALUE:
;   the tlb
;
function DB_Display2DI::GetTLB

return, self.TLB

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI_Event
;
; PURPOSE:
;   Main conventional event handler for all events originating from
;   the main UI of the application.
;
; PARAMETERS
;   event [in;req] - the event structure
;
; KEYWORDS:
;
pro DB_Display2DI_Event, event

; Basic error Handler
if (n_elements(!debug) && (!debug eq 0)) then begin
    catch, catchError
    if (catchError ne 0) then begin
        ;;print, 'Error handled!'
        eTitle = 'Error encountered'
        eMsg = 'An error or unusual condition was encountered!'
        eMsg = [eMsg,'Please, report the following to the DAVE team:']
        eMsg = [eMsg,!error_state.msg]
;    eMsg = [eMsg,'Function/module name: calledfunc()',!error_state.msg]
        void = dialog_message(/error,eMsg,title=eTitle,dialog_parent=event.top)
        catch, /cancel
        return
    endif
endif

; Retrieve the command structure embedded in the uvalue of the
; widget. The command structure is stored in the uvalue of either
; event.id or evend.handler
widget_control, event.id, get_uvalue = cmd

childID = event.id
while (vartype(cmd) ne 'DB_DISPLAY2D_CMD') do begin
    parentID = widget_info(childID,/parent)
    if (parentID eq 0) then break
    widget_control, parentID, get_uvalue = cmd
    childID = parentID
endwhile


if (vartype(cmd) eq 'DB_DISPLAY2D_CMD') then $
   call_method, cmd.method, cmd.object, event

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI_Cleanup
;
; PURPOSE:
;   Conventional cleanup procedure called when the tlb for this application is
;   destroyed.
;
; PARAMETERS
;   tlb [in;req] - the widget id that is to be destroyed
;
; KEYWORDS:
;
pro DB_Display2DI_Cleanup, tlb
widget_control, tlb, get_uvalue = cmd
; get the Widget Object's reference and destroy it
selfObject = cmd.object
obj_destroy, selfObject

end
;-------------------------------------------------------------------------------



;===============================================================================
; DB_Display2DI::Init
;
; PURPOSE:
;   Object initialization method. Builds the main dialog.
;
; PARAMETERS
;
; KEYWORDS:
;   group_leader [in] - the ID of the parent widget from which this
;                       app was launched.
;
;   objRef [in;req] - the DaveGr1D object reference(s) to be
;                     displayed.
;
;   workDir [in] - user's working directory setting from DAVE
;
; RETURN VALUE
;   1 - if sucessful
;   0 - failure
;
function DB_Display2DI::Init, group_leader=group_leader, objGrRef=oDaveGr, workDir=workDir

if ((n_elements(oDaveGr) gt 0) && obj_valid(oDaveGr)) then begin
   void = oDaveGr->get(dataRef=dataRef)
   ;; get the x,y and  z-axis data
   if (not dataRef->get(xval=xval,yval=yval,xtype=xtype,ytype=ytype)) then return, 0

   ;; Can't properly use image to visualize data that is not evenly spaced in x
   len = n_elements(xval)
   index = lindgen(len-1)
   diff = xval[index+1] - xval[index]
   unit = (diff[0] ne 0.0)? diff/diff[0] : diff ; normalize to unity
   unit = float(string(unit,format='(G10.3)')) ; up to 3 dec place precision
   void = where(unit ne 1.00, xBinNotUniform)
   if (xBinNotUniform gt 0) then begin
      msg = 'X-axis data does not contain evenly spaced bins'
      msg = [msg,'Cannot properly represented it with an image plot!']
      msg = [msg,'Please, use contour/surface plot or rebin the data in x first']
      void = dialog_message(dialog_parent=group_leader, msg, /info)
      return, 0
   endif

   ;; Can't properly use image to visualize data that is not evenly spaced in y
   len = n_elements(yval)
   index = lindgen(len-1)
   diff = yval[index+1] - yval[index]
   unit = (diff[0] ne 0.0)? diff/diff[0] : diff ; normalize to unity
   unit = float(string(unit,format='(G10.3)')) ; up to 3 dec place precision
   void = where(unit ne 1.00, yBinNotUniform)
   if (yBinNotUniform gt 0) then begin
      msg = 'Y-axis data does not contain evenly spaced bins'
      msg = [msg,'Cannot properly represented it with an image plot!']
      msg = [msg,'Please, use contour/surface plot or rebin the data in y first']
      void = dialog_message(dialog_parent=group_leader, msg, /info)
      return, 0
   endif
endif


;
device, get_decomposed = old_dec
self.old_dec = old_dec
;device, decomposed=0

; create a structure to specify methods that should act as event
; handlers for widgets defined in DB_Display2DI
cmdStr = {DB_DISPLAY2D_CMD, $
          object:self, $ ; reference to the widget object generating events
          method:'' $         ; the method that should handle the event
         }



; Various tooltips
deTooltip = 'Togle on/off errorbars.'
pmTooltip = 'Switch plot mode. View data as points or histograms.'
refTooltip = 'Refresh the plot window'
defZTooltip = 'Reset intensity range to default values from data.'
defXYTooltip = 'Reset x,y-axis display limits to full range.'
exitTooltip = 'Close display window. Activate by R-clicking on plot item from main window'
ptTooltip = 'Set/modify plot type (as lines and/or symbols).'
lsTooltip = 'Set/modify plot linestyle.'
pthTooltip = 'Set/modify plot line thickness.'
symTooltip = 'Set/modify plot symbols.'
stTooltip = 'Set/modify symbol type.'
szTooltip = 'Set/modify symbol size.'
pcolTooltip = 'Set/modify plot color.'
acolTooltip = 'Set/modify axes color.'
atTooltip = 'Set/modify axis line thickness.'
addTextTip = "Add 'New Text' label to plot. Then right-click on it to edit/position!"


; define the top-level-base
cmdStr.method = 'tlbEvent'
if (n_elements(group_leader) eq 0) then begin
    group_leader=0L
    modal=0
    self.dispType = 0b
    self.tlb = widget_base(/row,title=title,/align_right,/tlb_size_events,uname='TLB' $
                           ,uvalue=cmdStr,group_leader=group_leader,mbar=menubar)
endif else begin
    modal=1
    widget_control, group_leader, get_uvalue=sPtr

    ;; Get the DaveGr object to be viewed
    if (n_elements(oDaveGr) gt 0) then begin
        self.oDaveGr = oDaveGr
    endif else begin
        oSelCont = (*sPtr).sel_cont
        self.oDaveGr = oSelCont->get(position=0)
    endelse

    ;; Can't allow multiple views of the same DaveGr2D object so make
    ;; some checks now
    self.oActive2DCont = (*sPtr).o_active_gr2DI_cont
    if ((self.oActive2DCont)->count() gt 0) then begin
        ;; Exit immediately if DaveGr object is already being viewed
        if ((self.oActive2DCont)->isContained(self.oDaveGr)) then return, 0
    endif
    ;; register DaveGr object
    (self.oActive2DCont)->add, self.oDaveGr

    ; Retrieve ptr to previous GUI/widget settings
    ;if (not (self.oDaveGr)->get(zmin=zmin,zmax=zmax,zMiscAttribs=zMiscAttribs)) then return, 0
    if (not (self.oDaveGr)->get(guiAttribsPtr=guiAttribsPtr,zmin=zmin,zmax=zmax,zMiscAttribs=zMiscAttribs)) then return, 0
    usingPrevGuiSettings = (n_elements(*guiAttribsPtr) gt 0)? 1b : 0b
    if (usingPrevGuiSettings) then begin
        self.xrangeFlag = (*guiAttribsPtr).xrangeFlag
        self.yrangeFlag = (*guiAttribsPtr).yrangeFlag
        self.zrangeFlag = (*guiAttribsPtr).zrangeFlag
        self.xrange = (*guiAttribsPtr).xrange
        self.yrange = (*guiAttribsPtr).yrange
        case self.zrangeFlag of
            0: self.zrange = [zmin,zmax]
            1: self.zrange = (*guiAttribsPtr).zrange
        endcase
    endif else self.zrange = [zmin,zmax]

    void = (self.oDaveGr)->get(nameTag=title)
    title = 'DATABROWSER - '+title
    self.o_registry = (*sPtr).o_registry ; get the object registry
    (self.o_registry)->add, self    ; and register
    ;self.tlb = widget_base(group_leader=group_leader,/row,title=title,modal=modal $
    ;                 ,/align_right,/tlb_size_events,uname='TLB',uvalue=cmdStr)
    self.tlb = widget_base(group_leader=group_leader,/row,title=title $
                     ,/align_right,/tlb_size_events,uname='TLB',uvalue=cmdStr,mbar=menubar)
endelse


; Get working directory setting
if (n_elements(workDir) le 0) then $
  cd, current=workDir
self.workDir = workDir

; File Menu
filem = widget_button(menubar,value='File',/menu)
cmdStr.method='print'
expm = widget_button(filem,value='Export image as',/menu)
void = widget_button(expm,value='Postscript',uname='POST',uvalue=cmdStr)
void = widget_button(expm,value='Jpeg',uname='JPEG',uvalue=cmdStr,/separator)
void = widget_button(expm,value='Png',uname='PNG',uvalue=cmdStr)
void = widget_button(expm,value='Bmp',uname='BMP',uvalue=cmdStr)
void = widget_button(expm,value='Tiff',uname='TIFF',uvalue=cmdStr)
void = widget_button(filem,value='Print',uname='PRINT',uvalue=cmdStr)
cmdStr.method = 'exitEvent'
void = widget_button(filem,value='Hide Window',/separator,uname='EXIT',uvalue=cmdStr)

; split TLB into:
;  1) an left pane for placing dialog buttons
;  2) a right pane for placing the draw window
cb1 = widget_base(self.tlb,/col)
cb2 = widget_base(self.tlb,/frame)

; Split the dialog base into several sections for grouping similar controls
cb11 = widget_base(cb1,/col,/align_center,/frame)
cb11a = widget_base(cb1,/col,/align_center,/frame)
cb12 = widget_base(cb1,/col,/align_center,/frame)
;cb13 = widget_base(cb1,/col,/align_center,/frame)
cb14 = widget_base(cb1,/col,/align_center)

xsize = 130

self.dispTitle = (usingPrevGuiSettings)? (*guiAttribsPtr).dispTitle : 1
cmdStr.method = 'dispTitleEvent'
void = cw_bgroup(cb11,['Display Title'],/col,/nonexclusive,frame=0,/return_index,uname='DISPTITLE' $
                 ,set_value=self.dispTitle,uvalue=cmdStr)

self.cbarLabel = (usingPrevGuiSettings)? (*guiAttribsPtr).cbarLabel : 1
cmdStr.method = 'cbarLabelEvent'
void = cw_bgroup(cb11,['Annotate Colorbar'],/col,/nonexclusive,frame=0,/return_index,uname='CBARLABEL' $
                 ,set_value=self.cbarLabel,uvalue=cmdStr)

self.normAspect = (usingPrevGuiSettings)? (*guiAttribsPtr).normAspect : 0
cmdStr.method = 'normAspectEvent'
void = cw_bgroup(cb11,['Normalized Aspect'],/col,/nonexclusive,frame=0,/return_index,uname='NORMASPECT' $
                 ,set_value=self.normAspect,uvalue=cmdStr)

cmdStr.method = 'todoEvent'
void = widget_button(cb11,value='Edit X-axis',uname='EXAXIS',xsize=xsize,uvalue=cmdStr,sensitive=0)
void = widget_button(cb11,value='Edit Y-axis',uname='EYAXIS',uvalue=cmdstr,sensitive=0)
void = widget_button(cb11,value='Edit Title',uname='ETITLE',uvalue=cmdStr,sensitive=0)

cmdStr.method = 'addText'
void = widget_button(cb11,value='Add Text',uname='ADDTEXT',uvalue=cmdStr,tooltip=addTextTip)

; Data limits
void = widget_label(cb11a,value='Intensity Range',xsize=xsize)
;void = widget_label(cb11a,value='Range',xsize=xsize)
cmdStr.method = 'setZrange'
void = cw_field(cb11a,title='',/row,value=self.zrange[0],/float,uname='ZMIN' $
                ,/return_events,xsize=12,uvalue=cmdStr)
void = cw_field(cb11a,title='',/row,value=self.zrange[1],/float,uname='ZMAX' $
                ,/return_events,xsize=12,uvalue=cmdStr)

cmdStr.method = 'toggleZLog'
void = cw_bgroup(cb11a,['Log Scale'],/col,/nonexclusive,frame=0,/return_index,uname='ZLOG' $
                 ,set_value=zMiscAttribs.logflag,uvalue=cmdStr)

cmdStr.method = 'defZLimEvent'
void = widget_button(cb11a,value='Default Range',uname='DEFZLIM',xsize=xsize,uvalue=cmdStr,tooltip=defZTooltip)

cmdStr.method = 'displayEvent'
void = widget_button(cb12,value='Refresh',uname='DISPLAY',xsize=xsize,uvalue=cmdStr,tooltip=refTooltip)
cmdStr.method = 'defXYLimEvent'
void = widget_button(cb12,value='Reset Axes Limits',uname='DEFXYLIM',xsize=xsize,uvalue=cmdStr,tooltip=defXYTooltip)
cmdStr.method = 'exitEvent'
void = widget_button(cb12,value='Hide Window',uname='EXIT',uvalue=cmdstr,tooltip=exitTooltip)

; store useful widget dimensions in self (widget object)
res = widget_info(cb1,/geometry)
self.dialog_x = res.xsize
dialog_y = res.ysize
self.min_draw_y = fix(dialog_y*1.05)
self.min_draw_x = fix(self.min_draw_y*1.333)
self.winDim = (usingPrevGuiSettings)? (*guiAttribsPtr).winDim : $
              [self.min_draw_x > 600,self.min_draw_y > 450]
cmdStr.method = 'drawEvent'
drawID = widget_draw(cb2,xsize=self.winDim[0],ysize=self.winDim[1],graphics_level=2,uname='DRAW' $
                     ,/button_events,/expose_events,uvalue=cmdStr)

;----------------------------------------------------------------------------
; Create Context Sensitive menus for Contour object.
cmdStr.method = 'handleConSenMenuEvent'
csb1 = widget_base(self.tlb, /context_menu,uname='CSBIMAGE',uvalue=cmdStr)
fill = widget_button(csb1,value='Interpolation',/menu,tooltip=interpTip)
color = widget_button(csb1,value='Color Table',/menu,tooltip=colorTip)

; Get various DaveGr object settings
void = (self.oDaveGr)->get(interpFlag=interpFlag,colorIndex=colorIndex)

; Interpolation
self.interpIDs[0] = widget_button(fill,value='Nearest Neigbour',uname='INTERP',uvalue=0,/checked_menu)
self.interpIDs[1] = widget_button(fill,value='Bilinear',uname='INTERP',uvalue=1,/checked_menu)
case interpFlag of
    0: widget_control, self.interpIDs[0], set_button=1
    1: widget_control, self.interpIDs[1], set_button=1
endcase

; Color Tables
ctable=['B-W LINEAR','BLUE/WHITE','GRN-RED-BLU-WHTt','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']
count=n_elements(ctable)
ctableIDs = lindgen(count)
for i=0,count-1 do begin
    ctableIDs[i] = widget_button(color,value=ctable[i],uname='CTABLE',uvalue=i,/checked_menu)
    if (i eq colorIndex) then widget_control, ctableIDs[i], set_button=1
endfor
self.ctableIDsPtr = ptr_new(ctableIDs)

;----------------------------------------------------------------------------
; Create Context Sensitive menus for 'Axes'
csb2 = widget_base(self.tlb, /context_menu,uname='CSBAXES',uvalue=cmdStr)
thick = widget_button(csb2,value='Line Thickness',/menu)
font = widget_button(csb2,value='Font',/menu)
sfont = widget_button(csb2,value='Font Size',/menu)
color = widget_button(csb2,value='Color',/menu)
prec =  widget_button(csb2,value='Decimal Places',/menu)
tdir =  widget_button(csb2,value='Tick Direction',/menu)
minor =  widget_button(csb2,value='Minor Ticks',/menu)
void = widget_button(csb2,value='Properties...',uname='EDITAXIS')

void = widget_button(font,value='HELVETICA',uname='FONT',uvalue='HELVETICA')
void = widget_button(font,value='COURIER',uname='FONT',uvalue='COURIER')
void = widget_button(font,value='TIMES',uname='FONT',uvalue='TIMES')
void = widget_button(font,value='HERSHEY',uname='FONT',uvalue='HERSHEY')
void = widget_button(font,value='SYMBOL',uname='FONT',uvalue='SYMBOL')

void = widget_button(prec,value='0',uname='PRECISION',uvalue=0)
void = widget_button(prec,value='1',uname='PRECISION',uvalue=1)
void = widget_button(prec,value='2',uname='PRECISION',uvalue=2)
void = widget_button(prec,value='3',uname='PRECISION',uvalue=3)
void = widget_button(prec,value='4',uname='PRECISION',uvalue=4)

void = widget_button(tdir,value='Inwards',uname='TICKDIR',uvalue=0)
void = widget_button(tdir,value='Outwards',uname='TICKDIR',uvalue=1)

void = widget_button(minor,value='1',uname='MINOR',uvalue=1)
void = widget_button(minor,value='2',uname='MINOR',uvalue=2)
void = widget_button(minor,value='3',uname='MINOR',uvalue=3)
void = widget_button(minor,value='4',uname='MINOR',uvalue=4)
void = widget_button(minor,value='5',uname='MINOR',uvalue=5)
void = widget_button(minor,value='6',uname='MINOR',uvalue=6)
void = widget_button(minor,value='7',uname='MINOR',uvalue=7)
void = widget_button(minor,value='8',uname='MINOR',uvalue=8)
void = widget_button(minor,value='9',uname='MINOR',uvalue=9)
void = widget_button(minor,value='10',uname='MINOR',uvalue=10)

void = widget_button(thick,value='1.00',uname='THICK',uvalue=1.00)
void = widget_button(thick,value='1.25',uname='THICK',uvalue=1.25)
void = widget_button(thick,value='1.50',uname='THICK',uvalue=1.50)
void = widget_button(thick,value='1.75',uname='THICK',uvalue=1.75)
void = widget_button(thick,value='2.00',uname='THICK',uvalue=2.00)
void = widget_button(thick,value='2.25',uname='THICK',uvalue=2.25)
void = widget_button(thick,value='2.50',uname='THICK',uvalue=2.50)
void = widget_button(thick,value='2.75',uname='THICK',uvalue=2.75)
void = widget_button(thick,value='3.00',uname='THICK',uvalue=3.00)
void = widget_button(thick,value='3.25',uname='THICK',uvalue=3.25)
void = widget_button(thick,value='3.50',uname='THICK',uvalue=3.50)
void = widget_button(thick,value='3.75',uname='THICK',uvalue=3.75)
void = widget_button(thick,value='4.00',uname='THICK',uvalue=4.00)
void = widget_button(thick,value='4.25',uname='THICK',uvalue=4.25)
void = widget_button(thick,value='4.50',uname='THICK',uvalue=4.50)
void = widget_button(thick,value='4.75',uname='THICK',uvalue=4.75)
void = widget_button(thick,value='5.00',uname='THICK',uvalue=5.00)

void = widget_button(color,value='Aqua',uname='COLOR',uvalue=[0,255,255])
void = widget_button(color,value='Black',uname='COLOR',uvalue=[0,0,0])
void = widget_button(color,value='Blue',uname='COLOR',uvalue=[0,0,255])
void = widget_button(color,value='Fuchsia',uname='COLOR',uvalue=[255,0,255])
void = widget_button(color,value='Gray',uname='COLOR',uvalue=[128,128,128])
void = widget_button(color,value='Green',uname='COLOR',uvalue=[0,128,0])
void = widget_button(color,value='Lime',uname='COLOR',uvalue=[0,255,0])
void = widget_button(color,value='Maroon',uname='COLOR',uvalue=[128,0,0])
void = widget_button(color,value='Navy',uname='COLOR',uvalue=[0,0,128])
void = widget_button(color,value='Olive',uname='COLOR',uvalue=[128,128,0])
void = widget_button(color,value='Purple',uname='COLOR',uvalue=[128,0,128])
void = widget_button(color,value='Red',uname='COLOR',uvalue=[255,0,0])
void = widget_button(color,value='Silver',uname='COLOR',uvalue=[192,192,192])
void = widget_button(color,value='Teal',uname='COLOR',uvalue=[0,128,128])
void = widget_button(color,value='White',uname='COLOR',uvalue=[255,255,255])
void = widget_button(color,value='Yellow',uname='COLOR',uvalue=[255,255,0])

void = widget_button(sfont,value='8',uname='FONTSZ',uvalue=8)
void = widget_button(sfont,value='10',uname='FONTSZ',uvalue=10)
void = widget_button(sfont,value='12',uname='FONTSZ',uvalue=12)
void = widget_button(sfont,value='14',uname='FONTSZ',uvalue=14)
void = widget_button(sfont,value='16',uname='FONTSZ',uvalue=16)
void = widget_button(sfont,value='18',uname='FONTSZ',uvalue=18)
void = widget_button(sfont,value='20',uname='FONTSZ',uvalue=20)
void = widget_button(sfont,value='22',uname='FONTSZ',uvalue=22)
void = widget_button(sfont,value='24',uname='FONTSZ',uvalue=24)
void = widget_button(sfont,value='26',uname='FONTSZ',uvalue=26)
void = widget_button(sfont,value='28',uname='FONTSZ',uvalue=28)

;----------------------------------------------------------------------------
; Create Context Sensitive menus for Title & Labels
csb2 = widget_base(self.tlb, /context_menu,uname='CSBTITLE',uvalue=cmdStr)
color = widget_button(csb2,value='Color',/menu)
font = widget_button(csb2,value='Font',/menu)
sfont = widget_button(csb2,value='Font Size',/menu)
void = widget_button(csb2,value='Delete',uname='REMOVELABEL')
void = widget_button(csb2,value='Properties...',uname='EDITLABLE')

void = widget_button(font,value='HELVETICA',uname='FONT',uvalue='HELVETICA')
void = widget_button(font,value='COURIER',uname='FONT',uvalue='COURIER')
void = widget_button(font,value='TIMES',uname='FONT',uvalue='TIMES')
void = widget_button(font,value='HERSHEY',uname='FONT',uvalue='HERSHEY')
void = widget_button(font,value='SYMBOL',uname='FONT',uvalue='SYMBOL')

void = widget_button(color,value='Aqua',uname='COLOR',uvalue=[0,255,255])
void = widget_button(color,value='Black',uname='COLOR',uvalue=[0,0,0])
void = widget_button(color,value='Blue',uname='COLOR',uvalue=[0,0,255])
void = widget_button(color,value='Fuchsia',uname='COLOR',uvalue=[255,0,255])
void = widget_button(color,value='Gray',uname='COLOR',uvalue=[128,128,128])
void = widget_button(color,value='Green',uname='COLOR',uvalue=[0,128,0])
void = widget_button(color,value='Lime',uname='COLOR',uvalue=[0,255,0])
void = widget_button(color,value='Maroon',uname='COLOR',uvalue=[128,0,0])
void = widget_button(color,value='Navy',uname='COLOR',uvalue=[0,0,128])
void = widget_button(color,value='Olive',uname='COLOR',uvalue=[128,128,0])
void = widget_button(color,value='Purple',uname='COLOR',uvalue=[128,0,128])
void = widget_button(color,value='Red',uname='COLOR',uvalue=[255,0,0])
void = widget_button(color,value='Silver',uname='COLOR',uvalue=[192,192,192])
void = widget_button(color,value='Teal',uname='COLOR',uvalue=[0,128,128])
void = widget_button(color,value='White',uname='COLOR',uvalue=[255,255,255])
void = widget_button(color,value='Yellow',uname='COLOR',uvalue=[255,255,0])

void = widget_button(sfont,value='8',uname='FONTSZ',uvalue=8)
void = widget_button(sfont,value='10',uname='FONTSZ',uvalue=10)
void = widget_button(sfont,value='12',uname='FONTSZ',uvalue=12)
void = widget_button(sfont,value='14',uname='FONTSZ',uvalue=14)
void = widget_button(sfont,value='16',uname='FONTSZ',uvalue=16)
void = widget_button(sfont,value='18',uname='FONTSZ',uvalue=18)
void = widget_button(sfont,value='20',uname='FONTSZ',uvalue=20)
void = widget_button(sfont,value='22',uname='FONTSZ',uvalue=22)
void = widget_button(sfont,value='24',uname='FONTSZ',uvalue=24)
void = widget_button(sfont,value='26',uname='FONTSZ',uvalue=26)
void = widget_button(sfont,value='28',uname='FONTSZ',uvalue=28)

;----------------------------------------------------------------------------
; realize widgets
widget_control, self.tlb,/realize

; add the destination object to self (widget object)
widget_control, drawID, get_value=oDest
self.oDest = oDest
oDest->getProperty, dimensions=dim
self.winDim = dim

; create and add a scene to self (widget object)
self.oScene = obj_new('IDLgrScene')

; assign self to uvalue of tlb
;widget_control, self.tlb, set_uvalue=self

; the graphics scene should be always reconstructed by default
self.renewScene = 1
registerName = 'db_display2di'
ret = dave_set_focus(self.tlb)
xmanager,registerName,self.tlb,/no_block,event_handler='db_display2di_event',cleanup='db_display2di_cleanup'

; Set this widget object as the visualization object ref of the gr object
if (~(self.oDaveGr)->set(visRef=self)) then return, 0

return,1
end


;===============================================================================
;
pro DB_Display2DI__define

void = {DB_Display2DI, $
        tlb:0L, $
        old_dec:0, $
        o_registry:obj_new(), $ ; object registry which handles communication with other programs
        oDest:obj_new(), $      ; the Destination object
        oScene:obj_new(), $     ; Scene to be drawn in the destination
        oDaveGr:obj_new(), $    ; the DaveGr object to be displayed
        oRband:obj_new(), $     ; a rubber band obj gr atom used for zooming
        oActive2DCont:obj_new(), $ ; contains a list of all DaveGr2D objects being actively viewed
        workDir:'', $           ; user's working directory
        csmObjRef:obj_new(), $  ; will contain the obj ref for object which triggers a con. sen menu
        renewScene:1b, $        ; flag to indicate whether the scene is to be completely reconstructed
        rbStart:[0,0], $        ; rubberband start point (for zooming)
        rbScale:[0.,0.,1.,1.], $ ; x,y scale factor to convert from device to data coordinates (for zooming)
        mouseMoved:0b, $        ; flag to indicate if mouse was moved while LMB is depressed
        xrangeFlag:0b, $        ; flag to indicate that user specified x-axis range should be used
        xrange:[0.,0.], $       ; user specified x-axis limits
        yrangeFlag:0b, $        ; flag to indicate that user specified y-axis range should be used
        yrange:[0.,0.], $       ; user specified y-axis limits
        zrangeFlag:0b, $        ; flag to indicate that user specified z-axis range should be used
        zrange:[0.,0.], $       ; user specified z-axis limits
        ctableIDsPtr:ptr_new(), $ ; widget ID's for the different color table items in con. sen. base menu
        interpIDs:[0L,0L], $    ; widget ID's for type of interpolation
        ;shadeIDs:[0L,0L], $     ; widget ID's for type of shading (contour,surface)
        min_draw_x:0, $         ; min dimensions for draw widget
        min_draw_y:0, $         ; min dimensions for draw widget
        dialog_x:0, $           ; min width for dialog portion of tlb
        winDim:[0,0], $         ; current draw window dimensions
        cbarLabel:0b, $         ; flag to indicate if the colorbar should be annotated
        normAspect:0b, $        ; flag to indicate if a normalized aspect ratio linked to data should used
        dispTitle:1b $          ; flag to indicate if main title is to be displayed
       }

end
