subroutine popup(set,line,error,user_function)
  use gbl_message
  use classic_api
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>popup
  use class_parameter
  use class_popup
  use class_data
  use class_setup_new
  use class_types
  !----------------------------------------------------------------------
  ! @ public
  ! CLASS Support routine for command
  ! POPUP [Number | OffX OffY]
  !----------------------------------------------------------------------
  type(class_setup_t), intent(in)  :: set           !
  character(len=*),    intent(in)  :: line          ! Input command line
  logical,             intent(out) :: error         ! Logical error flag
  logical,             external    :: user_function !
  ! Local
  character(len=*), parameter :: rname='POPUP'
  integer(kind=obsnum_length) :: jpop
  integer(kind=entry_length) :: kpop,i,imin(1)
  integer(kind=4) :: nc,nx,ny,jx,iy,ier
  real(kind=4) :: off1,off2,x,y
  real(kind=4), allocatable :: dist(:)
  character(len=60) :: argum
  character(len=1) :: ch
  character(len=80) :: chain
  !
  if (sic_narg(0).eq.1) then
     ! Popup with observation number as argument (any observation from IX)
     call sic_i8 (line,0,1,jpop,.true.,error)
     if (error) return
     call popup_full(set,jpop,user_function,error)
     if (error) return
     !
  elseif (sic_narg(0).eq.2 .and. cpop.eq.cpop_map) then
     ! Popup after a MAP /GRID command, with offset in command line
     call sic_ch(line,0,1,argum,nc,.true.,error)
     if (error) return
     call coffse(set,rname,argum,' ',off1,error)  ! NB: no syntax for custom angle unit
     if (error) return
     call sic_ch(line,0,2,argum,nc,.false.,error)
     if (error) return
     call coffse(set,rname,argum,' ',off2,error)
     if (error) return
     do i=1,npop
        if (abs(off1-xpop(i)).lt.set%tole .and.abs(off2-ypop(i)).lt.set%tole) then
           call popup_full(set,ipop(i),user_function,error)
           if (error) return
           return
        endif
     enddo
     call class_message(seve%e,rname,'No observation in range')
     error = .true.
     return
     !
  elseif (.not.gtg_curs()) then
     call class_message(seve%e,rname,'No cursor available')
     error = .true.
     return
     !
  elseif (cpop.eq.cpop_stamp) then
     ! Popup after a STAMP command: Get box number from the cursor
     ch = 'H'
     do
        if (ch.eq.'H') then
          call class_message(seve%i,rname,'Interactions with the STAMP plot:')
          call popup_usage('Observation number')
        endif
        call gtcurs(x,y,ch,error)
        if (error)  return
        call sic_upper(ch)
        nx = nint(pux2-pux1)
        ny = nint(puy2-puy1)
        x = (x-pgx1)*(pux2-pux1)/(pgx2-pgx1)+pux1
        y = (y-pgy1)*(puy2-puy1)/(pgy2-pgy1)+puy1
        jx = nint(x)
        iy = nint(y)
        kpop = jx+(iy-1)*nx
        if (ch.eq.'E' .or. ch.eq.'*') then
           exit
        elseif (jx.lt.1 .or. jx.gt.nx .or.  &
                iy.lt.1 .or. iy.gt.ny .or.  &
                kpop.gt.npop) then
           call class_message(seve%w,rname,'No spectrum here')
        elseif (ch.eq.'P' .or. ch.eq.'&') then
           call popup_full(set,ipop(kpop),user_function,error)
           if (error) return
        else
           write(chain,'(a,i0)') 'Observation # ',ipop(kpop)
           call class_message(seve%i,rname,chain)
        endif
     enddo
     !
  elseif (cpop.eq.cpop_plotindex) then
     ! Popup after a PLOT /INDEX command: Get spectrum number from the cursor
     ch = 'H'
     do
        if (ch.eq.'H') then
          call class_message(seve%i,rname,'Interactions with the PLOT /INDEX:')
          call popup_usage('Observation number')
        endif
        call gtcurs(x,y,ch,error)
        if (error)  return
        call sic_upper(ch)
        y = (y-pgz1)*(puz2-puz1)/(pgz2-pgz1)
        kpop = nint(y+puz1)  ! Entry number in the current index
        if (ch.eq.'E' .or. ch.eq.'*') then
           exit
        elseif (kpop.lt.1 .or. kpop.gt.npop) then
           call class_message(seve%w,rname,'No spectrum here')
        elseif (ch.eq.'P' .or. ch.eq.'&') then
           call popup_full(set,ipop(kpop),user_function,error)
           if (error) return
        elseif (ch.ne.'H') then
           write(chain,'(a,i0)') 'Observation # ',ipop(kpop)
           call class_message(seve%i,rname,chain)
        endif
     enddo
     !
  elseif (cpop.eq.cpop_map) then
     ! Popup after a MAP command: Get offset from the cursor
     ch = 'H'
     do
        if (ch.eq.'H') then
          call class_message(seve%i,rname,'Interactions with the MAP plot:')
          call popup_usage('Cursor position and nearest observation')
        endif
        call gtcurs(x,y,ch,error)
        if (error)  return
        call sic_upper(ch)
        nx = nint(pux2-pux1)
        ny = nint(puy2-puy1)
        off1 = (x-pgx1)*(pux2-pux1)/(pgx2-pgx1)+pux1
        off2 = (y-pgy1)*(puy2-puy1)/(pgy2-pgy1)+puy1
        write(chain,'(a,f9.2,f9.2)') 'Offsets ',off1*class_setup_get_fangle(),  &
                                                off2*class_setup_get_fangle()
        call class_message(seve%i,rname,chain)
        allocate(dist(npop),stat=ier)
        if (failed_allocate(rname,'dist array',ier,error))  return
        do i=1,npop
           dist(i) = (off1-xpop(i))**2 +  (off2-ypop(i))**2
        enddo
        imin = minloc(dist)
        deallocate(dist)
        i = imin(1)
        if (ch.eq.'E' .or. ch.eq.'*') then
           exit
        elseif (ch.eq.'P' .or. ch.eq.'&') then
           call popup_full(set,ipop(i),user_function,error)
           if (error) return
        else
           write(chain,'(a,f9.2,f9.2)') &
                'Nearest observation at ',xpop(i)*class_setup_get_fangle(),  &
                                          ypop(i)*class_setup_get_fangle()
           call class_message(seve%i,rname,chain)
        endif
     enddo
  else
     call class_message(seve%e,rname,  &
       'Invalid number of arguments or no previous PLOT /INDEX, STAMP, or MAP')
     error = .true.
     return
  endif
  !
contains
  subroutine popup_usage(anykey)
    character(len=*), intent(in) :: anykey
    call class_message(seve%r,rname,'   Left   click :  Observation number')
    call class_message(seve%r,rname,'   Middle click :  Popup window')
    call class_message(seve%r,rname,'   Right  click :  Exit')
    call class_message(seve%r,rname,'   Press any key:  '//anykey)
    call class_message(seve%r,rname,'   Press P key  :  Popup window')
    call class_message(seve%r,rname,'   Press H key  :  Display this help')
    call class_message(seve%r,rname,'   Press E key  :  Exit')
  end subroutine popup_usage
  !
end subroutine popup
!
subroutine popup_full(set,this_one,user_function,error)
  use gildas_def
  use gbl_constant
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>popup_full
  use class_types
  use plot_formula
  !----------------------------------------------------------------------
  ! @ private
  !  Plot one observation in the <POPUP window
  !----------------------------------------------------------------------
  type(class_setup_t),         intent(in)    :: set            !
  integer(kind=obsnum_length), intent(in)    :: this_one       ! Obs. number
  logical,                     external      :: user_function  !
  logical,                     intent(inout) :: error          ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='POPUP'
  type(observation) :: obs
  character(len=80) :: cdir
  real(kind=4) :: x,y,expa,cdef,lx2,ly2
  !
  call init_obs(obs)
  call get_num(set,obs,this_one,0,user_function,error)
  if (error) return
  call abscissa(set,obs,error)
  if (error) return
  !
  call newlim(set,obs,error)
  if (error) return
  call get_box(gx1,gx2,gy1,gy2)
  !
  cdir(1:5) = 'GTVL'//char(92)
  if (.not.gtexist('<POPUP')) then
     cdir(6:) = 'CREATE DIRECTORY <POPUP'
     call exec_command(cdir,error)
     cdir(6:) = 'CHANGE DIRECTORY <POPUP'
     call exec_command(cdir,error)
     cdir(6:) = 'CHANGE POSITION 7'
     call exec_command(cdir,error)
  else
     cdir(6:) = 'CHANGE DIRECTORY <POPUP'
     call exec_command(cdir,error)
  endif
  cdir(6:) = 'CLEAR DIRECTORY'
  call exec_command(cdir,error)
  !
  ! Spectrum
  call spectr1d(rname,set,obs,error)
  if (error)  return
  !
  ! Box
  call class_box_default(set,.false.,obs,'Y',error)
  if (error)  return
  !
  ! Title
  call sic_get_real('PAGE_X',lx2,error)
  call sic_get_real('PAGE_Y',ly2,error)
  call sic_get_real('CHARACTER_SIZE',cdef,error)
  expa = 1.0
  x = lx2/2.0
  y = ly2-cdef*0.575*expa
  call out0('Graphic',x,y,error)
  call titout(set,obs%head,set%heade,'O')
  !
  cdir(6:) = 'CHANGE DIRECTORY <GREG'
  call exec_command(cdir,error)
  !
  call free_obs(obs)
end subroutine popup_full
