;+
; Project     : SOHO - CDS     
;                   
; Name        : CWQ_IMAGE
;               
; Purpose     : QuickLook compound widget for zoomabel images.
;               
; Explanation : This compound widget displays what is seen in the top/left
;               panel of the data display "columns" of DSPWAV.
;
;               Given a QLDS with a rastered area, the variables WINDOWI and
;               OFFSET uniquely define a rastered image that can be extracted
;               from the QLDS. This compound widget displays such images, but
;               it needs to be told about the QLDS on creation, and the
;               WINDOWI/OFFSET (both default to zero). When realized, it
;               displays the image with a focus point at a given XIX/YIX (also
;               defaulting to zero). This may be taken as the point at which
;               to extract e.g., a spectrum with gt_spectrum().
;
;               The image is displayed by using a CW_PZOOM compound widget, so
;               the user may zoom in and out of the image, and alter the focus
;               point. It is possible to use this compound widget in an
;               "autonomous" mode that will never generate events.
;
;               CHANGING STATUS VARIABLES
;
;               The status variables WINDOWI/OFFSET/XIX/YIX/TIX may be changed
;               through the mechanism
;
;                   WIDGET_CONTROL,CWQ_IMAGE_ID,SET_VALUE={<PARAMETER>:VALUE}
;
;               where CWQ_IMAGE_ID is the widget ID returned by CWQ_IMAGE.
;               Other status variables  that can be set are:
;
;                   ZOOM : The zoom factor of the CW_PZOOM widget.
;                   XTVSCALE : The XTVSCALE ID to use for intensity/color
;                              scaling.
;                              
;               All the status variables are "change sensitive". Modifying one
;               of them means that the display is updated (to any degree
;               necessary) to reflect the changes in the status.
;
;               EVENT HANDLING
;
;               If the widget is not in "autonomous" mode, it will generate
;               events whenever the user tries to change the XIX/YIX/ZOOM 
;               values by interacting with the CW_PZOOM window. The event
;               structure {CWQ_IMAGE_EVENT} has the following tags:
;
;                  ID : The CWQ_IMAGE widget ID.
;                  TOP : The ID of the top of the widget hierarchy.
;                  HANDLER : The ID of the event handler.
;                  SET : A structure {CWQ_IMAGE_SET} with tags XIX, YIX, and
;                        ZOOM.
;                  OLD : A {CWQ_IMAGE_SET} structure with the OLD values of
;                        XIX, YIX and ZOOM.
;                  EVENT : The original {CW_PZOOM_EVENT}. See CW_PZOOM for a
;                          description of this.
;               
;               When such an event is generated, the display is NOT updated
;               until the event is acknowledged by setting the OFFSET value
;               through the WIDGET_CONTROL SET_VALUE mechanism, e.g.,
;
;                  WIDGET_CONTROL,EV.ID,SET_VALUE=EV.SET
;
;               will do. When the widget is run in autonomous mode, this is
;               what is done before gobbling up the event.
;               
;               
; Use         : CW_ID = CWQ_IMAGE(BASE, QLDS [,KEYWORDS])
;    
; Inputs      :  BASE : The base to put the compound widget on.
;
;               QLDS : The QLDS from which to take the data to be displayed.
;                      During the active life of the compound widget, it must
;                      be possible to use the QLDS_CHECKIN mechanism to get at
;                      the QLDS.
;               
; Opt. Inputs : None.
;               
; Outputs     : Returns compound widget ID.
;               
; Opt. Outputs: None.
;               
; Keywords    : UVALUE : The user value to be associated with this widget.
;
;               NO_COPY : Whether to use NO_COPY when setting the UVALUE.
;
;               XSIZE/
;               YSIZE : The size of the widget_draw window in which to display
;                       the image.
;
;               CW_MOUSE : The widget ID of any CW_MOUSE control box to be
;                          used.
;
;               XTVSCALE : The ID of the XTVSCALE box to use when displaying
;                          the image.
;
;               XIX/YIX/TIX : Specifies the initial focus point.
;
;               WINDOWI : The index of the spectral window to take the
;                         image from.
;
;               OFFSET : The spectral window offset at which to generate the
;                        image.
;
;               AUTONOMOUS : Set this to make the widget self-acknowledge all
;                            user actions, without sending on events to the
;                            owner.
;
; Calls       : cwq_image_update qlds_checkin copy_tag_values cwq_image_print
;               cwq_image_update cw_pzoom() default detdesc() gt_iimage()
;               parcheck since_version() typ() widget_base()
;
; Common      : QLSAVE : Contains the QLDS to take the displayed data from,
;                        checking in with QLDS_CHECKIN.
;               
; Restrictions: Needs to be able to get at the QLDS via QLDS_CHECKIN.
;               
; Side effects: None.
;               
; Category    : QuickLook, Compound_widget, Display
;               
; Prev. Hist. : Based on cw_pzoom
;
; Written     : S.V.H.Haugan, UiO, June 1996
;               
; Modified    : Version 2, SVHH, 9 August 1996
;                       Using gt_iimage(/QUICK) to speed up execution.
;               Version 3, SVHH, 16 October 1996
;                       Modifying IDL v 4.0(.1) behaviour.
;
; Version     : 3, 16 October 1996
;-            



PRO cwq_image_update,info
  COMMON qlsave,qlds,saved
  
  qlds_checkin, info.int.ql_no
  
  ;; Update display
  
  replot = 0
  
  IF info.int.update THEN BEGIN
     windowi = info.ext.windowi
     offset = info.ext.offset
     WIDGET_CONTROL,info.int.cwpzoom, $
        set_value={title:qlds.detdesc(windowi).label}
     image = gt_iimage(qlds,offset=offset,WINDOW=windowi,/quick)
     info.int.update = 0
     info.int.repoint = 1
     info.int.rescale = 1
     replot = 1
  END
  
  IF info.int.repoint THEN BEGIN
     WIDGET_CONTROL,info.int.cwpzoom, $
        set_value={XFOCUS:info.ext.xix,YFOCUS:info.ext.yix,$
                   zoom:info.ext.zoom}
     info.int.repoint = 0
     replot = 1
  END
  
  rescale = info.int.rescale
  info.int.rescale = 0
  
  IF N_ELEMENTS(image) NE 0 THEN BEGIN
     WIDGET_CONTROL,info.int.cwpzoom,set_value=image ;; Rescaling done anyway
  END ELSE BEGIN
     WIDGET_CONTROL,info.int.cwpzoom, $
        set_value = {replot:replot,rescale:rescale}
  END
  
END


PRO cwq_image_print,info
  
  ;; !P.CLIP should mark an area with approximatly same height:width ratio 
  ;; as the cw_pzoom display
  
  ;; This is the space we're allowed to use:
  clip = !P.clip
  
  width = !P.clip(2)-!P.clip(0)
  height = !P.clip(3)-!P.clip(1)
  
  ;; Margins:
  
  xleftm = 0.2
  xrightm = 0.05
  
  ytopm = 0.05
  ybotm = 0.10
  
  xcenter = clip(0) + 0.5 * ((1.0 + xleftm - xrightm)*width)
  ycenter = clip(1) + 0.5 * ((1.0 + ybotm - ytopm)*height)
  
  maxwidth = (1.0-xleftm-xrightm)*width
  maxheight = (1.0-ytopm-ybotm)*height
  
  pheight = maxheight < maxwidth*info.int.ratio
  pwidth = maxwidth < pheight/info.int.ratio
  charsz = !P.charsize
  ;; Renormalized character size
  !P.charsize = 0.7*(0.5*(width+height))/8000.0
  !P.clip = [xcenter-0.5*pwidth,ycenter-0.5*pheight, $
             xcenter+0.5*pwidth,ycenter+0.5*pheight]
  
  WIDGET_CONTROL,info.int.cwpzoom,set_value={replot:1}
  !P.charsize = charsz
END



PRO cwq_image_setv,ID,VALUE
  IF datatype(value) NE 'STC' THEN RETURN ; No primary value
  
  ;; Get storage/info
  
  store = WIDGET_INFO(id,/child)
  WIDGET_CONTROL,store,get_uvalue=info,/no_copy
  
  tags = tag_names(value)
  IF total(tags EQ "PSPLOT") NE 0 THEN BEGIN
     ;; PRINT! and return!
     PRINT,"CWQ_IMAGE.PSPLOT Command discovered!"
     cwq_image_print,info
     WIDGET_CONTROL,store,set_uvalue=info,/no_copy
     return
  END
  
  ;;
  ;; Setting status variables
  ;;
  
  ext = info.ext
  copy_tag_values,ext,value,status
  
  ;; Change sensitive variables:
  
  IF info.ext.windowi NE ext.windowi OR $
     info.ext.offset NE ext.offset THEN info.int.update = 1
  
  IF info.ext.xix NE ext.xix OR $
     info.ext.yix NE ext.yix OR $
     info.ext.tix NE ext.tix OR $
     info.ext.zoom NE ext.zoom THEN info.int.repoint = 1
  
  IF info.ext.xtvscale NE ext.xtvscale THEN BEGIN
     WIDGET_CONTROL,info.int.cwpzoom, $
        set_value={xtvscale:ext.xtvscale}
     info.int.rescale = 1
  END
  
  ;; Make changes permanent
  
  info.ext = ext
  cwq_image_update,info
  
  ;; Store updated info structure 
  WIDGET_CONTROL,store,set_uvalue=info,/no_copy
END



FUNCTION cwq_image_event,ev

  ;; Find storage and info
  STORAGE = WIDGET_INFO(ev.handler,/child)
  WIDGET_CONTROL,STORAGE,get_uvalue=info,/no_copy
  
  WIDGET_CONTROL,ev.id,get_uvalue=action
  evnt = 0
  auto = 0
  oldxix = info.ext.xix
  oldyix = info.ext.yix
  oldzoom = info.ext.zoom
 
  CASE ACTION OF 
     
  'CW_PZOOM':BEGIN
     newxix = ev.set.xfocus
     newyix = ev.set.yfocus
     newzoom = ev.set.zoom
     ;; Don't pass on non-changing events
     IF ev.set.xfocus EQ ev.old.xfocus  $
        AND ev.set.yfocus EQ ev.old.yfocus $
        AND ev.set.zoom EQ ev.old.zoom THEN BEGIN
        WIDGET_CONTROL,EV.ID,SET_VALUE = EV.SET ;; Acknowledge change
        GOTO,NO_EVENT
     END
     ENDCASE
     
  ELSE:BEGIN
     ;; What could this be!
     PRINT,"ACTION?: "+ACTION
     GOTO,NO_EVENT
     ENDCASE
  END
  
MAKE_EVENT:
  
  set = {CWQ_IMAGE_SET,$
         XIX : newxix,$
         yix : newyix, $
         zoom : newzoom $
        }
  
  old = {CWQ_IMAGE_SET,$
         xix : oldxix,$
         yix : oldyix, $
         zoom : oldzoom $
        }
  
  ;; The original event may never have been caused by XTVSCALE (cause those
  ;; wouldn't get here...).  We can safely assume EV is always a
  ;; {CW_PZOOM_EVENT} structure, so it's safe to use a named structure here.
  
  evnt = {CWQ_IMAGE_EVENT,$
          ID:ev.handler,$
          TOP:ev.top,$
          HANDLER:0L,$
          SET : set,$
          OLD : old,$
          EVENT:EV}
  
  ;; Autonomous mode?
  auto = info.int.auto
  
NO_EVENT:
  
  ;; NO replotting so far, just store info structure
  
  WIDGET_CONTROL,STORAGE,set_uvalue=info,/no_copy
  
  ;; Autonomous mode means always acknowledge any event and
  ;; gobble it up.
  IF auto AND datatype(evnt) EQ 'STC' THEN BEGIN
     WIDGET_CONTROL,ev.handler,set_value=evnt.set
     RETURN,0
  END
  
  RETURN,evnt
END


;
; COMPOUND WIGET CREATION
;


FUNCTION cwq_image,on_base, QLDS, $
                   uvalue=uvalue, no_copy=no_copy, $
                   xsize=xsize,ysize=ysize,$
                   cw_mouse=cw_mouse, $
                   xtvscale=xtvscale,$ $
                   $ ;; Initial point
                   xix=xix,yix=yix,tix=tix, windowi=windowi,$
                   offset=offset,$
                   zoom=zoom,$
                   $
                   $;; Miscellaneous
                   $
                   autonomous=autonomous
;+  
;
; KEYWORD DEFAULTS/EXPLANATIONS
;
; All keywords not marked with * may be altered after widget creation
; through the
;  
;   WIDGET_CONTROL,CW_ID,SET_VALUE={<KEYWORD_NAME>:<keyword_value>}
;
; mechanism.
;
  
  default,uvalue,'CWQ_IMAGE'     ;*
  default,no_copy,0             ;* For setting uvalue of this Compound widget
  default,CW_MOUSE,-1L          ;* Compound widget mouse control box. 
  default,xtvscale,-1L
  
  default,xsize,200
  default,ysize,200
  
  default,xix,0
  default,yix,0
  default,tix,0
  default,windowi,0
  default,offset,0
  default,zoom,1.0
  
; Miscellaneous
  default,autonomous,0          ;* Auto-redisplay.
  
;-  
  
;;
;; Once more: Check variable types
;;
  keyword = 0
  scalar = 0
  real = typ(/rea)
  natural = typ(/nat)
  strng = typ(/str)
  lng = typ(/lon)
  
; Widgety things
  
  no_copy = KEYWORD_SET(no_copy)
  parcheck,cw_mouse,     keyword,    lng,    scalar,'CW_MOUSE'
  parcheck,xtvscale,     keyword,    lng,     [0,1],'XTVSCALE'
  parcheck,xsize,        keyword,natural,    scalar,'XSIZE'
  parcheck,ysize,        keyword,natural,    scalar,'YSIZE'
  
; Miscellaneous
  autonomous = KEYWORD_SET(autonomous)
  
  IF since_version('4.0') THEN esize = {scr_xsize:xsize,scr_ysize:ysize}
  
  base = WIDGET_BASE(on_base, _extra=esize,$
                     uvalue=uvalue,no_copy=no_copy, $
                     event_func='cwq_image_event', $
                     pro_set_value='cwq_image_setv')
  
  ;; Internal bases
  ;; 
  ;; storage = WIDGET_BASE(base,map=0,xpad=0,ypad=0,space=0)
  
  ;; Layout bases
  
  intbase = WIDGET_BASE(base,frame = 0,_extra=esize)
  storage = intbase
  
  val = gt_iimage(qlds,WINDOW=windowi,offset=offset,/quick)
  
  ;; SIZES and such
  
  xdsize = xsize-65
  ydsize = ysize-65
  origo = [55,45]
  xticks = -(xdsize/50) < (-2)
  xticklen = -8.0/xsize
  yticklen = -8.0/ysize
  title=qlds.detdesc(windowi).label
  
  ;; Data coordinates
  origin = qlds.detdesc(windowi).origin(1:2)
  scale = qlds.detdesc(windowi).spacing(1:2)
  
  pzoom = cw_pzoom(intbase,value = val, uvalue='CW_PZOOM', $
                   xtvscale=xtvscale,$
                   xtitle = 'SOLAR_X',ytitle='SOLAR_Y',$
                   origin = origin, scale=scale,$
                   xwsize=xsize,ywsize=ysize,xticks=xticks,$
                   xdsize=xdsize,ydsize=ydsize,origo=origo,$
                   title=title,xticklen=xticklen,yticklen=yticklen,$
                   cw_mouse=cw_mouse)
  
  IF zoom NE 1.0 THEN BEGIN
     WIDGET_CONTROL,pzoom,set_value={zoom:zoom}
  END
  
  
  WIDGET_CONTROL,pzoom,set_value={XFOCUS:xix,YFOCUS:YIX}
  
  ;; External values
  ;; These can be set by the user "on the fly"
  
  ext = $
     { $ ;; cwq_image_disp,$
       $
       $;; State/action variables
       $
       WINDOWI : windowi,$      ; Setting causes full update
       OFFSET : offset,$        ; Setting causes full update
       XIX : xix, $             ; Setting causes repoint
       YIX : yix, $             ; Setting causes repoint
       TIX : tix, $             ; Setting causes repoint
       ZOOM : FLOAT(zoom), $    ; Setting causes repoint
       XTVSCALE : (XTVSCALE)(0) $ ; Setting causes rescaling
     }
  
  ;; Internal values
  
  int = $
     { $ ;; cwq_image_int,$
       ql_no  : QLDS.QL_NO, $
       cwpzoom  : pzoom, $
       ratio : FLOAT(ydsize)/FLOAT(xdsize),$
       rescale : 0,$
       repoint : 0,$
       update  : 0,$
       auto   : autonomous}    ; Block events?

  
  info = $
     { $ ;;cwq_image_info,$
       ext  : ext,$
       int: int}
  
  WIDGET_CONTROL,storage,set_uvalue=info,/no_copy
  
  RETURN,base
END

