subroutine setmod(set,line,r,error)
  use gildas_def
  use gbl_constant
  use gbl_message
  use classcore_dependencies_interfaces
  use classcore_interfaces, except_this=>setmod
  use class_setup_new
  use class_types
  use class_popup
  use plot_formula
  !---------------------------------------------------------------------
  ! @ private
  ! CLASS Support routine for command
  !   SET MODE X | Y | Z | ALL [ AUTO | TOTAL | CURRENT | [Min Max] ]
  !   Computes limits and initialise plot parameters
  !---------------------------------------------------------------------
  type(class_setup_t), intent(inout) :: set    !
  character(len=*),    intent(inout) :: line   ! Input command line (modified on return)
  type(observation),   intent(inout) :: r      !
  logical,             intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='SET MODE'
  logical :: doall,dox,doy,doz, docursor,dovalues
  integer(kind=4) :: nkey1,nkey2,nl,nc
  real(kind=plot_length) :: ux1,ux2,uy1,uy2,uz1,uz2
  real(kind=plot_length) :: xc1,xc2,xv1,xv2,xf1,xf2,xi1,xi2
  real(kind=8) :: dux1,dux2,xfo,xio,restf,image,dummy
  character(len=1) :: ch
  character(len=64) :: chgreg
  integer(kind=4), parameter :: mvoc1=4,mvoc2=3
  character(len=12) :: voc1(mvoc1),voc2(mvoc2),arg1,key1
  character(len=24) :: arg2,key2
  ! Data
  data voc1 /'X','Y','Z','ALL'/
  data voc2 /'AUTO','TOTAL','CURRENT'/
  !
  ! 2nd argument: find which dimension
  call sic_ke (line,0,2,arg1,nc,.true.,error)
  nl = index(line,' ')+1
  call sic_ambigs(rname,arg1,key1,nkey1,voc1,mvoc1,error)
  if (error) return
  doall = key1.eq.'ALL'
  dox = key1.eq.'X' .or. doall
  doy = key1.eq.'Y' .or. doall
  doz = key1.eq.'Z' .or. doall
  !
  ! 3rd argument: find mode
  docursor = .false.
  dovalues = .true.
  if (sic_present(0,3)) then
    call sic_ke(line,0,3,arg2,nc,.true.,error)
    if (error)  return
    ! 'sic_ambigs_sub' will return nfound=0 without complaining if
    ! arg2 is not in the list of known keywords
    call sic_ambigs_sub(rname,arg2,key2,nkey2,voc2,mvoc2,error)
    if (error)  return
    !
    select case (nkey2)
    case (1)  ! Auto
      dovalues = .false.
    case (2)  ! Total
      dovalues = .false.
    case (3)  ! Current
      arg2 = 'F'  ! Fixed
      dovalues = .false.
    case (0)  ! Not a known keyword
      arg2 = 'F'  ! Fixed
      dovalues = .true.
    case default
      call class_message(seve%e,rname,'Internal error: argument not understood')
      error = .true.
      return
    end select
  else
    if (gtg_curs()) then
      arg2 = 'F'  ! Fixed
      docursor = .true.
      dovalues = .false.
    else
      call class_message(seve%e,rname,  &
        'Missing values and no cursor available')
      error = .true.
      return
    endif
  endif
  ! In all others cases, numerical values have to be retrieved from
  ! command line
  !
  ! Protections
  if (doall) then
    if (dovalues) then
      call class_message(seve%e,rname,  &
        'Can not set ALL values from numeric arguments on command line')
      error = .true.
      return
    endif
    if (docursor) then
      call class_message(seve%e,rname,'Can not set ALL values with cursor')
      error = .true.
      return
    endif
  endif
  !
  if (dox)  set%modex = arg2
  if (doy)  set%modey = arg2
  if (doz)  set%modez = arg2
  !
  ! Get values with the cursor
  if (docursor) then
    if (dox) then
      call setmod_cursor(set%kind,'X',set%unitx(1),ux1,ux2,error)
      if (error)  return
      !
      xc1 = 0.d0
      xc2 = 0.d0
      xv1 = 0.d0
      xv2 = 0.d0
      xf1 = 0.d0
      xf2 = 0.d0
      xfo = 0.d0
      xi1 = 0.d0
      xi2 = 0.d0
      xio = 0.d0
      !
      if (set%kind.eq.kind_cont) then
        ! Continuum observation
        if (set%unitx(1).eq.'C') then
          xc1 = ux1
          xc2 = ux2
        elseif (set%unitx(1).eq.'T') then
          xf1 = ux1
          xf2 = ux2
          xfo = 0.d0
        else
          xv1 = ux1
          xv2 = ux2
        endif
      elseif (set%kind.eq.kind_spec) then
        ! Spectroscopy observation
        if (set%unitx(1).eq.'I') then
          xi1 = ux1  ! Image units, without the 'image' frequency
          xi2 = ux2
          xio = gixo
        elseif (set%unitx(1).eq.'F') then
          xf1 = ux1  ! Frequency units, without the 'restf' frequency
          xf2 = ux2
          xfo = gfxo
        elseif (set%unitx(1).eq.'C') then
          xc1 = ux1
          xc2 = ux2
        elseif (set%unitx(1).eq.'V') then
          xv1 = ux1
          xv2 = ux2
        endif
      else
        call class_message(seve%e,rname,'Unsupported kind of data')
        error = .true.
        return
      endif
      !
      ! Save in command line
      write (line(nl:),100) 'X',tounit(set%kind,set%unitx(1),ux1),  &
                                tounit(set%kind,set%unitx(1),ux2),  &
                                set%unitx(1)
    endif
    !
    if (doy) then
      call setmod_cursor(set%kind,'Y','',uy1,uy2,error)
      if (error)  return
      ! Save in command line
      write (line(nl:),100) 'Y',tounit(set%kind,'',uy1),  &
                                tounit(set%kind,'',uy2)
    endif
    !
    if (doz) then
      call setmod_cursor(set%kind,'Z','',uz1,uz2,error)
      if (error)  return
      ! Save in command line
      write (line(nl:),100) 'Y',tounit(set%kind,'',uz1),  &
                                tounit(set%kind,'',uz2)
    endif
  endif
  !
  ! Get values from command line
  if (dovalues) then
    if (dox) then
      call sic_r8(line,0,3,dux1,.true.,error)
      if (error) return
      call sic_r8(line,0,4,dux2,.true.,error)
      if (error) return
      ch = set%unitx(1)
      call sic_ke(line,0,5,ch,nc,.false.,error)
      if (error) return
      !
      xc1 = 0.d0
      xc2 = 0.d0
      xv1 = 0.d0
      xv2 = 0.d0
      xf1 = 0.d0
      xf2 = 0.d0
      xfo = 0.d0
      xi1 = 0.d0
      xi2 = 0.d0
      xio = 0.d0
      if (set%kind.eq.kind_cont) then
        ! Continuum case
        if (ch.eq.'C') then
          ! Channel scale
          xc1 = dux1
          xc2 = dux2
          ux1 = xc1  ! For X range test there after
          ux2 = xc2
        elseif (ch.eq.'A') then
          ! Angle scale
          xv1 = dux1/class_setup_get_fangle()
          xv2 = dux2/class_setup_get_fangle()
          ux1 = xv1  ! For X range test there after
          ux2 = xv2
        else
          ! Time scale
          xf1 = dux1
          xf2 = dux2
          xfo = 0.d0
          ux1 = xf1  ! For X range test there after
          ux2 = xf2
        endif
        !
      elseif (set%kind.eq.kind_spec) then
        ! Spectrum case
        if (ch.eq.'C') then
          ! Channel scale
          xc1 = dux1
          xc2 = dux2
          ux1 = xc1  ! For X range test there after
          ux2 = xc2
        elseif (ch.eq.'V') then
          ! Velocity scale
          xv1 = dux1
          xv2 = dux2
          ux1 = xv1  ! For X range test there after
          ux2 = xv2
        elseif (ch.eq.'F') then
          ! Frequency scale
          if (r%head%xnum.eq.0) then
            restf = 1.d5  ! Use an arbitrary value, large enough to avoid
                          ! precision loss in offset frequencies
          else
            restf = r%head%spe%restf
          endif
          xf1 = dux1 - restf
          xf2 = dux2 - restf
          xfo = restf
          ux1 = xf1  ! For X range test there after
          ux2 = xf2
        elseif (ch.eq.'I') then
          ! Image frequency scale
          if (r%head%xnum.eq.0) then
            image = 1.d5  ! Use an arbitrary value, large enough to avoid
                          ! precision loss in offset frequencies
          else
            image = r%head%spe%image
          endif
          xi1 = dux1 - image
          xi2 = dux2 - image
          xio = image
          ux1 = xi1  ! For X range test there after
          ux2 = xi2
        endif
        !
      else
        call class_message(seve%e,rname,'Unsupported kind of data')
        error = .true.
        return
      endif
    endif
    !
    if (doy) then
      uy1 = guy1
      uy2 = guy2
      call sic_r4(line,0,3,uy1,.true.,error)
      if (error) return
      call sic_r4(line,0,4,uy2,.true.,error)
      if (error) return
    endif
    !
    if (doz) then
      uz1 = guz1
      uz2 = guz2
      call sic_r4(line,0,3,uz1,.true.,error)
      if (error) return
      call sic_r4(line,0,4,uz2,.true.,error)
      if (error) return
    endif
    !
  endif
  !
  ! Store values in global parameters
  if (dovalues .or. docursor) then
    if (dox) then
      if (ux1.eq.ux2) then
        call class_message(seve%e,rname,'No range in X')
        error = .true.
        return
      endif
      ! Set graphic limits. This is done only for the relevant X units.
      ! The other limits are computed when plotting the spectrum
      !! Print *,' xc1,xc2,xv1,xv2,xf1,xf2,xfo,xi1,xi2,xio'
      !! Print *, xc1,xc2,xv1,xv2,xf1,xf2,xfo,xi1,xi2,xio
      call selimx(r,xc1,xc2,xv1,xv2,xf1,xf2,xfo,xi1,xi2,xio)
      ! Note that the BASE is performed in the obs%cimin to obs%cimax
      ! range. They are set (indirectly) in selimx, from the gcx1 and gcx2
      ! range. So we need to set all the g*x1 and g*x2 plotting limits, and
      ! then call selimx to compute obs%cimin and obs%cimax. All this is done
      ! by newlimx:
      if (r%head%xnum.eq.0) then
        ! Compute new current limits
        call gelimx(dummy,gux1,gux2,gux,set%unitx(1))
      else
        call newlimx(set,r,error)
        if (error)  return
      endif
      ! Transmit to GreG ?
      write(chgreg,'(A,2(1X,G20.13),A)') 'LIMITS ',gux1,gux2,' = ='
      call gr_exec(chgreg)
      error = gr_error()
      if (error)  return
    endif
    !
    if (doy) then
      if (uy1.eq.uy2) then
        call class_message(seve%e,rname,'No range in Y')
        error = .true.
        return
      endif
      ! Compute new current Y limits
      guy1 = uy1
      guy2 = uy2
      guy = (gy2-gy1)/(guy2-guy1)
      ! Transmit to GreG ?
      write(chgreg,'(A,2(1X,G20.13),A)') 'LIMITS = = ',guy1,guy2
      call gr_exec(chgreg)
      error = gr_error()
      if (error)  return
    endif
    !
    if (doz) then
      if (uz1.eq.uz2) then
        call class_message(seve%e,rname,'No range in Z')
        error = .true.
        return
      endif
      ! Compute new current Z limits
      puz1 = 0.5+nint(uz1)
      puz2 = 0.5+nint(uz2)
      guz1 = puz1
      guz2 = puz2
      guz  = (gy2-gy1)/(guz2-guz1)
    endif
    !
  endif
  !
100 format('MODE ',a,1x,1pg15.8,1x,1pg15.8,1x,a)
  !
contains
  !
  function tounit(kind,unit,x)
    !-------------------------------------------------------------------
    ! Convert a X cursor position to absolute signal frequency (kind
    ! spec)
    !-------------------------------------------------------------------
    real(kind=8) :: tounit
    integer(kind=4),        intent(in) :: kind
    character(len=*),       intent(in) :: unit
    real(kind=plot_length), intent(in) :: x
    !
    if (kind.eq.kind_cont) then
      if (unit.eq.'A') then
        tounit = x*class_setup_get_fangle()
      else
        tounit = x
      endif
    else  ! kind_spec
      if (unit.eq.'F') then
        tounit = x+gfxo
      elseif (unit.eq.'I') then
        tounit = x+gixo
      else
        tounit = x
      endif
    endif
  end function tounit
  !
  subroutine setmod_cursor(kind,axis,unit,v1,v2,error)
    use plot_formula
    !---------------------------------------------------------------------
    ! Get min-max values from cursor
    !---------------------------------------------------------------------
    integer(kind=4),        intent(in)    :: kind   ! Kind of data
    character(len=*),       intent(in)    :: axis   ! Axis name
    character(len=*),       intent(in)    :: unit   ! Unit name
    real(kind=plot_length), intent(out)   :: v1     ! Lower value
    real(kind=plot_length), intent(out)   :: v2     ! Upper value
    logical,                intent(inout) :: error  ! Logical error flag
    ! Local
    real(kind=4) :: x,y
    character(len=1) :: ch
    !
    write(6,*) 'Type any char to set ',axis,' lower and upper limits'
    !
    call gtcurs(x,y,ch,error)
    if (error)  return
    if (axis.eq.'X') then
      v1 = gux1 + (x-gx1)/gux
    elseif (axis.eq.'Y') then
      v1 = guy1 + (y-gy1)/guy
    elseif (axis.eq.'Z') then
      v1 = guz1 + (y-gy1)/guz
    else
      error = .true.
      return
    endif
    write(6,10) axis,'1 = ',tounit(kind,unit,v1)  ! Feedback in terminal in user-friendly unit
    !
    call gtcurs(x,y,ch,error)
    if (error)  return
    if (axis.eq.'X') then
      v2 = gux1 + (x-gx1)/gux
    elseif (axis.eq.'Y') then
      v2 = guy1 + (y-gy1)/guy
    elseif (axis.eq.'Z') then
      v2 = guz1 + (y-gy1)/guz
    else
      error = .true.
      return
    endif
    write(6,10) axis,'2 = ',tounit(kind,unit,v2)  ! Feedback in terminal in user-friendly unit
    !
    10 format(a2,a,f12.3)
    !
  end subroutine setmod_cursor
  !
end subroutine setmod
