!-----------------------------------------------------------------------
! IMAGER
!   Support for command UV_PREVIEW /BROWSE
!
! (very useful when Nchan > Npixels on the plotting window).
!
!-----------------------------------------------------------------------
!
! Optimization: only define things if not already done
if (exist(p_browse)) then
  @ browse-check-spectrum &1
  @ browse-usage
  @ browse-loop
  return
endif
!
! Sanity checks
!
begin procedure browse-check-spectrum
  if (.not.exist(spectrum)) then
    message e BROWSE "No spectrum in memory, use UV_PREVIEW before"
    return base
  endif
  @ browse-define
  !
  defin integer nt nc
  let nc size(spectrum,1)
  let nt size(spectrum,2)-1
  !
  if (pro%narg.eq.0) then
    if (.not.exist(p_browse%rx)) then
      message e BROWSE "No taper selected, specify taper number"
      return base
    else
      return
    endif
  endif
  !
  nt = min(nt,&1+1)
  nt = max(2,nt)
  !
  ! Do not reload if already there...
  if (p_browse%last.eq.nt) return
  !
  greg1\set blank spectrum%blank[1] spectrum%blank[2]
  !
  if exist(p_browse%rx) then
    if (size(p_browse%rx).ne.nc) then
      delete /variable  p_browse%rx p_browse%ry
      define double p_browse%rx[nc] p_browse%ry[nc] /global
    endif
  else
    define double p_browse%rx[nc] p_browse%ry[nc] /global
  endif
  !!  let p_browse%rx spectrum[1]   ! This would be Velocity
  !!  define double velo freq /like spectrum[1]
  !!  velo[I] = (i-spectrum%convert[1,1])*spectrum%velres+spectrum%veloff
  !!  freq[i] = (i-spectrum%convert[1,1])*spectrum%freqres+spectrum%restfre
  !
  ! Conversion Formula
  !     Velo = (Freq-spectrum%restfre)*spectrum%velres/spectrum%freqres+spectrum%veloff
  let p_browse%rx[i] (i-spectrum%convert[1,1])*spectrum%freqres+spectrum%restfre     ! This is Frequency
  let p_browse%ry spectrum[nt]
  !
  if (p_browse%last.eq.-1) then
    @ browse-default-xwidth
    @ browse-default-xcenter
  endif
  let p_browse%last nt
end procedure browse-check-spectrum
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! Definitions and defaults
!
begin procedure browse-define
  if (exist(p_browse)) return
  !
  define structure p_browse /global
  define alias p_browse%last browse_last /global
  let p_browse%last -1
  !
  define double p_browse%xcenter p_browse%xwidth p_browse%xoffset /global
  define character*12 p_browse%ymode[2] /global
  let p_browse%ymode * *
  !
  define structure p_browse%full /global
  define real p_browse%full%xmin p_browse%full%xmax /global
  define real p_browse%full%ymin p_browse%full%ymax /global
  !
  define structure p_browse%zoom /like p_browse%full /global
  !
  define structure p_browse%status /global
  define integer p_browse%status%detected p_browse%status%doubtful p_browse%status%undetected /global
  define integer p_browse%status%unknown p_browse%status%last /global
  !
  let p_browse%status%unknown 1
  let p_browse%status%undetected 2
  let p_browse%status%doubtful 3
  let p_browse%status%detected 4
  let p_browse%status%last 4
  !
  define character p_browse%status%name*12[p_browse%status%last] /global
  let p_browse%status%name "unknown" "undetected" "doubtful" "detected"
  !
  ! GTV Directory Names
  define structure p_browse%dir /global
  define character*12 p_browse%dir%full p_browse%dir%zoom /global
  let p_browse%dir%full "BFULL"
  let p_browse%dir%zoom "BZOOM"
  !
  @ browse-defaults
end procedure browse-define
!
begin procedure browse-default-xwidth
  if .not.exist(p_browse%rx) return
  let channels size(p_browse%rx) /new integer
  let p_browse%xwidth  abs(p_browse%rx[channels]-p_browse%rx[1])/8.
  if exist(browse%width) then
    if (browse%width.ne.0) let p_browse%xwidth browse%width
  endif
end procedure browse-default-xwidth
!
begin procedure browse-default-xcenter
  if .not.exist(p_browse%rx) return
  let channels size(p_browse%rx) /new integer
  let p_browse%xcenter (p_browse%rx[channels]+p_browse%rx[1])/2.
  if (exist(browse%center)) then
    if (browse%center.ne.0) let p_browse%xcenter browse%center
  endif
end procedure browse-default-xcenter
!
begin procedure browse-defaults
  !
  ! Box positions
  let p_browse%full%xmin 0.10*page_x
  let p_browse%full%xmax 0.90*page_x
  let p_browse%full%ymin 0.10*page_y
  let p_browse%full%ymax 0.30*page_y
  let p_browse%zoom%xmin 0.10*page_x
  let p_browse%zoom%xmax 0.90*page_x
  let p_browse%zoom%ymin 0.425*page_y
  let p_browse%zoom%ymax 0.75*page_y
  !
  @ browse-default-xwidth
  @ browse-default-xcenter
  !
end procedure browse-defaults
!
begin procedure browse-line-annotate-multi
  if preview%nfound.eq.0 return
  greg1\pencil 3
  ! Small bug in DRAW TEXT -- All must be arrays (cannot mix scalar with arrays in DRAW TEXT)
  define double ypos[preview%nfound]
  let ypos user_ymax+0.05*(user_ymax-user_ymin)
  if (preview%nfound.eq.1) then
    greg1\draw text preview%found%freq[1]  ypos[1] preview%found%lines[1] 6 60 /user
  else
    greg1\draw text preview%found%freq  ypos preview%found%lines 6 60 /user
  endif
  delete /var ypos
  !
  greg1\pencil 0
  if (preview%ndetect.eq.0) return
  !
  greg1\pencil 1
  define double ypos[preview%ndetect]
  let ypos user_ymax+0.05*(user_ymax-user_ymin)
  if preview%ndetect.eq.1 then
    greg1\draw text preview%detected%freq[1]  ypos[1] preview%detected%lines[1] 6 60 /user
  else
    greg1\draw text preview%detected%freq  ypos preview%detected%lines 6 60 /user
  endif
  delete /var ypos
  greg1\pencil 0
end procedure browse-line-annotate-multi
!
!
! Actions and plots
!
begin procedure browse-line-id
  if (p_browse%line%n.le.0) return
  gtvl\change directory 'p_browse%dir%zoom'
  ! Get cursor frequency
  greg1\draw relo * *
  define double fres
  let fres use_curs[1]+p_browse%xoffset
  ! Get closest catalog line
  define integer loc[2] iline
  compute loc location p_browse%line%fres fres
  if (abs(p_browse%line%fres['loc[1]']-fres).le.abs(p_browse%line%fres['loc[2]']-fres)) then
    let iline loc[1]
  else
    let iline loc[2]
  endif
  ! Change line status
  let p_browse%line%status[iline] 1+mod(p_browse%line%status[iline],p_browse%status%last)
  @ browse-line-annotate-single 'iline'
  gtvl\change directory
end procedure browse-line-id
!
begin procedure browse-display-value
  gtvl\change directory 'p_browse%dir%zoom'
  greg1\draw relo * *
  say "   Rest Frequency      : " 'use_curs[1]' " MHz" /format a f15.4 a
  say "   Flux Density        : " 'use_curs[2]' " Jy" /format a 1pg15.4 a
  gtvl\change directory
end procedure browse-display-value
!
begin procedure browse-set-xcenter
  if (phy_curs[2].gt.p_browse%zoom%ymin) then
    gtvl\change directory 'p_browse%dir%zoom'
    let p_browse%xcenter (phy_curs[1]-p_browse%zoom%xmin)*(user_xmax-user_xmin)/(p_browse%zoom%xmax-p_browse%zoom%xmin)+user_xmin
    gtvl\change directory
  else
    gtvl\change directory 'p_browse%dir%full'
    let p_browse%xcenter (phy_curs[1]-p_browse%full%xmin)*(user_xmax-user_xmin)/(p_browse%full%xmax-p_browse%full%xmin)+user_xmin
    gtvl\change directory
  endif
end procedure browse-set-xcenter
!
begin procedure browse-shift-xcenter
  define double fmin fmax
  let p_browse%xcenter p_browse%xcenter&10.5*p_browse%xwidth
  let channels size(p_browse%rx) /new integer
  let fmin min(p_browse%rx[1],p_browse%rx[channels])
  let fmax max(p_browse%rx[1],p_browse%rx[channels])
  if (p_browse%xcenter.gt.fmax) then
    let p_browse%xcenter fmin
  else if (p_browse%xcenter.lt.fmin) then
    let p_browse%xcenter fmax
  endif
end procedure browse-shift-xcenter
!
begin procedure browse-plot-full-spectrum
  gtvl\create directory 'p_browse%dir%full'
  gtvl\change directory 'p_browse%dir%full'
  greg1\set box_location -
    'p_browse%full%xmin' 'p_browse%full%xmax' 'p_browse%full%ymin' 'p_browse%full%ymax'
  !
  define char*12 ymode[2]
  define integer nt
  nt = size(spectrum,2)-1 ! Last one is noise level...
  let ymode 'p_browse%ymode[1]' 'p_browse%ymode[2]'
  if (ymode[1].eq."=") let ymode[1] "*"
  if (ymode[2].eq."=") let ymode[2] "*"
  greg1\limits * *  'ymode[1]' 'ymode[2]' /var P_browse%rx spectrum[nt]
  if (user_ymin.eq.user_ymax) then
    if (user_ymax.gt.0) then
      greg1\limits = = 0 user_ymax
    else
      greg1\limits =  user_ymin 0
    endif
  endif
  for i 2 to nt
    greg1\histogram p_browse%rx spectrum[i]
  next
  greg1\box
  greg1\draw text -4 0 "Flux density ("'spectrum%unit'")" 6 90 /char 7
  !
  gtvl\change directory ..
end procedure browse-plot-full-spectrum
!
begin procedure browse-plot-zoom-lines
  ! Draw the red lines representing the zooming range. Segments are
  ! stored in the ZOOM directory since they have to be cleared and updated
  ! at each click.
  !
  ! Jump to the FULL directory to get its box location in correct units
  gtvl\change directory 'p_browse%dir%full'
  !
  ! Vertical lines representing the range:
  define real xleft xright ylow yup
  ! Define in user coordinates
  let xleft  p_browse%xcenter-p_browse%xwidth
  let xright p_browse%xcenter+p_browse%xwidth
  ! Convert to absolute physical coordinates
  greg1\draw relocate xleft user_ymin /user
  let xleft phy_curs[1]
  let ylow  phy_curs[2]
  greg1\draw relocate xright user_ymax /user
  let xright phy_curs[1]
  let yup    phy_curs[2]
  !
  ! Lines linked to the ZOOM box corners:
  define real xcornl xcornr ycorn
  let xcornl p_browse%zoom%xmin  ! In absolute physical coordinates
  let xcornr p_browse%zoom%xmax
  let ycorn  p_browse%zoom%ymin
  !
  gtvl\change directory ..<'p_browse%dir%zoom'
  ! Convert from absolute to relative physical coordinates (as expected
  ! by G\DRAW without option)
  let xleft  xleft-box_xmin
  let xright xright-box_xmin
  let ylow   ylow-box_ymin
  let yup    yup-box_ymin
  let xcornl xcornl-box_xmin
  let xcornr xcornr-box_xmin
  let ycorn  ycorn-box_ymin
  !
  greg1\pencil 1
  greg1\draw relocate xleft  ylow
  greg1\draw line     xleft  yup
  greg1\draw line     xcornl ycorn
  greg1\draw relocate xright ylow
  greg1\draw line     xright yup
  greg1\draw line     xcornr ycorn
  greg1\pencil 0
  !
  gtvl\change directory ..
end procedure browse-plot-zoom-lines
!
begin procedure browse-plot-zoomed-spectrum
  on error "RETURN BASE"
  !
  define double xmin xmax
  let xmin p_browse%xcenter-p_browse%xwidth+p_browse%xoffset
  let xmax p_browse%xcenter+p_browse%xwidth+p_browse%xoffset
  define integer ista iend ip im nc
  let nc size(p_browse%ry)
  let ip (xmin-spectrum%restfre)/spectrum%freqres+spectrum%convert[1,1]
  let im (xmax-spectrum%restfre)/spectrum%freqres+spectrum%convert[1,1]
  let ista min(ip,im)
  if (ista.gt.nc) return ! Out of range
  let ista max(1,ista)
  let iend max(ip,im)
  if (iend.lt.1) return  ! Out of range
  let iend min(iend,nc)
  !
  gtvl\clear directory 'p_browse%dir%zoom'
  gtvl\change directory 'p_browse%dir%zoom'
  greg1\set box_location -
    'p_browse%zoom%xmin' 'p_browse%zoom%xmax' 'p_browse%zoom%ymin' 'p_browse%zoom%ymax'
  !
  greg1\limits xmin xmax 'p_browse%ymode[1]' 'p_browse%ymode[2]' /var P_browse%rx[ista:iend] p_browse%ry[ista:iend]
  !
  greg1\histogram p_browse%rx p_browse%ry       !!   spectrum
  !
  !!@ browse-plot-baseline-spectrum     ! Does it still make sense ??
  !!@ browse-plot-significant-spectrum  ! Does it still make sense ??
  greg1\box
  @ browse-line-annotate-multi
  greg1\draw text 1 0 "Taper "'p_browse%last-1' 5 90 /char 6
  !
  gtvl\change directory ..
end procedure browse-plot-zoomed-spectrum
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! User interface
!
begin procedure browse-usage
  say ""
  say "Authors: S.Guilloteau (2020)"
  say "   derived from GO BROWSE in CLASS by S.Bardeau & J.Pety (2010-2011)"
  say "Left  clic: Center zoom at cursor location"
  say "Right clic: Exit"
  say "Press SPACE key: Center zoom at cursor location"
  say "Press   Z   key: Zoom at cursor location"
  say "Press   U   key: Unzoom at cursor location"
  say "Press   B   key: Reset zoom factor to default"
  say "Press   D   key: Default zoom width and location"
  say "Press   V   key: Values at cursor location"
  say "Press   N   key: Shift forward  the zoom window by half its size"
  say "Press   P   key: Shift backward the zoom window by half its size"
  say "Press   Y   key: Select Y axis scale in Zoom window"
  say "Press   T   key: Back to full scale for Y axis in Zoom window"
  say "Press   E   key: Exit loop"
  say "Press   H   key: Help display"
  SAY "Press   1,2,3 or 4 : Select taper number"
  say ""
!!  say "Y scales are ruled by the current SET MODE Y value"
end procedure browse-usage
!
begin procedure browse-loop
  !
  ! Clear current directory only i.e. do not affect the other plots of the
  ! user. This also allows several zooms in several windows. It's up
  ! to the user to decide where to run this procedure.
  gtvl\clear directory
  @ browse-plot-full-spectrum
  gtvl\create directory 'p_browse%dir%zoom'
  !
  def char*1 quotes question
  let quotes = """"
  let question "?"
  !
  for /while yes
    ! There is only one GTV\CLEAR in the loop to avoid long redrawings.
    ! It is located in the procedure below:
    @ browse-plot-zoomed-spectrum
    @ browse-plot-zoom-lines
    !
    ! Next position
    greg1\draw relo
    if ((cursor_code.eq."E").or.(cursor_code.eq."*")) then
      break
    else if (cursor_code.eq."H") then
      @ browse-usage
    else if (cursor_code.eq."L") then
      @ browse-line-id
    else if (cursor_code.eq."V") then
      @ browse-display-value
    else if ((cursor_code.eq." ").or.(cursor_code.eq."R")) then
      @ browse-set-xcenter
    else if (cursor_code.eq."N") then
      @ browse-shift-xcenter "+"
    else if (cursor_code.eq."P") then
      @ browse-shift-xcenter "-"
    else if (cursor_code.eq."Z") then
      let p_browse%xwidth p_browse%xwidth/1.414214
    else if (cursor_code.eq."U") then
      let p_browse%xwidth p_browse%xwidth*1.414214
    else if (cursor_code.eq."B") then
      @ browse-default-xwidth
    else if (cursor_code.eq."D") then
      @ browse-defaults
    else if (cursor_code.eq."Y") then
      let p_browse%ymode /Prompt "set Y range"
    else if (cursor_code.eq."T") then
      let p_browse%ymode "=" "="
    else if (cursor_code.eq."1".or.cursor_code.eq."&") then
      @ browse-check-spectrum 1
    else if (cursor_code.eq."2".or.cursor_code.eq.question) then
      @ browse-check-spectrum 2
    else if (cursor_code.eq."3".or.cursor_code.eq.quotes) then
      @ browse-check-spectrum 3
    else if (cursor_code.eq."4".or.cursor_code.eq."'") then
      @ browse-check-spectrum 4
    else
      !! message w browse "Unknown key: "'cursor_code'
    endif
  next
end procedure browse-loop
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
let mapping_error yes
on error "RETURN BASE"
@ browse-check-spectrum &1
@ browse-usage
@ browse-loop
let mapping_error NO
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
