; Copyright (c) 2003, Max Planck Institute for Aeronomy
;   Unauthorized reproduction prohibited.
;+
; CLASS_NAME:
;   pdf_tab__define
;
; PURPOSE:
;   This defines the pdf_tab plugin module for the GUI tool.
;
; 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 pdf_tab object.
;
; MODIFICATION HISTORY:
;   Written by:  Mark Cheung, April 2003.
;      Any additional mods get described here.  Remember to
;      change the stuff above if you add a new keyword or
;      something!

;=============Event Handler for this tab========================
PRO pdf_context_menu_events, event

   widget_control, widget_info(event.id, /parent), get_uvalue=context_menu_state
   pdf_tab_obj = context_menu_state.pdf_tab_obj
   pdf_tab_obj->GetProperty, pdf_settings_window=pdf_settings_window, DW=DW
   DW->GetProperty, DW_ID=DW_ID, data_obj=data_obj
   widget_control, event.id, get_uvalue=button_rank
   pdf_tab_obj->SetProperty, rank=button_rank
   pdf_tab_obj->Refresh
   END

PRO pdf_settings_window_events, event

;=========Retrive Information about Settings Window==========
pdf_settings_window = event.top
widget_control, pdf_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 pdf Tab Plugin=====
       widget_control, info.ax_slider, get_value=ax
       widget_control, info.az_slider, get_value=az
       info.pdf_tab_obj->SetProperty, ax=ax, az=az
       info.pdf_tab_obj->Update
    ENDCASE

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

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

;============The following code handles slider events============
IF (TAG_NAMES(event, /STRUCTURE_NAME) EQ 'WIDGET_SLIDER') THEN BEGIN
   widget_control, info.ax_slider, get_value=ax
   widget_control, info.az_slider, get_value=az
   info.pdf_tab_obj->SetProperty, ax=ax, az=az
   info.pdf_tab_obj->Update
ENDIF

END

PRO pdf_settings_window_cleanup, pdf_settings_window

   widget_control, pdf_settings_window, get_uvalue = info
   info.pdf_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.pdf_tab_obj->SetProperty, pdf_settings_window = 0L
   widget_control, pdf_settings_window, /destroy

END

PRO pdf_tab_events, event
   widget_control, widget_info(event.id, /parent), get_uvalue = pdf_tab_obj
   pdf_tab_obj->GetProperty, context_menu = context_menu

  IF (TAG_NAMES(EVENT, /STRUCTURE_NAME) EQ "WIDGET_DRAW") THEN BEGIN
    IF (event.release EQ 4) THEN BEGIN
       WIDGET_DISPLAYCONTEXTMENU, EVENT.ID, event.x, event.y, context_menu
    ENDIF
   ENDIF
END

PRO pdf_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(Traceback=1, /Error)
   RETURN
ENDIF

IF resize THEN BEGIN
   widget_control, self.drawID, XSize=self.tab_size[0], YSize=self.tab_size[1]
   free_horizontal_space = self.tab_size[0]
   free_vertical_space = self.tab_size[1]
   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

  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)
   IF (slice_aspect_ratio GT scr_aspect_ratio) THEN BEGIN
    height = 0.7*free_vertical_space
    width = height/slice_aspect_ratio
   ENDIF ELSE BEGIN
    width = 0.7*free_horizontal_space
    height = width*slice_aspect_ratio
   ENDELSE

   height = round(height)
   width = round(width)
   horizontal_margin = round((free_horizontal_space-width)/2.)
   vertical_margin = round((free_vertical_space-height)/2.)
   self.active_draw_region = [horizontal_margin, vertical_margin,$
    horizontal_margin+width, vertical_margin+height]

ENDIF
self->Update

END

PRO pdf_tab::DrawPostscript

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

    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

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

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

   ;Get the frame number from the slider in the movie player module.
   widget_control, movie_player, get_uvalue = movie_player_state
   widget_control, movie_player_state.frame_slider, get_value=frame_number

   levels = *(self.contour_levels_ptr)

    case orientation of
       1: begin
       image = reform((*cube_ptr)(*,frame_number,*))
       horiz_max = n_elements(image(*,0))
       vert_max = n_elements(image(0,*))
       xtitle = 'x ('+axes_units[0]+')'
       ytitle = 'z ('+axes_units[2]+')'
       x_axis = findgen(horiz_max)*dx_vec[0]
       y_axis = findgen(vert_max)*dx_vec[2]
       end
       2: begin
       image =  reform((*cube_ptr)(*,*,frame_number))
       horiz_max = n_elements(image(*,0))
       vert_max = n_elements(image(0,*))
       xtitle = 'x ('+axes_units[0]+')'
       ytitle = 'y ('+axes_units[1]+')'
       x_axis = findgen(horiz_max)*dx_vec[0]
       y_axis = findgen(vert_max)*dx_vec[1]
       end
       3: begin
       image = transpose(reform((*cube_ptr)(frame_number,*,*)))
       horiz_max = n_elements(image(*,0))
       vert_max = n_elements(image(0,*))
       xtitle = 'z ('+axes_units[2]+')'
       ytitle = 'y ('+axes_units[1]+')'
       x_axis = findgen(horiz_max)*dx_vec[2]
       y_axis = findgen(vert_max)*dx_vec[1]
       end
    endcase


free_horiz_space = !D.X_SIZE
free_vert_space = !D.Y_SIZE

ps_aspect_ratio = float(free_vert_space)/float(free_horiz_space)
slice_aspect_ratio = float(vert_max)/float(horiz_max)

IF (slice_aspect_ratio GT ps_aspect_ratio) THEN BEGIN
   ps_y_size = 0.75*free_vert_space
   ps_x_size = ps_y_size/slice_aspect_ratio
ENDIF ELSE BEGIN
   ps_x_size = 0.75*free_horiz_space
   ps_y_size = ps_x_size*slice_aspect_ratio
ENDELSE

vert_margin = (free_vert_space - ps_y_size)/2.
horiz_margin = (free_horiz_space - ps_x_size)/2.

position = [horiz_margin, vert_margin, horiz_margin+ps_x_size, $
   vert_margin+ps_y_size]

;========Draw on Postscript=========
contour, image, x_axis, y_axis, c_colors=(levels-minValue)/(maxValue-minValue)*255, $
   color=!P.color, position=position, /device, $
   xstyle=1, ystyle=1, levels=levels


END

;==================================================================
; METHODNAME:
;       pdf_tab::Update
;
; PURPOSE:
;   For updating the pdf tab in the Display Window if it is currently selected
;   and some event (user-driven or not) occurs.
;
; CALLING SEQUENCE:
;   pdf_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.
;
;   pdf_tab = Obj_New("pdf_tab", DW=DW)
;   pdf_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 pdf_tab::Update

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

    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

widget_control, self.drawID, get_value=wid

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

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

   data_obj[self.rank]->GetProperty, cube_ptr=cube_ptr, dx_vec=dx_vec, $
    minValue = minValue, maxValue = maxValue, axes_units=axes_units, $
    variable_name = variable_name, unit = unit

   widget_control, self.drawID, get_value = wid

   ;Get the frame number from the slider in the movie player module.
   widget_control, movie_player, get_uvalue = movie_player_state
   widget_control, movie_player_state.frame_slider, get_value=frame_number

   levels = *(self.contour_levels_ptr)

    case orientation of
       1: begin
       image = reform((*cube_ptr)(*,frame_number,*))
       end
       2: begin
       image =  reform((*cube_ptr)(*,*,frame_number))
       end
       3: begin
       image = reform((*cube_ptr)(frame_number,*,*))
       end
    endcase

    ytitle = "Probability"
    xtitle = variable_name 

    bins = minValue+findgen(30)*(maxValue-minValue)/30.0
    pdf  = 1.0*histogram(image, nbins=30, max=maxValue, min=minValue)/(1.0*N_ELEMENTS(image))

   ;=========Draw on X device==========
   wset, wid
   position=[80,50,self.tab_size[0]-50,self.tab_size[1]-30]
   plot, bins, pdf,$
    xtitle=xtitle, ytitle=ytitle, psym=10, /ylog, yrange=[1.0/N_ELEMENTS(image),1.0], /device,$
	 position=position, charsize=1.5

END

; METHODNAME:
;       pdf_tab::SetProperty
;
; PURPOSE:
;   For modifying the attributes of a pdf_tab class object
;
; CALLING SEQUENCE:
;   pdf_tab = Obj_New("pdf_tab", DW=DW)
;   pdf_tab->SetProperty, plugin_name=plugin_name
;
; 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.
;
;   pdf_tab = Obj_New("pdf_tab", DW=DW)
;   pdf_tab->SetProperty, plugin_name="New Pixel 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 pdf_tab::SetProperty, $
    plugin_name = plugin_name, $
    active_draw_region = active_draw_region, $
    draw_canvas_size = draw_canvas_size, $
    pdf_settings_window = pdf_settings_window, $
    contour_levels_ptr = contour_levels_ptr, $
    rank = rank

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

IF N_ELEMENTS(plugin_name) NE 0 THEN self.plugin_name=plugin_name
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(pdf_settings_window) NE 0 THEN self.pdf_settings_window=pdf_settings_window
IF N_ELEMENTS(contour_levels_ptr) NE 0 THEN self.contour_levels_ptr=contour_levels_ptr
IF N_ELEMENTS(rank) NE 0 THEN self.rank=rank

END

; METHODNAME:
;       pdf_tab::GetProperty
;
; PURPOSE:
;   For the retrieval of information about the pdf_tab object
;
; CALLING SEQUENCE:
;   pdf_tab = Obj_New("pdf_tab", DW=DW)
;   pdf_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 pdf 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.
;
;   pdf_tab = Obj_New("pdf_tab", DW=DW)
;   pdf_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 pdf_tab::GetProperty, $
    plugin_name = plugin_name, $
    tab_ID = tab_ID, $
    DW = DW, $
    drawID = drawID, $
    draw_canvas_size = draw_canvas_size, $
    active_draw_region = active_draw_region, $
    pdf_settings_window = pdf_settings_window, $
    context_menu = context_menu, $
    contour_levels_ptr = contour_levels_ptr, $
    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, 'pdf_tab::GetProperty Method: ' + !Error_State.Msg
ENDIF

plugin_name = self.plugin_name
tab_ID = self.tab_ID
DW = self.DW
drawID = self.drawID
draw_canvas_size = self.draw_canvas_size
active_draw_region = self.active_draw_region
pdf_settings_window = self.pdf_settings_window
context_menu = self.context_menu
contour_levels_ptr = self.contour_levels_ptr
rank = self.rank
END

; METHODNAME:
;       pdf_tab::Init
;
; PURPOSE:
;   For the creation of a the pdf_tab plugin and it's tab in a Display Window
;
; CALLING SEQUENCE:
;   pdf_tab = Obj_New("pdf_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.
;
;   pdf_tab = Obj_New("pdf_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 pdf_tab::INIT, $
    DW=DW, $
    active_draw_region=active_draw_region

;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(active_draw_region) EQ 0 THEN active_draw_region=[20,20,307,307]
IF N_ELEMENTS(ax) EQ 0 THEN ax=30.
IF N_ELEMENTS(az) EQ 0 THEN az=30.

;=====Pixel tab widget=================================
DW->GetProperty, xsize=xsize, $
    ysize=ysize, $
    DW_ID=DW_ID, $
    DW_tabs=DW_tabs, $
    data_obj=data_obj

pdf_tab = widget_base(DW_tabs, Title="PDF", xsize = xsize, ysize=ysize, $
   /context_events, event_pro="pdf_tab_events")
pdf_draw = widget_draw(pdf_tab, xsize=xsize, ysize=ysize, /button_events, $
   event_pro="pdf_tab_events")

;==============Context Menu for pdf Tab Plugin======================
context_menu = widget_base(pdf_tab, /context_menu)
buttons=lonarr(4)
FOR I=0,3 DO BEGIN
   IF data_obj[I] NE Obj_New() THEN BEGIN
	data_obj[I]->GetProperty, variable_name=variable_name
	buttons[I] = widget_button(context_menu, value=variable_name, $
		   event_pro="pdf_context_menu_events", xsize=80, uvalue=I)
   ENDIF
ENDFOR
context_menu_state = {pdf_tab_obj:self, context_menu:context_menu, buttons:buttons}
widget_control, context_menu, set_uvalue=context_menu_state

widget_control, pdf_draw, get_value = pdf_wid
pdf_tab_state = {pdf_tab:pdf_tab, drawID:pdf_draw, context_menu:context_menu}

;============Initialize contour levels=======================
DW->GetProperty, data_obj = data_obj
data_obj[self.rank]->GetProperty, minValue=minValue, maxValue=maxValue
contour_levels = minValue + (maxValue-minValue)*[0.0, 0.2, 0.4, 0.6, 0.8, 1.0]
self.draw_canvas_size = [xsize,ysize-150]
self.tab_size = [xsize,ysize-150]
self.plugin_name='Pdf Tab'
self.drawID = pdf_draw
self.tab_ID = pdf_tab
self.DW = DW
self.active_draw_region = active_draw_region
self.context_menu = context_menu
self.pdf_settings_window = 0L
self.contour_levels_ptr = Ptr_New(contour_levels)
self.ax = ax
self.az = az

widget_control, self.tab_ID, set_uvalue = self
RETURN, 1
END

PRO pdf_tab__define

struct = {pdf_tab, $
    drawID:0L, $      ; The widget ID of the draw canvas
    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
    pdf_settings_window:0L, $   ; Widget ID for Settings Window
    ;draw_colorbar:0, $       ; whether to draw colorbar
    contour_levels_ptr:Ptr_New(), $    ; Pointer to array specifying contour levels
    rank:0l,$      ; Rank
    ax: 0, $      ; Angle from x-axis}used as parameters in shade_surf
    az: 0, $      ; Angle from z-axis}
    INHERITS plugin $
    }
END
