; CLASS_NAME:
;   sot_tab__define
;
; PURPOSE:
;   This defines the sot_tab plugin module for the Sodasurf package
;   in Solarsoft
;
; CATEGORY:
;   Main Module
;
; SUPERCLASSES:
;       Inherits from the plugin class
;
; SUBCLASSES:
;       List classes that inherit from this class, if any.
;
; CREATION:
;       Note how an object of this class is created.
;       Generally, this is just a reference to the class'
;       Init method.
;
; METHODS:
;       List the methods intrinsic to this class. There is no
;       need to list the inherited methods.
;
;   Update: A procedure for updating the tab in the Display Window belonging
;     to this plugin. This procedure is only called when this tab
;     is the currently selected one in the Display Window.
;
;   Init: For the creation of the tab.
;
;   GetProperty: retrieve information about the sot_tab object.
;
; MODIFICATION HISTORY:
;   Written by:  Mark Cheung, February 2007.
;      Any additional mods get described here.  Remember to
;      change the stuff above if you add a new keyword or
;      something!


PRO sot_profiles_menu_events, event
   ; Reference to Display_Window object
   widget_control, event.top, get_uvalue=DW
   DW->GetProperty, $
    DW_ID = DW_ID, $
    orientation = orientation, $
    main_ID=main_ID, colorbar=colorbar

   menu_id = widget_info(event.id, /parent)
   widget_control, menu_id,  get_uvalue = info
   sot_tab_obj = info.sot_tab_obj
   sot_tab_obj->GetProperty, profiles_window=profiles_window, $
    profiles_menu=profiles_menu, drawID=drawID

   widget_control, event.id, get_value=button_label

   case button_label of

    "Show Profiles": begin
    ; Create a new profiles window
          xsizes=[600, 600, 600] ;The profiles window sizes for the respective orientations
          ysizes=[500, 500, 500]
          xsize=xsizes[orientation-1]
          ysize=ysizes[orientation-1]
          profiles_window=widget_base(xsize=xsize, ysize=ysize, $
       group_leader = DW_ID, title="Orthogonal Profiles Window")
          profiles_draw=widget_draw(profiles_window, frame=1, $
           xsize=xsize-2, ysize=ysize-2, xoffset=1, yoffset=1)
          sot_tab_obj->SetProperty, profiles_orientation=orientation
          widget_control, profiles_window, /realize

          profiles_window_state = {profiles_window:profiles_window,$
        	profiles_draw:profiles_draw, sot_tab_obj:sot_tab_obj, profileID:event.id}
          widget_control, profiles_window, set_uvalue = profiles_window_state

          sot_tab_obj->SetProperty, profiles_window = profiles_window
          widget_control, event.id, set_value = "Hide Profiles"
          xmanager, 'profiles_events', profiles_window, /just_reg, cleanup='sot_profiles_window_cleanup'

    end

    "Hide Profiles": begin
       ;Kill the profiles window
       widget_control, profiles_window, /destroy
       widget_control, event.id, set_value = "Show Profiles"
    end

    "Blur off": begin
        ;Switch blur on/off
       sot_tab_obj->SetProperty, blur_or_not=0l
       sot_tab_obj->Update
       widget_control, event.id, set_value = "Blur on"
    end

    "Blur on": begin
       ;Switch blur on/off
       sot_tab_obj->SetProperty, blur_or_not=1l
       sot_tab_obj->Update
       widget_control, event.id, set_value = "Blur off"
    end

    "Zoom in": begin
       ;Zoom in 
       sot_tab_obj->GetProperty, draw_xsize=draw_xsize, draw_ysize=draw_ysize, tab_size=tab_size, zoom=zoom;, data_obj=data_obj, rank=rank
       ;data_obj[rank]->GetProperty, cube_size=cube_size
       sot_tab_obj->SetProperty, draw_xsize=max([2*draw_xsize,tab_size[0]]), draw_ysize=max([2*draw_ysize, tab_size[1]]), zoom=2*zoom
       sot_tab_obj->Refresh, resize=1
    end

    "Zoom out": begin
       ;Zoom out
       sot_tab_obj->GetProperty, draw_xsize=draw_xsize, draw_ysize=draw_ysize, tab_size=tab_size, zoom=zoom
       sot_tab_obj->SetProperty, draw_xsize=max([draw_xsize/2,tab_size[0]]), draw_ysize=max([draw_ysize/2, tab_size[1]]), zoom=zoom/2.
       sot_tab_obj->Refresh, resize=1
    end

    "Zoom to fit window": begin
       ;Zoom to fit window
        sot_tab_obj->GetProperty, draw_colorbar=draw_colorbar, draw_xsize=draw_xsize, draw_ysize=draw_ysize, $
          rank=rank
        IF draw_colorbar THEN BEGIN
            free_horizontal_space = draw_xsize-min([0.25*draw_xsize,100])
        ENDIF ELSE BEGIN
            free_horizontal_space = draw_ysize
        ENDELSE
        free_vertical_space = draw_ysize
        scr_aspect_ratio = float(free_vertical_space)/float(free_horizontal_space)

        DW->GetProperty, data_obj=data_obj, orientation=orientation
        (data_obj[rank])->GetProperty, cube_ptr=cube_ptr, axes_units=axes_units

        case orientation of
            1: begin
                slice_height = n_elements((*cube_ptr)[0,0,*])
                slice_width = n_elements((*cube_ptr)[*,0,0])
            end
            2: begin
                slice_height = n_elements((*cube_ptr)[0,*,0])
                slice_width = n_elements((*cube_ptr)[*,0,0])
            end
            3: begin
                slice_height = n_elements((*cube_ptr)[0,*,0])
                slice_width = n_elements((*cube_ptr)[0,0,*])
            end
        endcase
        slice_aspect_ratio = float(slice_height)/float(slice_width)
        
        height = draw_ysize-100 ;round(slice_height)*self.zoom
        width  = draw_xsize-100 ;round(slice_width)*self.zoom
        zoom = float(height)/float(slice_height)
        zoom = min([zoom,float(width)/float(slice_width)])

        ;horizontal_margin = round((free_horizontal_space-width)/2.)
        ;vertical_margin   = round((free_vertical_space-height)/2.)
        active_draw_region = [60, 80,$
                                   60+width-1, 80+height-1] ;-[0.,vertical_margin/2,0.,vertical_margin/2.]

        sot_tab_obj->GetProperty, draw_xsize=draw_xsize, draw_ysize=draw_ysize, tab_size=tab_size
        sot_tab_obj->SetProperty, draw_xsize=tab_size[0], draw_ysize=tab_size[1], zoom=zoom,$
          active_draw_region=active_draw_region
        sot_tab_obj->Refresh, resize=1
        
    end

    "Zoom 1x": begin
       ;Original size
       sot_tab_obj->GetProperty, draw_xsize=draw_xsize, draw_ysize=draw_ysize, tab_size=tab_size
       sot_tab_obj->SetProperty, draw_xsize=tab_size[0], draw_ysize=tab_size[1], zoom=1
       sot_tab_obj->Refresh, resize=1
    end

    'Custom 2D Profile': begin
       IF orientation EQ 1 THEN BEGIN
       widget_control, drawID, get_uvalue = cursor_pos
       print, cursor_pos
       i0 = min([cursor_pos.i0, cursor_pos.i1])
       i1 = max([cursor_pos.i0, cursor_pos.i1])
       j0 = min([cursor_pos.j0, cursor_pos.j1])
       j1 = max([cursor_pos.j0, cursor_pos.j1])
       print, i0, j0, i1, j1
       ; Line is undefined->exit case statement
       if (i0 eq i1) and (j0 eq j1) then break

       p_length = sqrt(float(i1-i0)^2.+float(j1-j0)^2.)
       cosine = (float(i1)-float(i0))/p_length
       sine = (float(j1)-float(j0))/p_length
       N_p = ceil(p_length)
       i_axis = fltarr(N_p)
       k_axis = fltarr(N_p)
       i_axis = i0+findgen(N_p)*cosine
       k_axis = j0+findgen(N_p)*sine

       DW->GetProperty, data_obj = data_obj
       data_obj->GetProperty,$
          cube_ptr = cube_ptr, $
          variable_name=variable_name, $
          variable_obj = variable_obj, $
          dir = dir, nmod=nmod
       N_y = n_elements((*cube_ptr)[0,*,0])
       j_axis = findgen(N_y)
       temp_cube = interpolate(*cube_ptr, i_axis, j_axis, k_axis, /grid)
       help, temp_cube
       export_slice = fltarr(N_p,1,N_y)

       temp_line = fltarr(N_p)
       for h=0,N_y-1,1 do begin
       for g=0,N_p-1,1 do begin
         temp_line[g] = temp_cube[g, h, g]
       endfor
          export_slice[*,0,h] = temp_line
       endfor

       data_obj = Obj_New("data_set", data_type=2, dir=dir, $
          nmod = nmod, cube_ptr=Ptr_New(export_slice), $
          variable_name = variable_name, $
          variable_object = variable_obj, $
          grid_ptr=Ptr_New([i_axis, j_axis, k_axis]))

       DW_new = OBJ_NEW("Display_Window", group_leader=main_ID, data_obj = data_obj)
       ENDIF
    END

    "Line Profile": BEGIN
       sot_tab_obj->GetProperty, line_profile_window=line_profile_window, tab_ID=tab_ID
       IF widget_info(line_profile_window, /valid_ID) THEN BEGIN
          widget_control, line_profile_window, /destroy
          sot_tab_obj->SetProperty, line_profile_window=0L
       ENDIF ELSE BEGIN
          line_profile_window = widget_base(xsize=400,ysize=600, group_leader=tab_ID)
          line_profile_draw = widget_draw(line_profile_window, xsize=400,ysize=600)
          sot_tab_obj->SetProperty, line_profile_window=line_profile_window
          widget_control, line_profile_window, set_uvalue = $
             {line_profile_draw:line_profile_draw, $
             line_profile_window:line_profile_window}
          widget_control, line_profile_window, /realize
          xmanager, 'profiles_events', line_profile_window
          Print, "line_profile_window=", line_profile_window
          ;sot_tab_obj->Update
       ENDELSE
    END

    "Show Colorbar": BEGIN
       widget_control, event.id, set_value = "Hide Colorbar"
       sot_tab_obj->SetProperty, draw_colorbar=1
       sot_tab_obj->Refresh, resize=1
    END

    "Hide Colorbar": BEGIN
       widget_control, event.id, set_value = "Show Colorbar"
       sot_tab_obj->SetProperty, draw_colorbar=0
       sot_tab_obj->Refresh, resize=1
    END

    "Draw Axes Labels": BEGIN
       widget_control, event.id, set_value = "Hide Axes Labels"
       sot_tab_obj->SetProperty, draw_axes_labels=1
       sot_tab_obj->Refresh, resize=1
    END

    "Hide Axes Labels": BEGIN
       widget_control, event.id, set_value = "Draw Axes Labels"
       sot_tab_obj->SetProperty, draw_axes_labels=0
       sot_tab_obj->Refresh, resize=1
    END

    "Scale colors to slice extrema": BEGIN
       ;widget_control, event.id, set_value = "Scale colors to cube extrema"
       sot_tab_obj->SetProperty, tvscl_by_slice=1
       sot_tab_obj->Refresh, resize=1
    END

    "Scale colors to cube extrema": BEGIN
       ;widget_control, event.id, set_value = "Scale colors to slice extrema"
       sot_tab_obj->SetProperty, tvscl_by_slice=0
       sot_tab_obj->Refresh, resize=1
    END

    "middle 99.9%": BEGIN
       ;=======Apply settings changes to surface Tab Plugin=====
       sot_tab_obj->GetProperty, data_obj=data_obj, rank=rank
       data_obj->GetProperty, cube_ptr=cube_ptr
       min=min(*cube_ptr)
       max=max(*cube_ptr)
       hist=histogram(*cube_ptr, min=min, max=max, nbins=100, locations=locations)
       hist=total(hist, /cumulative)/total(hist)
       min = locations[min(where(hist GE 0.0005))]
       max = locations[max(where(hist LE 0.9995))]
       data_obj->SetProperty, colormin=min, colormax=max
       sot_tab_obj->SetProperty, tvscl_by_slice=2
       sot_tab_obj->Refresh, resize=1
    END


    "middle 99%": BEGIN
       ;=======Apply settings changes to surface Tab Plugin=====
       sot_tab_obj->GetProperty, data_obj=data_obj, rank=rank
       data_obj->GetProperty, cube_ptr=cube_ptr
       min=min(*cube_ptr)
       max=max(*cube_ptr)
       hist=histogram(*cube_ptr, min=min, max=max, nbins=100, locations=locations)
       hist=total(hist, /cumulative)/total(hist)
       min = locations[min(where(hist GE 0.005))]
       max = locations[max(where(hist LE 0.995))]
       data_obj->SetProperty, colormin=min, colormax=max
       sot_tab_obj->SetProperty, tvscl_by_slice=2
       sot_tab_obj->Refresh, resize=1
    END

    "middle 95%": BEGIN
       ;=======Apply settings changes to surface Tab Plugin=====
       sot_tab_obj->GetProperty, data_obj=data_obj, rank=rank
       data_obj->GetProperty, cube_ptr=cube_ptr
       min=min(*cube_ptr)
       max=max(*cube_ptr)
       hist=histogram(*cube_ptr, min=min, max=max, nbins=100, locations=locations)
       hist=total(hist, /cumulative)/total(hist)
       min = locations[min(where(hist GE 0.025))]
       max = locations[max(where(hist LE 0.975))]
       data_obj->SetProperty, colormin=min, colormax=max
       sot_tab_obj->SetProperty, tvscl_by_slice=2
       sot_tab_obj->Refresh, resize=1
    END

    "lower 40%": BEGIN
       ;=======Apply settings changes to surface Tab Plugin=====
       sot_tab_obj->GetProperty, data_obj=data_obj, rank=rank
       data_obj->GetProperty, cube_ptr=cube_ptr
       min=min(*cube_ptr)
       max=max(*cube_ptr)
       hist=histogram(*cube_ptr, min=min, max=max, nbins=100, locations=locations)
       hist=total(hist, /cumulative)/total(hist)
       min = locations[min(where(hist GE 0.005))]
       max = locations[max(where(hist LT 0.405))]
       data_obj->SetProperty, colormin=min, colormax=max
       sot_tab_obj->SetProperty, tvscl_by_slice=2
       sot_tab_obj->Refresh, resize=1
       ;stop
    END

    "upper 40%": BEGIN
       ;=======Apply settings changes to surface Tab Plugin=====
       sot_tab_obj->GetProperty, data_obj=data_obj, rank=rank
       data_obj->GetProperty, cube_ptr=cube_ptr
       min=min(*cube_ptr)
       max=max(*cube_ptr)
       hist=histogram(*cube_ptr, min=min, max=max, nbins=100, locations=locations)
       hist=total(hist, /cumulative)/total(hist)
       min = locations[min(where(hist GE 0.595))]
       max = locations[max(where(hist LE 0.995))]
       data_obj->SetProperty, colormin=min, colormax=max
       sot_tab_obj->SetProperty, tvscl_by_slice=2
       sot_tab_obj->Refresh, resize=1
    END

   "Scale colors to range:": BEGIN
       sot_tab_obj->GetProperty, data_obj = data_obj
       
       IF N_ELEMENTS(range_settings_window) EQ 0 THEN BEGIN
       ;===============Build new Settings Window================
       range_settings_window = widget_base(xsize=250,ysize=90,row=3, $
          title="Range settings", group_leader=DW_ID, $
          event_pro="sot_profiles_menu_events")
       data_obj->GetProperty, colormin=colormin, colormax=colormax

       min_label  = widget_label(range_settings_window, value="Min")
       min_text = widget_text(range_settings_window, Value=string(colormin, format="(F12.3)"), /editable, event_pro='sot_profiles_menu_events')
       max_label  = widget_label(range_settings_window, value='Max')
       max_text = widget_text(range_settings_window, Value=string(colormax, format="(F12.3)"), /editable, event_pro='sot_profiles_menu_events')

       apply_button = widget_button(range_settings_window, value="Apply", event_pro=$
          "sot_range_settings_window_events")
       done_button = widget_button(range_settings_window, value="Done", event_pro=$
          "sot_range_settings_window_events")

       ;=============Save widget IDs======================
       sot_tab_obj->SetProperty, range_settings_window=range_settings_window
       widget_control, range_settings_window, set_uvalue = {$
          sot_tab_obj:sot_tab_obj, $
          min_text:min_text, max_text:max_text,$
          range_settings_window:range_settings_window, data_obj:data_obj}

       ;==========Realize the Settings Window================
       widget_control, range_settings_window, /realize
       xmanager, 'sot_profiles_menu_events', range_settings_window, $
          /just_reg, cleanup='sot_range_settings_window_cleanup'

       ;==========Change context menu button label to "Hide Settings"===
       ;widget_control, event.id, set_value="Hide Settings"
       ENDIF
    ENDCASE

    'HelioKB reporter': BEGIN
        sot_tab_obj->GetProperty, rank=rank
        DW->Register_Plugin, plugin=Obj_New("kb_tab", DW=DW, rank=rank)
        DW->Refresh
    ENDCASE
    'Zoom view of bounded region': BEGIN
        sot_tab_obj->GetProperty, rank=rank
        DW->Register_Plugin, plugin=Obj_New("sot_zoom_tab", DW=DW, rank=rank)
        DW->Refresh
    ENDCASE


    ELSE: BEGIN
    END
   ENDCASE
END

PRO sot_profiles_window_cleanup, profiles_window
    widget_control, profiles_window, get_uvalue = profiles_window_state
    sot_tab_obj = profiles_window_state.sot_tab_obj
    sot_tab_obj->GetProperty, tab_ID=tab_ID
    if (widget_info(tab_ID, /valid_id)) then begin
       sot_tab_obj->SetProperty, profiles_window=0L
    endif

    if (widget_info(profiles_window_state.profileID, /valid_id)) then begin
       widget_control, profiles_window_state.profileID, set_value="Show Profiles"
    endif
    print, "Profile window " + string(profiles_window) + " killed"
END

PRO sot_cursor_events, event
; Coordinates of box containing active cursor region

; Fetch information about Display Window Object

sot_tab_ID=widget_info(event.id, /parent)
widget_control, sot_tab_ID, get_uvalue=sot_tab_obj
sot_tab_obj->GetProperty, DW=DW, $
    profiles_window=profiles_window, $
    line_profile_window = line_profile_window, $
    active_draw_region=active_draw_region, $
    context_menu=context_menu

i0 = active_draw_region[0]
j0 = active_draw_region[1]
i1 = active_draw_region[2]
j1 = active_draw_region[3]

DW->GetProperty, $
    DW_ID=DW_ID, $
    red=red, green=green, blue=blue, $
    orientation=orientation, $
    movie_player=movie_player

sot_tab_obj->GetProperty, data_obj=data_obj, zoom=zoom

widget_control, movie_player, get_uvalue=movie_player_state
widget_control, movie_player_state.frame_slider, get_value=frame_number

widget_control, event.id, get_value=wid
wset, wid

; Mouse press events
if  event.type EQ 0 AND (event.x ge i0) AND (event.x le i1) AND $
    (event.y ge j0) AND (event.y le j1) then begin
     data_obj->GetProperty, vertex1=vertex1, vertex2=vertex2, cube_ptr=cube_ptr

    case orientation of
       1: begin
       imin=vertex1[0]
       imax=vertex2[0]
       jmin=vertex1[2]
       jmax=vertex2[2]
       end
       2: begin
       imin=vertex1[0]
       imax=vertex2[0]
       jmin=vertex1[1]
       jmax=vertex2[1]
       end
       3: begin
       imin=vertex1[2]
       imax=vertex2[2]
       jmin=vertex1[1]
       jmax=vertex2[1]
       end
    endcase
    iscale=1
    jscale=1
    if (imax gt imin) then iscale=imax-imin
    if (jmax gt jmin) then jscale=jmax-jmin
    inew = floor((float(event.x-i0)*iscale)/float(i1-i0))
    jnew = floor((float(event.y-j0)*jscale)/float(j1-j0))

    widget_control, event.id, get_uvalue = cursor_state
    cursor_state.i = inew
    cursor_state.j = jnew
    widget_control, event.id, set_uvalue = cursor_state
    case event.press of 
       1:BEGIN
	    DW->GetProperty, bounding_box=bounding_box
    	    bounding_box[0] = inew
    	    bounding_box[1] = jnew
    	    DW->SetProperty, bounding_box=bounding_box
    	    ; Cross-hairs
    	    plots, [i0+inew*zoom,i0+inew*zoom], [j0,j1], color=255, /device, line=2
    	    plots, [i0,i1], [j0+jnew*zoom,j0+jnew*zoom], /device, color=255, line=2
                                ; Let Draw widget generate cursor
                                ; motion events, so that rubberband
                                ; bounding box can be updated as the
                                ; user drags the cursor
            widget_control, event.id, draw_motion_events=1
       ENDCASE
       ELSE: BEGIN
       ENDELSE
    END
endif
; ENDIF Mouse press events

; Mouse release events
if  event.type EQ 1 AND (event.x ge i0) AND (event.x le i1) AND $
    (event.y ge j0) AND (event.y le j1) then begin

    data_obj->GetProperty, vertex1=vertex1, vertex2=vertex2, cube_ptr=cube_ptr

    case orientation of
       1: begin
       imin=vertex1[0]
       imax=vertex2[0]
       jmin=vertex1[2]
       jmax=vertex2[2]
       end
       2: begin
       imin=vertex1[0]
       imax=vertex2[0]
       jmin=vertex1[1]
       jmax=vertex2[1]
       end
       3: begin
       imin=vertex1[2]
       imax=vertex2[2]
       jmin=vertex1[1]
       jmax=vertex2[1]
       end
    endcase
    iscale=1
    jscale=1
    if (imax gt imin) then iscale=imax-imin
    if (jmax gt jmin) then jscale=jmax-jmin
    inew = floor((float(event.x-i0)*iscale)/float(i1-i0))
    jnew = floor((float(event.y-j0)*jscale)/float(j1-j0))

    widget_control, event.id, get_uvalue = cursor_state
    cursor_state.i = inew
    cursor_state.j = jnew
    widget_control, event.id, set_uvalue = cursor_state

    case event.release of

       1: begin
       cursor_state.i0 = inew
       cursor_state.j0 = jnew
       cursor_state.x0 = event.x
       cursor_state.y0 = event.y
       if (cursor_state.x0 ne cursor_state.x1) and $
         (cursor_state.y0 ne cursor_state.y1) and $
         (cursor_state.x1 ge i0) and $
         (cursor_state.y1 ge j0) then begin
         sot_tab_obj->Update
       endif
       widget_control, event.id, set_uvalue = cursor_state
       DW->GetProperty, bounding_box=bounding_box
       bounding_box[2] = inew
       bounding_box[3] = jnew
       temp_box = bounding_box
       ; Make sure bounding box coordinates are ordered correctly.
       if bounding_box[0] GT bounding_box[2] THEN BEGIN
	  bounding_box[2] = temp_box[0]
	  bounding_box[0] = temp_box[2]
       endif
       if bounding_box[1] GT bounding_box[3] THEN BEGIN
	  bounding_box[3] = temp_box[1]
	  bounding_box[1] = temp_box[3]
       endif

       DW->SetProperty, bounding_box=bounding_box
       sot_tab_obj->Update
       ; Draw bounding box
       plots, [i0+bounding_box[0]*zoom,i0+bounding_box[0]*zoom], [j0+bounding_box[1]*zoom,j0+bounding_box[3]*zoom], color=255, /device, line=2
       plots, [i0+bounding_box[0]*zoom,i0+bounding_box[2]*zoom], [j0+bounding_box[1]*zoom,j0+bounding_box[1]*zoom], color=255, /device, line=2
       plots, [i0+bounding_box[2]*zoom,i0+bounding_box[2]*zoom], [j0+bounding_box[1]*zoom,j0+bounding_box[3]*zoom], color=255, /device, line=2
       plots, [i0+bounding_box[0]*zoom,i0+bounding_box[2]*zoom], [j0+bounding_box[3]*zoom,j0+bounding_box[3]*zoom], color=255, /device, line=2
       widget_control, event.id, draw_motion_events=0
       end

       2:begin
       cursor_state.i1 = inew
       cursor_state.j1 = jnew
       cursor_state.x1 = event.x
       cursor_state.y1 = event.y
       if (cursor_state.x0 ne cursor_state.x1) and $
         (cursor_state.y0 ne cursor_state.y1) and $
         (cursor_state.x0 ge i0) and $
         (cursor_state.y0 ge j0) then begin
         sot_tab_obj->Update
         plots, [cursor_state.x0, cursor_state.x1], $
            [cursor_state.y0,cursor_state.y1], /device, psym=4,$
            thick=1.5, color=0
       endif
       widget_control, event.id, set_uvalue = cursor_state
       end
       4:begin
       base_ID = widget_info(event.id, /parent)
       widget_displaycontextmenu, event.id, event.x, event.y, $
         context_menu
       end

       else:begin
       end
    endcase
endif
; END Mouse release events

;BEGIN Mouse motion events
if event.type EQ 2 AND (event.x ge i0) AND (event.x le i1) AND $
    (event.y ge j0) AND (event.y le j1) then begin
     data_obj->GetProperty, vertex1=vertex1, vertex2=vertex2, cube_ptr=cube_ptr

    case orientation of
       1: begin
       imin=vertex1[0]
       imax=vertex2[0]
       jmin=vertex1[2]
       jmax=vertex2[2]
       end
       2: begin
       imin=vertex1[0]
       imax=vertex2[0]
       jmin=vertex1[1]
       jmax=vertex2[1]
       end
       3: begin
       imin=vertex1[2]
       imax=vertex2[2]
       jmin=vertex1[1]
       jmax=vertex2[1]
       end
    endcase

    iscale=1
    jscale=1
    if (imax gt imin) then iscale=imax-imin
    if (jmax gt jmin) then jscale=jmax-jmin
    inew = floor((float(event.x-i0)*iscale)/float(i1-i0))
    jnew = floor((float(event.y-j0)*jscale)/float(j1-j0))

    widget_control, event.id, get_uvalue = cursor_state
    cursor_state.i = inew
    cursor_state.j = jnew
    widget_control, event.id, set_uvalue = cursor_state
       DW->GetProperty, bounding_box=bounding_box
       bounding_box[2] = inew
       bounding_box[3] = jnew
       temp_box = bounding_box

       DW->SetProperty, bounding_box=bounding_box
       sot_tab_obj->Update
       ; Draw bounding box
       plots, [i0+bounding_box[0]*zoom,i0+bounding_box[0]*zoom], [j0+bounding_box[1]*zoom,j0+bounding_box[3]*zoom], color=255, /device, line=2
       plots, [i0+bounding_box[0]*zoom,i0+bounding_box[2]*zoom], [j0+bounding_box[1]*zoom,j0+bounding_box[1]*zoom], color=255, /device, line=2
       plots, [i0+bounding_box[2]*zoom,i0+bounding_box[2]*zoom], [j0+bounding_box[1]*zoom,j0+bounding_box[3]*zoom], color=255, /device, line=2
       plots, [i0+bounding_box[0]*zoom,i0+bounding_box[2]*zoom], [j0+bounding_box[3]*zoom,j0+bounding_box[3]*zoom], color=255, /device, line=2
       
endif 
;END Mouse motion events

if event.type EQ 5 AND (event.x ge i0) AND (event.x le i1) AND $
    (event.y ge j0) AND (event.y le j1) then begin

    data_obj->GetProperty, vertex1=vertex1, vertex2=vertex2, cube_ptr=cube_ptr

    case orientation of
       1: begin
       imin=vertex1[0]
       imax=vertex2[0]
       jmin=vertex1[2]
       jmax=vertex2[2]
       end
       2: begin
       imin=vertex1[0]
       imax=vertex2[0]
       jmin=vertex1[1]
       jmax=vertex2[1]
       end
       3: begin
       imin=vertex1[2]
       imax=vertex2[2]
       jmin=vertex1[1]
       jmax=vertex2[1]
       end
    endcase

    iscale=1
    jscale=1
    if (imax gt imin) then iscale=imax-imin
    if (jmax gt jmin) then jscale=jmax-jmin
    inew = floor((float(event.x-i0)*iscale)/float(i1-i0))
    jnew = floor((float(event.y-j0)*jscale)/float(j1-j0))

    widget_control, event.id, get_uvalue = cursor_state
    cursor_state.i = inew
    cursor_state.j = jnew

       IF cursor_state.i0 NE cursor_state.i1 AND cursor_state.j0 NE cursor_state.j1 THEN BEGIN
           case orientation of
             1: print, "C1=",cursor_state.i0, cursor_state.j0, (*cube_ptr)[cursor_state.i0,frame_number,cursor_state.j0]
             2: print, "C1=",(data_obj->axis('x'))[cursor_state.i0], (data_obj->axis('y'))[cursor_state.j0],$
		 (data_obj->axis('z'))[frame_number], $
		7.25e7^2*total((*cube_ptr)[min([cursor_state.i0,cursor_state.i1]):max([cursor_state.i0,cursor_state.i1])$
		,min([cursor_state.j0,cursor_state.j1]):max([cursor_state.j0,cursor_state.j1]),frame_number])
             3: print, "C1=",cursor_state.i0, cursor_state.j0, (*cube_ptr)[frame_number,cursor_state.i0,cursor_state.j0]
            endcase
       ENDIF


    case event.release of

       1: begin
       cursor_state.i0 = inew
       cursor_state.j0 = jnew
       cursor_state.x0 = event.x
       cursor_state.y0 = event.y
       if (cursor_state.x0 ne cursor_state.x1) and $
         (cursor_state.y0 ne cursor_state.y1) and $
         (cursor_state.x1 ge i0) and $
         (cursor_state.y1 ge j0) then begin
         sot_tab_obj->Update
         ;plots, [cursor_state.x0, cursor_state.x1], $
         ;   [cursor_state.y0,cursor_state.y1], /device, psym=6,$
         ;   thick=1.5, color=0
       endif
       end

       2:begin
       cursor_state.i1 = inew
       cursor_state.j1 = jnew
       cursor_state.x1 = event.x
       cursor_state.y1 = event.y
       if (cursor_state.x0 ne cursor_state.x1) and $
         (cursor_state.y0 ne cursor_state.y1) and $
         (cursor_state.x0 ge i0) and $
         (cursor_state.y0 ge j0) then begin
         sot_tab_obj->Update
         plots, [cursor_state.x0, cursor_state.x1], $
            [cursor_state.y0,cursor_state.y1], /device, psym=6,$
            thick=1.5, color=0
       endif
;       print, "C2=",cursor_state.x1, cursor_state.x1
       end

       4:begin
       base_ID = widget_info(event.id, /parent)
       widget_displaycontextmenu, event.id, event.x, event.y, $
         context_menu
       end

       else:begin
       end
    endcase

    ; Store the cursor positions in the uvalue of this draw widget.
    widget_control, event.id, set_uvalue = cursor_state

endif


IF widget_info(profiles_window, /valid_id) AND $
    widget_info(DW_ID, /valid_id) AND $
    (event.x ge i0) AND (event.x lt i1) AND $
    (event.y ge j0) AND (event.y lt j1) THEN BEGIN

    ; Draw the cross-sections
    widget_control, profiles_window, get_uvalue = profiles_window_state
    widget_control, profiles_window_state.profiles_draw, get_value = pwid
    wset, pwid
    sot_tab_obj->draw_profiles

ENDIF

IF widget_info(line_profile_window, /valid_id) AND $
    widget_info(DW_ID, /valid_id) AND $
    (event.x ge i0) AND (event.x lt i1) AND $
    (event.y ge j0) AND (event.y lt j1) THEN BEGIN

    ; Draw the line profile
    sot_tab_obj->draw_line_profile

ENDIF
END


PRO sot_range_settings_window_events, event

;=========Retrive Information about Settings Window==========
range_settings_window = event.top
widget_control, range_settings_window, get_uvalue = info

;===Retrieve label of the button that generated this event===

IF (TAG_NAMES(event, /STRUCTURE_NAME) EQ 'WIDGET_BUTTON') THEN BEGIN
   widget_control, event.id, get_value = button_label

   ;==================Handle different button events==================
   CASE button_label OF

    "Apply": BEGIN
       ;=======Apply settings changes to surface Tab Plugin=====
       widget_control, info.min_text, get_value=min
       widget_control, info.max_text, get_value=max
       info.data_obj->SetProperty, colormin=min, colormax=max
       info.sot_tab_obj->SetProperty, tvscl_by_slice=2
       info.sot_tab_obj->Refresh, resize=1
    ENDCASE

    "Done": BEGIN
       widget_control, range_settings_window, /destroy
       info.sot_tab_obj->SetProperty, range_settings_window=0L
    ENDCASE

    ELSE: BEGIN
       ; This shouldn't happen
    ENDCASE
   END
ENDIF


END

PRO sot_range_settings_window_cleanup, range_settings_window

   widget_control, range_settings_window, get_uvalue = info
   info.sot_tab_obj->GetProperty, context_menu = context_menu
   widget_control, context_menu, get_uvalue = context_menu_state
   ;widget_control, context_menu_state.settings, set_value = "Settings"

   info.sot_tab_obj->SetProperty, range_settings_window = 0L
   widget_control, range_settings_window, /destroy

END

;==================================================================
; METHODNAME:
;       sot_tab::draw_profiles
;
; PURPOSE:
;   For drawing 2D profiles of the data cube in directions orthogonal to
;   the orientation displayed in the draw canvas of the sot tab.
;   e.g. If the slice (*,y,*) is shown in the sot tab, this method
;   will draw slices (x,*,*) and (*,*,z) in the profiles window, with
;   x and z determined from the position of the cursor on the draw canvas.
;
; CALLING SEQUENCE:
;   sot_tab->draw_profiles
;
; RESTRICTIONS:
;   Describe any "restrictions" here.  Delete this section if there are
;   no important restrictions.
;
; MODIFICATION HISTORY:
;   Written by:  Mark Cheung, April 2003
;   May, 2003 Made this into a method of the sot_tab object class.
;      Initially this was a stand-alone method but implementation
;      was problematic. By incorporating this a method of the class,
;      it has become much more robust.

PRO sot_tab::draw_line_profile
   widget_control, self.drawID, get_uvalue = coords
   ;print, "Calling from sot_tab::draw_line_profile"
   self.DW->GetProperty, data_obj = data_obj, orientation=orientation,$
    movie_player=movie_player
   data_obj[self.rank]->GetProperty, cube_ptr=cube_ptr

   widget_control, movie_player, get_uvalue=movie_player_state
   widget_control, movie_player_state.frame_slider, get_value=frame_number

   widget_control, self.line_profile_window, get_uvalue = info
   widget_control, info.line_profile_draw, get_value = profile_drawID
   wset, profile_drawID

   CASE orientation OF

    1: BEGIN
       coords.i = min([coords.i,N_ELEMENTS((*cube_ptr)[*,0,0])-1])
       coords.j = min([coords.j,N_ELEMENTS((*cube_ptr)[0,0,*])-1])
       array1 = (*cube_ptr)[coords.i,*,coords.j]
       title = "x="+string(coords.i, format="(I5)")+", z="+$
       string(coords.j, format="(I5)")
       array2 = (*cube_ptr)[*,frame_number,coords.j]
       array3 = (*cube_ptr)[coords.i,frame_number,*]
    ENDCASE

    2: BEGIN
       coords.i = min([coords.i,N_ELEMENTS((*cube_ptr)[*,0,0])-1])
       coords.j = min([coords.j,N_ELEMENTS((*cube_ptr)[0,*,0])-1])
       array1 = (*cube_ptr)[coords.i, coords.j, *]
       array2 = (*cube_ptr)[*,coords.j,frame_number]
       array3 = (*cube_ptr)[coords.i,*,frame_number]
       title = "x="+string(coords.i, format="(I5)")+", y="+$
       string(coords.j, format="(I5)")
    ENDCASE

    3: BEGIN
       coords.i = min([coords.i,N_ELEMENTS((*cube_ptr)[0,0,*])-1])
       coords.j = min([coords.j,N_ELEMENTS((*cube_ptr)[0,*,0])-1])
       array1 = (*cube_ptr)[*, coords.j, coords.i]
       array2 = (*cube_ptr)[frame_number, coords.j,*]
       array3 = (*cube_ptr)[frame_number, *, coords.i]
       title = "y="+string(coords.j, format="(I5)")+", z="+$
       string(coords.i, format="(I5)")
;      title1 = "y="+string(coords.j, format="(I5)")+", z="+$
;     string(coords.i, format="(I5)")
;      title1 = "y="+string(coords.j, format="(I5)")+", z="+$
;     string(coords.i, format="(I5)")
    ENDCASE
   END
   oldPMulti = !P.multi
   oldCharsize = !P.charsize
   !P.charsize = 2.0
   !P.multi=[0,1,3]
   !P.position=[0,0,0,0]
   plot, array1, title=title,/xstyle
   plot, array2, /xstyle
   plot, array3, /xstyle
   !P.charsize=oldCharsize
   !P.multi=oldPMulti
END

PRO sot_tab::draw_profiles

self.DW->GetProperty, $
    data_obj = data_obj, $
    red=red, green=green, blue=blue, $
    orientation=orientation

(data_obj[self.rank])->GetProperty, cube_ptr = cube_ptr, minValue=minValue, maxValue=maxValue

; Draw the cross-sections
widget_control, self.profiles_window, get_uvalue = profiles_window_state
widget_control, profiles_window_state.profiles_draw, get_value = index
if !D.NAME EQ 'X' then wset, index
TVLCT, red, green, blue

; Get coordinates of cursor for profiles
widget_control, self.drawID, get_uvalue = coords

if self.profiles_orientation ne orientation then begin
   xsizes=[300, 300, 300]
   ysizes=[300, 450, 450]
   xsize = xsizes[orientation-1]
   ysize = ysizes[orientation-1]

   widget_control, self.profiles_window, ysize=ysize
   widget_control, self.profiles_window, xsize=xsize

   widget_control, profiles_window_state.profiles_draw, /destroy
   profiles_draw=widget_draw(self.profiles_window, frame=1, $
    xsize=xsize-2, ysize=ysize-2, xoffset=1, yoffset=1)
   profiles_window_state.profiles_draw=profiles_draw
   widget_control, self.profiles_window, set_uvalue=profiles_window_state
   self.profiles_orientation = orientation

endif

x_length = n_elements((*cube_ptr)[*,0,0])
y_length = n_elements((*cube_ptr)[0,*,0])
z_length = n_elements((*cube_ptr)[0,0,*])

case orientation of

   1: begin ; sot tab is showing x-z slice
   if (coords.j lt z_length) and (coords.i lt x_length) then begin
    image1 = (*cube_ptr)(*,*,coords.j)
    image2 = transpose((*cube_ptr)(coords.i,*,*))
    IF self.tvscl_by_slice THEN BEGIN
       tvscl, image1, 5, 15
       tvscl, image2, 5, 150
    ENDIF ELSE BEGIN
       image1 = (!D.Table_Size-1)*(image1-minValue)/(maxValue-minValue)
       image2 = (!D.Table_Size-1)*(image2-minValue)/(maxValue-minValue)
       tv, image1, 5, 15
       tv, image2, 5, 150
    ENDELSE
    xyouts, 10, 17, string(coords.j, format='("z = ",I4)'),$
       color=[255,255,255], /device
    xyouts, 11, 18, string(coords.j, format='("z = ",I4)'),$
       color=[0,0,0], /device
        xyouts, 10, 152, string(coords.i, format='("x = ",I4)'),$
       color=[255,255,255],  /device
    xyouts, 11, 153, string(coords.i, format='("x = ",I4)'),$
       color=[0,0,0],  /device
   endif
   end

   2: begin ; sot tab is showing x-y slice
   if (coords.j lt y_length) and (coords.i lt x_length) then begin
    image1 = (*cube_ptr)(*,coords.j,*)
    image2 = transpose((*cube_ptr)(coords.i,*,*))
    IF self.tvscl_by_slice THEN BEGIN
       tvscl, image1, 5, 15
       tvscl, image2, 5, 315
    ENDIF ELSE BEGIN
       image1 = (!D.Table_Size-1)*(image1-minValue)/(maxValue-minValue)
       image2 = (!D.Table_Size-1)*(image2-minValue)/(maxValue-minValue)
       tv, image1, 5, 15
       tv, image2, 5, 315
    ENDELSE
    xyouts, 10, 17, string(coords.j, format='("y = ",I4)'),$
       color=[255,255,255], /device
    xyouts, 11, 18, string(coords.j, format='("y = ",I4)'),$
       color=[0,0,0], /device
    xyouts, 10, 317, string(coords.i, format='("x = ",I4)'),$
       color=[255,255,255],  /device
    xyouts, 11, 318, string(coords.i, format='("x = ",I4)'),$
       color=[0,0,0],  /device
   endif
   end

   3: begin ; sot tab is showing z-y slice
   if (coords.j lt y_length) and (coords.i lt z_length) then begin
    image1 = (*cube_ptr)(*,coords.j,*)
    image2 = (*cube_ptr)(*,*,coords.i)
    IF self.tvscl_by_slice THEN BEGIN
       tvscl, image1, 5, 15
       tvscl, image2, 5, 315
    ENDIF ELSE BEGIN
       image1 = (!D.Table_Size-1)*(image1-minValue)/(maxValue-minValue)
       image2 = (!D.Table_Size-1)*(image2-minValue)/(maxValue-minValue)
       tv, image1, 5, 15
       tv, image2, 5, 315
    ENDELSE
    xyouts, 10, 17, string(coords.j, format='("y = ",I4)'),$
       color=[255,255,255], /device
    xyouts, 11, 18, string(coords.j, format='("y = ",I4)'),$
       color=[0,0,0], /device
    xyouts, 10, 317, string(coords.i, format='("z = ",I4)'),$
       color=[255,255,255],  /device
    xyouts, 11, 318, string(coords.i, format='("z = ",I4)'),$
       color=[0,0,0],  /device
   endif
   end

   else: begin
    ;This part of the code should never be needed.
    print, "Error: orientation variable not equal to 1, 2, or 3"
   end
endcase
END

;==================================================================
; METHODNAME:
;       sot_tab::Refresh
;
; PURPOSE:
;   For Refreshing the tab. This method is usually called upon
;   events generated by tabs in the Display Window.
;   For example, when the user selects a different tab,
;   the Refresh procedure for this tab is called.
;
;   In contrast to sot_tab::Refresh, sot_tab::Update is usually called
;   upon movie_player events like moving the slider.
;
; CALLING SEQUENCE:
;   sot_tab->Refresh
;
; OPTIONAL INPUTS:
;
; RESTRICTIONS:
;   Describe any "restrictions" here.  Delete this section if there are
;   no important restrictions.
;
; PROCEDURE:
;   You can describe the foobar superfloatation method being used here.
;   You might not need this section for your routine.
;
; EXAMPLE:
;   The following example creates a Display_Window object named DW and retrives the
;   widget ID of the Display Window using the GetProperty function of this object.
;
;   sot_tab = Obj_New("sot_tab", DW=DW)
;   sot_tab->Update
;
; MODIFICATION HISTORY:
;   Written by:  Mark Cheung, April 2003
;   April, 2003   Any additional mods get described here.  Remember to
;      change the stuff above if you add a new keyword or
;      something!

PRO sot_tab::Refresh, resize=resize

IF N_ELEMENTS(resize) EQ 0 THEN resize=0

; Error handling for all trapped errors.
Catch, theError
IF theError NE 0 THEN BEGIN
   Catch, /Cancel
   ok = Error_Message(sotback=1, /Error)
   RETURN
ENDIF

IF resize THEN BEGIN
   ;widget_control, self.drawID, draw_xsize=max([self.draw_xsize,self.tab_size[0]]),$
;	draw_ysize=max([self.draw_ysize,self.tab_size[1]]), $
;	scr_xsize=self.tab_size[0], scr_ysize=self.tab_size[1]

   widget_control, self.drawID, get_uvalue = coords
   IF self.draw_colorbar THEN BEGIN
    free_horizontal_space = self.draw_xsize-min([0.25*self.draw_xsize,100])
   ENDIF ELSE BEGIN
    free_horizontal_space = self.draw_ysize
   ENDELSE
   free_vertical_space = self.draw_ysize
   scr_aspect_ratio = float(free_vertical_space)/float(free_horizontal_space)

   self.DW->GetProperty, data_obj=data_obj, orientation=orientation
   (data_obj[self.rank])->GetProperty, cube_ptr=cube_ptr, axes_units=axes_units

  case orientation of
    1: begin
       slice_height = n_elements((*cube_ptr)[0,0,*])
       slice_width = n_elements((*cube_ptr)[*,0,0])
    end
    2: begin
       slice_height = n_elements((*cube_ptr)[0,*,0])
       slice_width = n_elements((*cube_ptr)[*,0,0])
    end
    3: begin
       slice_height = n_elements((*cube_ptr)[0,*,0])
       slice_width = n_elements((*cube_ptr)[0,0,*])
    end
   endcase
   slice_aspect_ratio = float(slice_height)/float(slice_width)

   height = round(slice_height)*self.zoom
   width  = round(slice_width)*self.zoom
   horizontal_margin = round((free_horizontal_space-width)/2.)
   vertical_margin   = round((free_vertical_space-height)/2.)
   self.active_draw_region = [60, 40,$
    60+width-1, 40+height-1];-[0.,vertical_margin/2,0.,vertical_margin/2.]

ENDIF

widget_control, self.drawID, get_value=wid
wset, wid
TVLCT, intarr(256), intarr(256), intarr(256)
IF KEYWORD_SET(resize) THEN erase, color=0

self->Update

IF self.draw_colorbar THEN BEGIN
   self.DW->GetProperty, colorbar=colorbar
   wset, wid
   colorbar->draw
ENDIF

END

PRO sot_tab::DrawPostscript

; Error handling for all trapped errors.
Catch, theError
IF theError NE 0 THEN BEGIN
   Catch, /Cancel
   ok = Error_Message(sotback=1, /Error)
   RETURN
ENDIF

; Current window, if supported.

self.DW->GetProperty, $
    red=red, green=green, blue=blue, $
    weraseit=weraseit, $
    movie_player=movie_player, $
    orientation=orientation, $
    data_obj=data_obj, $
    draw_contours=draw_contours, $
    colorbar = colorbar

(data_obj[self.rank])->GetProperty, cube_ptr=cube_ptr, axes_units=axes_units, $
    dx_vec = dx_vec
widget_control, self.drawID, get_value=wid

i0 = self.active_draw_region[0]
i1 = self.active_draw_region[2]
j0 = self.active_draw_region[1]
j1 = self.active_draw_region[3]
width  = i1-i0+1
height = j1-j0+1

IF (!D.Flags AND 256) NE 0 THEN WSet, wid

   ; Need an erase before drawing graphics?

IF weraseit THEN BEGIN
   TVLCT, intarr(256), intarr(256), intarr(256)
   erase, color=0
ENDIF

; Color protection on? Load color vectors if appropriate.
TVLCT, red, green, blue


   widget_control, movie_player, get_uvalue=movie_player_state
   widget_control, movie_player_state.frame_slider, get_value=frame_number

;TVSCL, image, horiz_margin, vert_margin, $
;    xsize=ps_x_size, ysize=ps_y_size, /device
;IF self.draw_colorbar THEN colorbar->draw

END

;==================================================================
; METHODNAME:
;       sot_tab::Update
;
; PURPOSE:
;   For updating the sot tab in the Display Window if it is currently selected
;   and some event (user-driven or not) occurs.
;
; CALLING SEQUENCE:
;   sot_tab->Update
;
; OPTIONAL INPUTS:
;
; RESTRICTIONS:
;   Describe any "restrictions" here.  Delete this section if there are
;   no important restrictions.
;
; PROCEDURE:
;   You can describe the foobar superfloatation method being used here.
;   You might not need this section for your routine.
;
; EXAMPLE:
;   The following example creates a Display_Window object named DW and retrives the
;   widget ID of the Display Window using the GetProperty function of this object.
;
;   sot_tab = Obj_New("sot_tab", DW=DW)
;   sot_tab->Update
;
; MODIFICATION HISTORY:
;   Written by:  Mark Cheung, April 2003
;   April, 2003   Any additional mods get described here.  Remember to
;      change the stuff above if you add a new keyword or
;      something!

PRO sot_tab::Update

; Error handling for all trapped errors.
Catch, theError
IF theError NE 0 THEN BEGIN
   Catch, /Cancel
   ok = Error_Message(sotback=1, /Error)
   RETURN
ENDIF

; Current window, if supported.
self.DW->GetProperty, $
    red=red, green=green, blue=blue, $
    weraseit=weraseit, $
    movie_player=movie_player, $
    orientation=orientation, $
    data_obj=data_obj, $
    draw_contours=draw_contours, $
    colorbar = colorbar

    
(data_obj[self.rank])->GetProperty, cube_ptr=cube_ptr, $
    dx_vec=dx_vec, axes_units=axes_units, $
    minValue=minValue, maxValue=maxValue, colormin=colormin, colormax=colormax


widget_control, self.drawID, get_value=wid

i0 = self.active_draw_region[0]
j0 = self.active_draw_region[1]
IF (!D.Flags AND 256) NE 0 THEN WSet, wid

   ; Need an erase before drawing graphics?

; Color protection on? Load color vectors if appropriate.
TVLCT, red, green, blue


wset, wid

widget_control, movie_player, get_uvalue=movie_player_state
widget_control, movie_player_state.frame_slider, get_value=frame_number

   case orientation of
    1: begin ; x-z orientation
	width=N_ELEMENTS(((*cube_ptr)[*,0,0]))*self.zoom
	height=N_ELEMENTS(((*cube_ptr)[0,0,*]))*self.zoom
	i1=i0+width-1
	j1=j0+height-1
        slice_width = n_elements((*cube_ptr)(*,0,0))
        slice_height = n_elements((*cube_ptr)(0,0,*))
        aspect_ratio = slice_width/slice_height
        image = (*cube_ptr)(*,frame_number,*)
        IF self.zoom NE 1 THEN image = congrid(reform(image), round(width), round(height) )
       ;image = interpolate(image, width_interpol, height_interpol, /grid)

    end

    2: begin ; x-y orientation
       ;stop
       widget_control, movie_player_state.status_text, set_value=string((data_obj[self.rank])->axis('z',index=frame_number))
       slice_width = n_elements((*cube_ptr)(*,0,0))
       slice_height = n_elements((*cube_ptr)(0,*,0))
       width=slice_width*self.zoom
       height=slice_height*self.zoom
       i1=i0+width-1
       j1=j0+height-1
       image = (*cube_ptr)(*,*,frame_number)
       ;(data_obj[1])->GetProperty, cube_ptr=over_cube_ptr, colormin=overcolormin, colormax=overcolormax
       ;overimage = (*over_cube_ptr)(*,*,frame_number)
       IF self.zoom NE 1 THEN image = congrid(reform(image), round(width), round(height) )
    end

    3: begin ; z-y orientation
	width=N_ELEMENTS(((*cube_ptr)[0,0,*]))*self.zoom
	height=N_ELEMENTS(((*cube_ptr)[0,*,0]))*self.zoom
	i1=i0+width-1
	j1=j0+height-1
       slice_width = n_elements((*cube_ptr)(0,0,*))
       slice_height = n_elements((*cube_ptr)(0,*,0))
       image = reform((*cube_ptr)(frame_number,*,*), slice_height, slice_width)
       IF self.zoom NE 1 THEN image = congrid(transpose(reform(image)), round(width), round(height) )
    end
   endcase


;=============DRAW AXES OVERLAYS WHEN THE USER DESIRES===========
   IF self.draw_axes_labels AND (orientation EQ 2) THEN BEGIN

    case orientation of
       1: begin
;        image2 = reform((*cube_ptr)(*,frame_number,*))
;        horiz_max = n_elements(image2(*,0))
;        vert_max = n_elements(image2(0,*))
;        xtitle = 'x ('+axes_units[0]+')'
;        ytitle = 'z ('+axes_units[2]+')'
;        stop
;        x_axis = reform(((data_obj[self.rank])->axis('x'))[frame_number,*])
;        y_axis = (data_obj[self.rank])->axis('z')
;        z_axis = reform(((data_obj[self.rank])->axis('y'))[frame_number,*])
;        stop
       end
       2: begin
       image2 =  reform((*cube_ptr)(*,*,frame_number))
       horiz_max = n_elements(image2(*,0))
       vert_max = n_elements(image2(0,*))
       xtitle = 'x ('+axes_units[0]+')'
       ytitle = 'y ('+axes_units[1]+')'
       x_axis = reform(((data_obj[self.rank])->axis('x'))[*,frame_number])
       y_axis = reform(((data_obj[self.rank])->axis('y'))[*,frame_number])
       z_axis = (data_obj[self.rank])->axis('z')
       end
       3: begin
;        image2 = transpose(reform((*cube_ptr)(frame_number,*,*)))
;        horiz_max = n_elements(image2(*,0))
;        vert_max = n_elements(image2(0,*))
;        xtitle = 't ('+axes_units[2]+')'
;        ytitle = 'z ('+axes_units[1]+')'
;        x_axis = reform(((data_obj[self.rank])->axis('y'))[*,frame_number])
;        y_axis = (data_obj[self.rank])->axis('z')
;        z_axis = reform(((data_obj[self.rank])->axis('x'))[*,frame_number])
       end
    endcase
    ; Force color table to give black bg and white annotations
    TVLCT, red, green, blue, /Get
        white_table = intarr(256)
    white_table[255] = 255
    white_table[0:254] = 0
    TVLCT, white_table, white_table, white_table
    !P.position=[0,0,0,0]
    !P.multi=[0,1,1]
    !P.position=[i0,j0,i1,j1]
    contour,  image2, x_axis, y_axis, /device, position=[i0,j0,i1,j1], xstyle=1, ystyle=1, xtitle=xtitle, ytitle=ytitle, ticklen=-0.005, /nodata

    ;============Restore original colortable===============
    TVLCT, red, green, blue

   ENDIF

CASE self.tvscl_by_slice OF
   0: BEGIN
      ; Scale image by global max and and min
      image = (!D.Table_Size-1)*(image-minValue)/(maxValue-minValue)
      colorbar->SetProperty, Range=[minValue, maxValue]
      IF self.draw_colorbar THEN BEGIN
	erase
	colorbar->draw
      ENDIF
      TV, image, i0, j0, xsize=i1-i0, ysize=j1-j0
   ENDCASE
   1: BEGIN
      ; Scale image by max and min specific to this 2D slice.
      IF (self.draw_colorbar) OR (self.draw_axes_labels) THEN Erase
      colorbar->SetProperty, Range=[min(image), max(image)]
      TVSCL, image, i0, j0, xsize=i1-i0, ysize=j1-j0
      IF self.draw_colorbar THEN colorbar->draw
   ENDCASE
   2: BEGIN
      ; Scale image by user specified range
      IF (self.draw_colorbar) AND (self.draw_axes_labels) THEN Erase
      (data_obj[self.rank])->GetProperty, colormin=colormin, colormax=colormax
      image    = bytscl(image,min=(colormin), max=(colormax))
      colorbar->SetProperty, Range=[colormin, colormax]
      TV, image, i0, j0, xsize=i1-i0, ysize=j1-j0
      IF self.draw_colorbar THEN colorbar->draw
   ENDCASE
ENDCASE



;===========Optionally, draw profiles for other orientations========
IF widget_info(self.profiles_window, /valid_id) THEN BEGIN
   self->draw_profiles
ENDIF

;===========Optionally, draw profiles for other orientations========
IF widget_info(self.line_profile_window, /valid_id) THEN BEGIN
   self->draw_line_profile
ENDIF


END

; METHODNAME:
;       sot_tab::SetProperty
;
; PURPOSE:
;   For modifying the attributes of a sot_tab class object
;
; CALLING SEQUENCE:
;   sot_tab = Obj_New("sot_tab", DW=DW)
;   sot_tab->SetProperty, plugin_name=plugin_name
;
; OPTIONAL INPUTS:
;   plugin_name : The name of this plugin
;   profiles_window: The widget ID of the any profiles window associated
;   with this sot tab.
;
; RESTRICTIONS:
;   Describe any "restrictions" here.  Delete this section if there are
;   no important restrictions.
;
; PROCEDURE:
;   You can describe the foobar superfloatation method being used here.
;   You might not need this section for your routine.
;
; EXAMPLE:
;   The following example creates a Display_Window object named DW and retrives the
;   widget ID of the Display Window using the GetProperty function of this object.
;
;   sot_tab = Obj_New("sot_tab", DW=DW)
;   sot_tab->SetProperty, plugin_name="New sot Tab"
;
; MODIFICATION HISTORY:
;   Written by:  Mark Cheung, April 2003
;   April, 2003   Any additional mods get described here.  Remember to
;      change the stuff above if you add a new keyword or
;      something!

PRO sot_tab::SetProperty, $
    plugin_name = plugin_name, $
    profiles_window = profiles_window, $
    line_profile_window = line_profile_window,$
    profiles_orientation = profiles_orientation, $
    active_draw_region = active_draw_region, $
    draw_canvas_size = draw_canvas_size, $
    draw_colorbar = draw_colorbar, $
    draw_axes_labels = draw_axes_labels, $
    tvscl_by_slice = tvscl_by_slice, $
    blur_or_not = blur_or_not, $
    range_settings_window=range_settings_window, $
    tab_size=tab_size, draw_xsize=draw_xsize, draw_ysize=draw_ysize, zoom=zoom

;Error Handling
Catch, theError
IF theError NE 0 THEN BEGIN
   Catch, Cancel=1
   ok = Dialog_Message('Error in SetProperty Method. Returning...')
   Print, ''
   Print, 'sot_tab::SetProperty Method: ' + !Error_State.Msg
ENDIF

IF N_ELEMENTS(plugin_name) NE 0 THEN self.plugin_name=plugin_name
IF N_ELEMENTS(profiles_window) NE 0 THEN self.profiles_window=profiles_window
IF N_ELEMENTS(profiles_orientation) NE 0 THEN self.profiles_orientation=profiles_orientation
IF N_ELEMENTS(active_draw_region) NE 0 THEN self.active_draw_region=active_draw_region
IF N_ELEMENTS(draw_canvas_size) NE 0 THEN self.draw_canvas_size=draw_canvas_size
IF N_ELEMENTS(draw_colorbar) NE 0 THEN self.draw_colorbar=draw_colorbar
IF N_ELEMENTS(draw_axes_labels) NE 0 THEN self.draw_axes_labels=draw_axes_labels
IF N_ELEMENTS(tvscl_by_slice) NE 0 THEN self.tvscl_by_slice=tvscl_by_slice
IF N_ELEMENTS(line_profile_window) NE 0 THEN self.line_profile_window = line_profile_window
IF N_ELEMENTS(blur_or_not) NE 0 THEN self.blur_or_not = blur_or_not
IF N_ELEMENTS(range_settings_window) NE 0 THEN self.range_settings_window=range_settings_window
IF N_ELEMENTS(tab_size) EQ 2 THEN self.tab_size=tab_size
IF N_ELEMENTS(draw_xsize) NE 0 THEN self.draw_xsize=draw_xsize
IF N_ELEMENTS(draw_ysize) NE 0 THEN self.draw_ysize=draw_ysize
IF N_ELEMENTS(zoom) NE 0 THEN self.zoom=zoom


END

; METHODNAME:
;       sot_tab::GetProperty
;
; PURPOSE:
;   For the retrieval of information about the sot_tab object
;
; CALLING SEQUENCE:
;   sot_tab = Obj_New("sot_tab", DW=DW)
;   sot_tab->GetProperty, plugin_name=plugin_name, ...
;
; OPTIONAL INPUTS:
;   plugin_name : Returns the name of this plugin
;   tab_ID: Returns the widget ID of the tab associated with this plugin
;   drawID: Returns the widget ID of the draw widget contained in the sot tab.
;   DW : Returns an object pointer to the Display Window object to which
;     this plugin is attached.
;
; RESTRICTIONS:
;   Describe any "restrictions" here.  Delete this section if there are
;   no important restrictions.
;
; PROCEDURE:
;   You can describe the foobar superfloatation method being used here.
;   You might not need this section for your routine.
;
; EXAMPLE:
;   The following example creates a Display_Window object named DW and retrives the
;   widget ID of the Display Window using the GetProperty function of this object.
;
;   sot_tab = Obj_New("sot_tab", DW=DW)
;   sot_tab->GetProperty, tab_ID=tab_ID, plugin_name=name
;
; MODIFICATION HISTORY:
;   Written by:  Mark Cheung, April 2003
;   April, 2003   Any additional mods get described here.  Remember to
;      change the stuff above if you add a new keyword or
;      something!

PRO sot_tab::GetProperty, $
    plugin_name = plugin_name, $
    tab_ID = tab_ID, $
    DW = DW, $
    drawID = drawID, $
    profiles_menu = profiles_menu, $
    profileID = profileID, $
    profiles_window = profiles_window, $
    line_profile_window = line_profile_window, $
    profiles_orientation = profiles_orientation, $
    active_draw_region = active_draw_region, $
    draw_canvas_size = draw_canvas_size, $
    context_menu = context_menu, $
    draw_colorbar = draw_colorbar, $
    draw_axes_labels = draw_axes_labels, $
    tvscl_by_slice = tvscl_by_slice, $
    blur_or_not = blur_or_not, $
    psf = psf, data_obj=data_obj,$
    range_settings_window=range_settings_window, $
    tab_size=tab_size, draw_xsize=draw_xsize, draw_ysize=draw_ysize, zoom=zoom, rank=rank

;Error Handling
Catch, theError
IF theError NE 0 THEN BEGIN
   Catch, Cancel=1
   ok = Dialog_Message('Error in GetProperty Method. Returning...')
   Print, ''
   Print, 'sot_tab::GetProperty Method: ' + !Error_State.Msg
ENDIF

plugin_name = self.plugin_name
tab_ID = self.tab_ID
DW = self.DW
drawID = self.drawID
profiles_menu = self.profiles_menu
profileID = self.profileID
profiles_window = self.profiles_window
line_profile_window = self.line_profile_window
profiles_orientation = self.profiles_orientation
active_draw_region = self.active_draw_region
draw_canvas_size = self.draw_canvas_size
context_menu = self.context_menu
draw_colorbar = self.draw_colorbar
draw_axes_labels = self.draw_axes_labels
tvscl_by_slice = self.tvscl_by_slice
blur_or_not = self.blur_or_not
psf    = self.psf
range_settings_window=self.range_settings_window
tab_size=self.tab_size
draw_xsize=self.draw_xsize
draw_ysize=self.draw_ysize
zoom = self.zoom
data_obj=self.data_obj
rank    = self.rank
END

; METHODNAME:
;       sot_tab::Init
;
; PURPOSE:
;   For the creation of a the sot_tab plugin and it's tab in a Display Window
;
; CALLING SEQUENCE:
;   sot_tab = Obj_New("sot_tab", DW=DW)
;
; INPUTS:
;   DW: The Display Window Object to which this plugin is attached.
;
; OPTIONAL INPUTS:
;
; KEYWORD PARAMETERS:
;   KEY1: Document keyword parameters like this. Note that the keyword
;     is shown in ALL CAPS!
;
; OPTIONAL OUTPUTS:
;   Describe optional outputs here.  If the routine doesn't have any,
;   just delete this section.
;
; COMMON BLOCKS:
;   BLOCK1:   Describe any common blocks here. If there are no COMMON
;     blocks, just delete this entry. Object methods probably
;               won't be using COMMON blocks.
;
; SIDE EFFECTS:
;   Describe "side effects" here.  There aren't any?  Well, just delete
;   this entry.
;
; RESTRICTIONS:
;   Describe any "restrictions" here.  Delete this section if there are
;   no important restrictions.
;
; PROCEDURE:
;   You can describe the foobar superfloatation method being used here.
;   You might not need this section for your routine.
;
; EXAMPLE:
;   The following example creates a Display_Window object named DW and retrives the
;   widget ID of the Display Window using the GetProperty function of this object.
;
;   sot_tab = Obj_New("sot_tab", DW=DW)
;
; MODIFICATION HISTORY:
;   Written by:  Mark Cheung, April 2003
;   April, 2003   Any additional mods get described here.  Remember to
;      change the stuff above if you add a new keyword or
;      something!

FUNCTION sot_tab::INIT, $
    DW=DW, rank=rank

;Error Handling
Catch, theError
IF theError NE 0 THEN BEGIN
   Catch, Cancel=1
   ok = Dialog_Message('Error in INIT Method. Returning...')
   Print, ''
   Print, 'data_set::INIT Method: ' + !Error_State.Msg
   RETURN, 0
ENDIF

IF N_ELEMENTS(tab_ID) EQ 0 THEN tab_ID=0L
IF N_ELEMENTS(profiles_window) EQ 0 THEN profiles_window=0L
IF N_ELEMENTS(line_profile_window) EQ 0 THEN line_profile_window=0L
IF N_ELEMENTS(profiles_orientation) EQ 0 THEN profiles_orientation=1
IF N_ELEMENTS(active_draw_region) EQ 0 THEN active_draw_region=[20,20,307,307]
IF N_ELEMENTS(draw_colorbar) EQ 0 THEN draw_colorbar = 0
IF N_ELEMENTS(draw_axes_labels) EQ 0 THEN draw_axes_labels = 0
IF N_ELEMENTS(tvscl_by_slice) EQ 0 THEN tvscl_by_slice = 0
IF N_ELEMENTS(rank) EQ 0 THEN rank=0

self.zoom=1l

;=====================sot tab widget========================
DW->GetProperty, xsize=xsize, $
    ysize=ysize, $
    DW_ID=DW_ID, $
    DW_tabs=DW_tabs, $
    mbarID=mbarID, data_obj=data_obj
(data_obj[rank])->GetProperty, variable_name=variable_name, cube_size=cube_size
sot_tab = widget_base(title=variable_name, DW_tabs, xsize=xsize, $
    ysize=ysize-100, xoffset=0, yoffset=0, /context_events)

sot_tab_context_menu = widget_base(sot_tab, /context_menu)
self.context_menu = sot_tab_context_menu

drawID_state = {i:0,j:0,i0:0,j0:0,i1:0,j1:0,x0:0,y0:0,x1:0,y1:0}
; i and j are current positions of the cursor in "cube index units"
; (i0,j0) and (i1,j1) are points defining the plane for custom profile
; (x0,y0) and (x1,y1) are (i0,j0) and (i1,j1) in sot coordinates
; in the draw widget.
;stop
drawID = Widget_Draw(sot_tab, xoffset=0, yoffset=0, $
     uvalue=drawID_state, event_pro='sot_cursor_events',$
     /button_events, /keyboard_events, /scroll, xsize=max([cube_size[0]+2*60,xsize]), ysize=cube_size[1]+2*40,$
     x_scroll_Size=xsize, Y_scroll_Size=ysize-100)

self.draw_canvas_size = [xsize,ysize]
self.tab_size         = [xsize,ysize-100]

sot_tab_state = {sot_tab:sot_tab, drawID:drawID, tab_object:self}
widget_control, sot_tab, set_uvalue = sot_tab_state

Hide_Colorbar = widget_button(sot_tab_context_menu, value='Show Colorbar',$
     event_pro='sot_profiles_menu_events')
draw_axes_button = widget_button(sot_tab_context_menu, value='Draw Axes Labels',$
     event_pro='sot_profiles_menu_events')
color_table_by_slice_button = widget_button(sot_tab_context_menu, value='Scale colors to slice extrema',$
     event_pro='sot_profiles_menu_events', /separator)
color_table_by_cube_button = widget_button(sot_tab_context_menu, value='Scale colors to cube extrema',$
     event_pro='sot_profiles_menu_events')
color_table_custom_button = widget_button(sot_tab_context_menu, value='Scale colors to range:',$
     event_pro='sot_profiles_menu_events')
color_table_equalize_button = widget_button(sot_tab_context_menu, value='Scale by percentile: ',$
     event_pro='sot_profiles_menu_events' ,/menu)
color_table_ninetyninenine_button = widget_button(color_table_equalize_button, $
	value="middle 99.9%", event_pro='sot_profiles_menu_events')
color_table_ninetynine_button = widget_button(color_table_equalize_button, $
	value="middle 99%", event_pro='sot_profiles_menu_events')
color_table_ninetyfive_button = widget_button(color_table_equalize_button, $
	value="middle 95%", event_pro='sot_profiles_menu_events')
color_table_lower_10_button = widget_button(color_table_equalize_button, $
	value="lower 40%", event_pro='sot_profiles_menu_events')
color_table_upper_10_button = widget_button(color_table_equalize_button, $
	value="upper 40%", event_pro='sot_profiles_menu_events')
one_dim_profile = widget_button(sot_tab_context_menu, value='Line Profile',$
     event_pro='sot_profiles_menu_events',/separator)
profileID=one_dim_profile
zoom_in_button = widget_button(sot_tab_context_menu, value='Zoom in',$
     event_pro='sot_profiles_menu_events')
zoom_out_button = widget_button(sot_tab_context_menu, value='Zoom out',$
     event_pro='sot_profiles_menu_events')
zoom_fit_button = widget_button(sot_tab_context_menu, value='Zoom to fit window',$
     event_pro='sot_profiles_menu_events')
zoom_fit_button = widget_button(sot_tab_context_menu, value='Zoom 1x',$
     event_pro='sot_profiles_menu_events')
heliokb_button = widget_button(sot_tab_context_menu, value='HelioKB reporter',$
     event_pro='sot_profiles_menu_events',/separator)
zoom_view_button = widget_button(sot_tab_context_menu, value='Zoom view of bounded region',$
     event_pro='sot_profiles_menu_events',/separator)

profileID_state = {profiles_menu:sot_tab_context_menu, profileID:profileID, sot_tab_obj:self}
widget_control, profileID, set_uvalue = profileID_state
widget_control, sot_tab_context_menu, set_uvalue = profileID_state
widget_control, color_table_equalize_button, set_uvalue = profileID_state
self.profileID = profileID
self.plugin_name='SOT Tab'
self.drawID = drawID
self.tab_ID = sot_tab
self.DW = DW
self.active_draw_region=active_draw_region
self.context_menu = sot_tab_context_menu
self.draw_colorbar = draw_colorbar
self.draw_axes_labels = draw_axes_labels
self.tvscl_by_slice = tvscl_by_slice
self.line_profile_window = 0L
self.blur_or_not = 0L
self.draw_xsize = self.tab_size[0]
self.draw_ysize = self.tab_size[1]
self.rank = rank
self.data_obj = data_obj[self.rank] ; data_obj is pointer to data obj, which is carried by the Display Window. 


widget_control, sot_tab, set_uvalue=self

RETURN, 1
END

PRO sot_tab__define

struct = {sot_tab, $
    drawID:0L, $                   ; The widget ID of the draw area
    profiles_menu:0L, $            ; The widget ID of the profiles menu
    profileID:0L, $                ; The widget ID of the profiles menu button
    profiles_window:0L, $          ; The widget ID of the 2D profiles window
    line_profile_window:0L, $      ; The widget ID of the line profile window
    profiles_orientation:0, $      ; The orientation of 2D profiles
    draw_canvas_size:intarr(2), $  ; The [width,height] of the draw widget with ID=drawID
    active_draw_region:intarr(4), $ ; The region [i0,j0,i1,j1] on the draw canvas used for displaying the 2D slice
    draw_colorbar:0, $     ; Draw color bar?
    draw_axes_labels:0, $   ; Draw axes labels?
    range_settings_window:0, $ ; Widget ID of window for setting colorbar range
    tvscl_by_slice:0, $       ; Whether to show each 2D slice scaled with slice (min,max) or global (min,max)
    blur_or_not:0L, $	    ; Blur image?
    psf:fltarr(41,41), $    ; Point spread function
    draw_xsize:640l, $      ; Drawing area size in pixels (includes scroll)
    draw_ysize:640l, $      ; Drawing area size in pixels (includes scroll)
    zoom:1., $		    ; Zoom factor
    rank:0l,$		    ; Rank within Display Window. Determines which data_obj to access.
    data_obj:obj_new(), $   ; Data_obj
    INHERITS plugin $
    }
END
