c
c     Copyright (c) 1999,2000, Compaq Computer Corporation
c
c     See the file "license.terms" for information on usage and redistribution
c     of this file, and for a DISCLAIMER OF ALL WARRANTIES.
c
c   Routines to get plot annotations interactively and store them
c
      subroutine anno_annotate_graph(window_id)
      implicit none
c
      integer window_id
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'io.cmn'
      include 'annotations.cmn'
c
c     locals
c
      integer err_stat, temp_ws_id, temp_ws_type, lookup_ws_id
      character*1 ch
      character*75 err_mess
c
      if( .NOT. gks_is_open ) then
         call plt$error_message('anno_annotate_graph',
     1      'Window never opened before')
      endif
c
      temp_ws_id = lookup_ws_id(window_id)
      if( temp_ws_id .eq. PLT$EMPTY_WINDOW_SLOT ) then
c        Bad window id
         call plt$error_message('anno_annotate_graph',
     1      'Bad window id')
         return
      endif
c
c     Annotations only work on workstations
      temp_ws_type = ws_struct(temp_ws_id)%type
      if( temp_ws_type .ne. GKS$K_VSII .and.
     1    temp_ws_type .ne. GKS$K_VSII_GPX .and.
     2    temp_ws_type .ne. GKS$K_DECWINDOWS .and.
     3    temp_ws_type .ne. GKS$K_MOTIF ) then
                  call plt$error_message('anno_annotate_graph',
     1      'Annotation routines are only for workstations')
         return
      endif
c
      err_mess = ' '
c
1000  call clear_screen
      write(luttyo,100) err_mess
100   format(' ',a)
      err_mess = ' '
      write(luttyo,150)
150   format(' ','Graph annotation loop:'//
     1       ' ','    A -- Add angled line or arrow'/
     1       ' ','    B -- Add box'/
     1       ' ','    C -- Add elliptical curve'/
     1       ' ','    H -- Add horizontal line or arrow'/
     1       ' ','    M -- Add marker'/
     1       ' ','    T -- Add text'/
     1       ' ','    V -- Add vertical line or arrow'//
     1       ' ','    D -- Delete item'/
     1       ' ','    P -- Change position of items'//
     1       ' ','    R -- Restore previous annotations'//
     1       ' ','    E,Q -- Exit annotation loop'/)
      call get_char(ch,'Enter annotation type: ',1)
      call upcase(ch)
      if( ch .eq. 'A' ) then
         call anno_add_line_note(window_id, 3, err_stat)
      else if( ch .eq. 'B' ) then
         call anno_add_box_note(window_id, err_stat)
      else if( ch .eq. 'C' ) then
         call anno_add_ellipse_note(window_id, err_stat)
      else if( ch .eq. 'D' ) then
         call anno_delete_notes(window_id, err_stat)
      else if( ch .eq. 'H' ) then
         call anno_add_line_note(window_id, 1, err_stat)
      else if( ch .eq. 'M' ) then
         call anno_add_marker_note(window_id, err_stat)
      else if( ch .eq. 'P' ) then
         call anno_position_notes(window_id, err_stat)
      else if( ch .eq. 'T' ) then
         call anno_add_text_note(window_id, err_stat)
      else if( ch .eq. 'V' ) then
         call anno_add_line_note(window_id, 2, err_stat)
      else if( ch .eq. 'R' ) then
         call anno_restore_notes_from_file(window_id, err_stat)
      else if( ch .eq. 'E' .or. ch .eq. 'Q' ) then
         goto 2000
      else
         call beep_terminal
         write(err_mess,200) ch
200      format('Illegal menu item: ',a1)
      endif
      if( err_stat .ne. PLT$NORMAL ) then
         call beep_terminal
         if( err_stat .eq. PLT$OUT_OF_NOTE_STORAGE ) then
            err_mess = 'Error: Reached limit for number of notes ' //
     1                 'of this type'
         else if ( err_stat .eq. PLT$BAD_NOTE_TYPE) then
            err_mess = 'Internal error: bad note type'
         else if ( err_stat .eq. PLT$INPUT_CANCELLED) then
            err_mess = 'Input cancelled'
         else if ( err_stat .eq. PLT$BAD_NOTE_ID) then
            err_mess = 'Internal error: bad note id'
         else if ( err_stat .eq. PLT$NOTE_ALREADY_FREE) then
            err_mess = 'Internal error: note structure already free'
         else
            err_mess = 'Internal error: unknown error'
         endif
      endif
      goto 1000
c
c     Save state of annotations in external file
2000  call anno_write_notes_to_file(window_id,err_stat)
      return
      end
c
      subroutine anno_add_box_note(window_id, err_stat)
      implicit none
c
c     Get annotation box
c
      integer window_id, err_stat
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'io.cmn'
      include 'annotations.cmn'
      include 'defaults.cmn'
      include 'gui.cmn'
c
c     locals
c
      integer box_id, work_id, int_vec(1),
     1        xform, pet_type, dev_num, data_record(2),
     1        record_buffer_length, input_status
      integer lookup_ws_id, anno_alloc_note_struct, pm_color_to_index
      real    echo_area(4), x, y
c
c     Menu stuff
      character*32 temp_str
      integer item_number, i
      character*80 string
      character*3  ch_filled
      logical eof, reuse_last_input, color0_invisible
c
c     Initialize
      reuse_last_input = .FALSE.
c
      err_stat = PLT$NORMAL
      box_id = anno_alloc_note_struct(BOX_NOTE_TYPE, err_stat)
      if( err_stat .ne. PLT$NORMAL ) return
c
c     mark as used
      box_notes(box_id)%window = window_id
c
      if( lgui ) then
c
c        Get information from gui transfer area
         if( gui_xfer_icount .ne. 2 .or. gui_xfer_lcount .ne. 1 ) then
            err_stat = PLT$BAD_GUI_GET
            box_notes(box_id)%window = -1
            return
         endif
c
         box_notes(box_id)%color = gui_xfer_ivector(1)  ! (integer)
         box_notes(box_id)%filled = gui_xfer_lvector(1) ! (logical)
         box_notes(box_id)%fill_color = gui_xfer_ivector(2) ! (integer)
         box_notes(box_id)%thickness = 1.0  ! Not set yet...
         box_notes(box_id)%use_graph_coords = .FALSE.  ! Not set yet...
c
      else
c     BEGIN terminal based input
c
100   call clear_screen
      call display_string(1 ,1 ,'  Annotate box menu',20,0)
      call display_string(3 ,1 ,' 1) Outline color ',19,0)
      call display_string(4 ,1 ,' 2) Interior color',19,0)
      call display_string(5 ,1 ,' 3) Fill interior ',19,0)
      call display_string(6 ,1 ,' 4) Attach to ',19,0)
c
      i = box_notes(box_id)%color
      if( i .lt. 0 .or. i .gt. MAX_RGB_VALUES ) i = MAX_RGB_VALUES
      call display_string(3 ,21,color_names(i),15,1)
      call display_intp  (3 ,38,i,3)
c
      i = box_notes(box_id)%fill_color
      if( i .lt. 0 .or. i .gt. MAX_RGB_VALUES ) i = MAX_RGB_VALUES
      call display_string(4 ,21,color_names(i),15,1)
      call display_intp  (4 ,38,i,3)
c
      if( box_notes(box_id)%filled ) then
         ch_filled = 'yes'
      else
         ch_filled = ' no'
      endif
      call display_string(5 ,21,ch_filled,3,0)
c
      if( box_notes(box_id)%use_graph_coords ) then
         temp_str = 'graph'
      else
         temp_str = 'background'
      endif
      call display_string(6 ,21,temp_str,10,1)
c
      box_notes(box_id)%thickness = 1.0
c
200   call display_prompt(
     1 'Enter number of item to modify, or Repaint, Add, Quit:')
      if( reuse_last_input ) then
         reuse_last_input = .FALSE.
      else
         call read_from_input_area(string, eof)
      endif
      if( eof ) goto 200
      call upcase(string)
      if( string(1:1) .eq. 'Q' ) then
c        Mark box note as free
         box_notes(box_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else if (string(1:1) .eq. 'A' ) then
         goto 300
      else if (string(1:1) .eq. 'R' ) then
         goto 100
      else
         read(string,*,err=250) item_number
         if ( item_number .eq. 1 ) then
            call get_string_with_prompt(temp_str,
     1      'Enter color name (enter ? for list of colors)')
            if( temp_str .eq. '?' ) then
c              Display color names and then repaint screen
               color0_invisible = .FALSE.
               call pm_display_color_list(color0_invisible)
               reuse_last_input = .TRUE.
               goto 100
            endif
            int_vec(1) = pm_color_to_index(temp_str)
            if( int_vec(1) .lt. 0 ) then
               call display_message('Illegal value')
            else
               box_notes(box_id)%color = int_vec(1)
               i = box_notes(box_id)%color
               call display_string(3 ,21,color_names(i),15,1)
               call display_intp  (3 ,38,i,3)
            endif
         else if ( item_number .eq. 2 ) then
            call get_string_with_prompt(temp_str,
     1      'Enter color name (enter ? for list of colors)')
            if( temp_str .eq. '?' ) then
c              Display color names and then repaint screen
               color0_invisible = .FALSE.
               call pm_display_color_list(color0_invisible)
               reuse_last_input = .TRUE.
               goto 100
            endif
            int_vec(1) = pm_color_to_index(temp_str)
            if( int_vec(1) .lt. 0 ) then
               call display_message('Illegal value')
            else
               box_notes(box_id)%fill_color = int_vec(1)
               i = box_notes(box_id)%fill_color
               call display_string(4 ,21,color_names(i),15,1)
               call display_intp  (4 ,38,i,3)
            endif
         else if ( item_number .eq. 3 ) then
            box_notes(box_id)%filled = .NOT. box_notes(box_id)%filled
            if( box_notes(box_id)%filled ) then
               ch_filled = 'yes'
            else
               ch_filled = 'no'
            endif
            call display_string(5 ,21,ch_filled,3,0)
         else if ( item_number .eq. 4 ) then
            box_notes(box_id)%use_graph_coords =
     1           .NOT. box_notes(box_id)%use_graph_coords
            if( box_notes(box_id)%use_graph_coords ) then
               temp_str = 'graph'
            else
               temp_str = 'background'
            endif
            call display_string(6, 21, temp_str, 10, 1)
         else
            call display_message('Item number out of range')
         endif
      endif
      goto 200
c
250   call display_message('Illegal input')
      goto 200
c
300   continue
c
      write(luttyo,310) PM_CANCEL_BUTTON
310   format(' ',
     1   'To draw box, enter lower left and upper right corners.'/
     1   ' ','Use ',a,' mouse button to cancel input')
c
c     END terminal based input
      endif
c
c     Activate window and set up normalization transformations
      work_id = lookup_ws_id(window_id)
      if( work_id .eq. -1 ) then
         err_stat = PLT$BAD_WINDOW_ID
         box_notes(box_id)%window = -1
         return
      endif
c
      call anno_setup_ws_for_locator(window_id, echo_area, err_stat)
c
c     Put locator at initial point
c     Use echo type 2 to get cross hairs
      dev_num = 1
      xform = 1
      pet_type = 2
c     gks$init_locator modifies record_buffer_length.
c     Reset it to expected value.
      record_buffer_length = 0
      call gks$init_locator(work_id, dev_num, 0.5, 0.5,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
      call gks$request_locator(work_id, dev_num, input_status,
     1     xform, x, y)
      if( input_status .ne. 1 ) then
c        Input was cancelled, mark box as free
         box_notes(box_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else
         if( box_notes(box_id)%use_graph_coords ) then
            call anno_norm_to_graph_coords(x, y, 1,
     1           box_notes(box_id)%x1, box_notes(box_id)%y1)
         else
            box_notes(box_id)%x1 = x
            box_notes(box_id)%y1 = y
         endif
      endif
c
c     Get upper right corner
c     Use echo type 5 to get rubber band box
      pet_type = 5
      record_buffer_length = 8
      data_record(1) = GKS$K_ACF_POLYLINE
      data_record(2) = GKS$K_ACF_CURRENT
      call gks$init_locator(work_id, dev_num,
     1     x, y,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
      call gks$request_locator(work_id, dev_num, input_status,
     1     xform, x, y)
      if( input_status .ne. 1 ) then
c        Input was cancelled, mark box as free
         box_notes(box_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else
         if( box_notes(box_id)%use_graph_coords ) then
            call anno_norm_to_graph_coords(x, y, 1,
     1           box_notes(box_id)%x2, box_notes(box_id)%y2)
         else
            box_notes(box_id)%x2 = x
            box_notes(box_id)%y2 = y
         endif
      endif
c
c     Now, echo box to workstation!
      call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                               GKS$K_DETECTABLE)
      call anno_draw_box(box_id)
c
      box_notes(box_id)%segment = cur_segment_id
c
1000  continue
c     Deactivate window
      call deactivate_plot_device
c
      return
      end
c
      subroutine anno_add_line_note(window_id, type, err_stat)
      implicit none
c
c     Get line annotation. Type is {1,2,3} == {horizontal, vertical,
c     or angled}
c
      integer window_id, type, err_stat
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'io.cmn'
      include 'annotations.cmn'
      include 'defaults.cmn'
      include 'gui.cmn'
c
c     locals
c
      integer line_id, work_id, int_vec(1),
     1        xform, pet_type, dev_num, data_record(1),
     1        record_buffer_length, input_status
      integer lookup_ws_id, anno_alloc_note_struct,
     1        pm_color_to_index, pm_linetype_to_index
      real    echo_area(4), x, y
c
c     Menu stuff
      integer item_number, i
      character*80 string
      character*32 temp_str
      character*8  ch_arrow
      logical eof, reuse_last_input, color0_invisible
c
c     Initialize
      reuse_last_input = .FALSE.
c
      err_stat = PLT$NORMAL
      line_id = anno_alloc_note_struct(LINE_NOTE_TYPE, err_stat)
      if( err_stat .ne. PLT$NORMAL ) return
c
c     mark as used
      line_notes(line_id)%window = window_id
c
      if( lgui ) then
         if( gui_xfer_icount .ne. 3 ) then
            err_stat = PLT$BAD_GUI_GET
            line_notes(line_id)%window = -1
            return
         endif
c
         line_notes(line_id)%color = gui_xfer_ivector(1) ! Integer
         line_notes(line_id)%type  = gui_xfer_ivector(2) ! Integer
         line_notes(line_id)%arrow = gui_xfer_ivector(3) ! Integer
         line_notes(line_id)%thickness = 1.0  ! Not set yet
         line_notes(line_id)%use_graph_coords = .FALSE. ! Not see yet
c
      else
c
100   call clear_screen
      call display_string(1 ,1 ,'  Annotate line menu',21,0)
      call display_string(3 ,1 ,' 1) Color    ',14,0)
      call display_string(4 ,1 ,' 2) Arrow    ',14,0)
      call display_string(5 ,1 ,' 3) Linetype ',14,0)
      call display_string(6 ,1 ,' 4) Attach to ',14,0)
c
      i = line_notes(line_id)%color
      if( i .lt. 0 .or. i .gt. MAX_RGB_VALUES ) i = MAX_RGB_VALUES
      call display_string(3,16,color_names(i),15,1)
      call display_intp  (3,33,i,3)
c
      if( line_notes(line_id)%arrow .eq. 1 ) then
         ch_arrow = 'single'
      else if( line_notes(line_id)%arrow .eq. 2 ) then
         ch_arrow = 'double'
      else
         ch_arrow = '  none'
      endif
      call display_string(4 ,16,ch_arrow,8,0)

      i = line_notes(line_id)%type
      if( i .lt. 0 .or. i .gt. MAX_LINETYPE_VALUES )
     1    i = MAX_LINETYPE_VALUES
      call display_string(5,16,line_names(i),15,1)
      call display_intp  (5,33,i,3)
c
      if( line_notes(line_id)%use_graph_coords ) then
         temp_str = 'graph'
      else
         temp_str = 'background'
      endif
      call display_string(6 ,16,temp_str,10,1)
c
      line_notes(line_id)%thickness = 1.0
c
200   call display_prompt(
     1 'Enter number of item to modify, or Repaint, Add, Quit:')
      if( reuse_last_input ) then
         reuse_last_input = .FALSE.
      else
         call read_from_input_area(string, eof)
      endif
      if( eof ) goto 200
      call upcase(string)
      if( string(1:1) .eq. 'Q' ) then
c        Mark box note as free
         line_notes(line_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else if (string(1:1) .eq. 'A' ) then
         goto 300
      else if (string(1:1) .eq. 'R' ) then
         goto 100
      else
         read(string,*,err=250) item_number
         if ( item_number .eq. 1 ) then
            call get_string_with_prompt(temp_str,
     1      'Enter color name (enter ? for list of colors)')
            if( temp_str .eq. '?' ) then
c              Display color names and then repaint screen
               color0_invisible = .FALSE.
               call pm_display_color_list(color0_invisible)
               reuse_last_input = .TRUE.
               goto 100
            endif
            int_vec(1) = pm_color_to_index(temp_str)
            if( int_vec(1) .lt. 0 ) then
               call display_message('Illegal value')
            else
               line_notes(line_id)%color = int_vec(1)
               i = line_notes(line_id)%color
               call display_string(3 ,16,color_names(i),15,1)
               call display_intp  (3 ,33,i,3)
            endif
         else if ( item_number .eq. 2 ) then
            call get_ints_with_prompt(int_vec, 1,
     1         'Enter 0==no arrow, 1==single arrow, 2==double arrow ')
            if( int_vec(1) .lt. 0 .or. int_vec(1) .gt. 2 ) then
               call display_message('Illegal value')
            else
               line_notes(line_id)%arrow = int_vec(1)            
               if( line_notes(line_id)%arrow .eq. 1 ) then
                  ch_arrow = 'single'
               else if( line_notes(line_id)%arrow .eq. 2 ) then
                  ch_arrow = 'double'
               else
                  ch_arrow = '  none'
               endif
               call display_string(4 ,16,ch_arrow,8,0)
            endif
         else if ( item_number .eq. 3 ) then
            call get_string_with_prompt(temp_str,
     1      'Enter line types (enter ? for list of types)')
            if( temp_str .eq. '?' ) then
c              Display linetypes and then repaint screen
               call pm_display_linetype_list
               reuse_last_input = .TRUE.
               goto 100
            endif
            int_vec(1) = pm_linetype_to_index(temp_str)
            if( int_vec(1) .lt. 0 ) then
               call display_message('Illegal value')
            else
               line_notes(line_id)%type = int_vec(1)
               i = line_notes(line_id)%type
               call display_string(5 ,16,line_names(i),15,1)
               call display_intp  (5 ,33,i,3)
            endif
         else if ( item_number .eq. 4 ) then
            line_notes(line_id)%use_graph_coords =
     1           .NOT. line_notes(line_id)%use_graph_coords
            if( line_notes(line_id)%use_graph_coords ) then
               temp_str = 'graph'
            else
               temp_str = 'background'
            endif
            call display_string(6, 16, temp_str, 10, 1)
         else
            call display_message('Item number out of range')
         endif
      endif
      goto 200
c
250   call display_message('Illegal input')
      goto 200
c
300   continue
c
      if( line_notes(line_id)%arrow .eq. 1 ) then
         write(luttyo,301) PM_CANCEL_BUTTON
301      format(' ','To draw arrow, enter two points.'/
     1   ' ','First point is arrow tail, second is arrow head.'
     1   ' ','Use ',a,' mouse button to cancel input')
      else
         write(luttyo,302) PM_CANCEL_BUTTON
302      format(' ','To draw line, enter two points.'/
     1   ' ','Use ',a,' mouse button to cancel input')
      endif
      endif
c
c     Activate window and set up normalization transformations
      work_id = lookup_ws_id(window_id)
      if( work_id .eq. -1 ) then
         err_stat = PLT$BAD_WINDOW_ID
         line_notes(line_id)%window = -1
         return
      endif
c
      call anno_setup_ws_for_locator(window_id, echo_area, err_stat)
c
c     Put locator at initial point
c     Use echo type 2 to get cross hairs
      dev_num = 1
      xform = 1
      pet_type = 2
c     gks$init_locator modifies record_buffer_length.
c     Reset it to expected value.
      record_buffer_length = 0
      call gks$init_locator(work_id, dev_num, 0.5, 0.5,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
      call gks$request_locator(work_id, dev_num, input_status,
     1                         xform, x, y)
      if( input_status .ne. 1 ) then
c        Input was cancelled, mark line as free
         line_notes(line_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else
         if( line_notes(line_id)%use_graph_coords ) then
            call anno_norm_to_graph_coords(x, y, 1,
     1           line_notes(line_id)%x1, line_notes(line_id)%y1)
         else
            line_notes(line_id)%x1 = x
            line_notes(line_id)%y1 = y
         endif
      endif
c
c     Get second point
c     Use echo type 4 to get rubber band line
      pet_type = 4
      record_buffer_length = 4
      data_record(1) = GKS$K_ACF_CURRENT
      call gks$init_locator(work_id, dev_num,
     1     x, y,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
      call gks$request_locator(work_id, dev_num, input_status,
     1     xform, x, y)
      if( input_status .ne. 1 ) then
c        Input was cancelled, mark line as free
         line_notes(line_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else
         if( line_notes(line_id)%use_graph_coords ) then
            call anno_norm_to_graph_coords(x, y, 1,
     1           line_notes(line_id)%x2, line_notes(line_id)%y2)
         else
            line_notes(line_id)%x2 = x
            line_notes(line_id)%y2 = y
         endif
      endif
c
      if( type .eq. 1 ) then
c        Force horizontal line
         line_notes(line_id)%y2 = line_notes(line_id)%y1
      else if ( type .eq. 2 ) then
c        Force vertical line
         line_notes(line_id)%x2 = line_notes(line_id)%x1
      endif      
c
c     Now, echo line to workstation!
      call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                               GKS$K_DETECTABLE)
      call anno_draw_line(line_id)
c
      line_notes(line_id)%segment = cur_segment_id
c
1000  continue
c     Deactivate window
      call deactivate_plot_device
c
      return
      end
c
      subroutine anno_add_marker_note(window_id, err_stat)
      implicit none
c
      integer window_id, err_stat
c
c     Get annotation marker
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'io.cmn'
      include 'annotations.cmn'
      include 'defaults.cmn'
      include 'gui.cmn'
c
c     locals
c
      integer marker_id, work_id, int_vec(1),
     1        xform, pet_type, dev_num, data_record(1),
     1        record_buffer_length, input_status
      integer lookup_ws_id, anno_alloc_note_struct,
     1        pm_color_to_index, pm_symbol_to_index
      real    echo_area(4), real_vec(1), x, y
c
c     Menu stuff
      integer item_number, i
      character*80 string
      character*32 temp_str
      logical eof, reuse_last_input, color0_invisible
c
c
c     Initialize
      reuse_last_input = .FALSE.
c
      err_stat = PLT$NORMAL
      marker_id = anno_alloc_note_struct(MARKER_NOTE_TYPE, err_stat)
      if( err_stat .ne. PLT$NORMAL ) return
c
c     mark as used
      marker_notes(marker_id)%window = window_id
c
      if( lgui ) then
         if( gui_xfer_icount .ne. 2 .or. gui_xfer_rcount .ne. 1 ) then
            err_stat = PLT$BAD_GUI_GET
            marker_notes(marker_id)%window = -1
            return
         endif
c
         marker_notes(marker_id)%color = gui_xfer_ivector(1) ! Integer
         marker_notes(marker_id)%type  = gui_xfer_ivector(2) ! Integer
         marker_notes(marker_id)%size  = gui_xfer_rvector(1) ! Real
         marker_notes(marker_id)%use_graph_coords  = .FALSE. ! Not yet
      else
c
100   call clear_screen
      call display_string(1 ,1 ,'  Annotate marker menu',23,0)
      call display_string(3 ,1 ,' 1) Color ',11,0)
      call display_string(4 ,1 ,' 2) Type  ',11,0)
      call display_string(5 ,1 ,' 3) Size  ',11,0)
      call display_string(6 ,1 ,' 4) Attach to ',14,0)
c
      i = marker_notes(marker_id)%color
      if( i .lt. 0 .or. i .gt. MAX_RGB_VALUES ) i = MAX_RGB_VALUES
      call display_string(3 ,16,color_names(i),15,1)
      call display_intp  (3 ,33,i,3)
c
      i = marker_notes(marker_id)%type
      if( i .lt. 0 .or. i .gt. MAX_SYMBOL_VALUES) i = MAX_SYMBOL_VALUES
      call display_string(4, 16, symbol_names(i), 15, 1)
      call display_intp  (4 ,33,i,3)
c
      call display_real  (5 ,16,marker_notes(marker_id)%size,1)
c
      if( marker_notes(marker_id)%use_graph_coords ) then
         temp_str = 'graph'
      else
         temp_str = 'background'
      endif
      call display_string(6 ,16,temp_str,10,1)
c
200   call display_prompt(
     1 'Enter number of item to modify, or Repaint, Add, Quit:')
      if( reuse_last_input ) then
         reuse_last_input = .FALSE.
      else
         call read_from_input_area(string, eof)
      endif
      if( eof ) goto 200
      call upcase(string)
      if( string(1:1) .eq. 'Q' ) then
c        Mark marker note as free
         marker_notes(marker_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else if (string(1:1) .eq. 'A' ) then
         goto 300
      else if (string(1:1) .eq. 'R' ) then
         goto 100
      else
         read(string,*,err=250) item_number
         if ( item_number .eq. 1 ) then
            call get_string_with_prompt(temp_str,
     1      'Enter color name (enter ? for list of colors)')
            if( temp_str .eq. '?' ) then
c              Display color names and then repaint screen
               color0_invisible = .FALSE.
               call pm_display_color_list(color0_invisible)
               reuse_last_input = .TRUE.
               goto 100
            endif
            int_vec(1) = pm_color_to_index(temp_str)
            if( int_vec(1) .lt. 0 ) then
               call display_message('Illegal value')
            else
               marker_notes(marker_id)%color = int_vec(1)
               i = marker_notes(marker_id)%color
               call display_string(3 ,16,color_names(i),15,1)
               call display_intp  (3 ,33,i,3)
            endif
         else if ( item_number .eq. 2 ) then
            call get_string_with_prompt(temp_str,
     1      'Enter marker type (enter ? for list of types)')
            if( temp_str .eq. '?' ) then
c              Display symbol names and then repaint screen
               call pm_display_symbol_list
               reuse_last_input = .TRUE.
               goto 100
            endif
            int_vec(1) = pm_symbol_to_index(temp_str)
            if( int_vec(1) .lt. 0 ) then
               call display_message('Illegal value')
            else
               marker_notes(marker_id)%type = int_vec(1)
               i = marker_notes(marker_id)%type
               call display_string(4 ,16,symbol_names(i),15,1)
               call display_intp  (4 ,33,i,3)
            endif
         else if ( item_number .eq. 3 ) then
            real_vec(1) = marker_notes(marker_id)%size
            call get_reals_with_prompt(real_vec,1,
     1              'Enter marker size (0.1 < x < 10.0)')
            if( real_vec(1) .lt. 0.1 .or. real_vec(1) .gt. 10.0 ) then
               call display_message('Invalid marker size')
            else
               marker_notes(marker_id)%size = real_vec(1)
               call display_real(5 ,16,marker_notes(marker_id)%size,1)
            endif
         else if ( item_number .eq. 4 ) then
            marker_notes(marker_id)%use_graph_coords =
     1           .NOT. marker_notes(marker_id)%use_graph_coords
            if( marker_notes(marker_id)%use_graph_coords ) then
               temp_str = 'graph'
            else
               temp_str = 'background'
            endif
            call display_string(6, 16, temp_str, 10, 1)
         else
            call display_message('Item number out of range')
         endif
      endif
      goto 200
c
250   call display_message('Illegal input')
      goto 200
c
300   continue
c
      write(luttyo,301) PM_CANCEL_BUTTON
301   format(' ','To draw marker, enter its location.'/
     1   ' ','Use ',a,' mouse button to cancel input')
c
      endif
c
c     Activate window and set up normalization transformations
      work_id = lookup_ws_id(window_id)
      if( work_id .eq. -1 ) then
         err_stat = PLT$BAD_WINDOW_ID
         marker_notes(marker_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         return
      endif
c
      call anno_setup_ws_for_locator(window_id, echo_area, err_stat)
c
c     Put locator at initial point
c     Use echo type 2 to get cross hairs
      dev_num = 1
      xform = 1
      pet_type = 2
      record_buffer_length = 0
      call gks$init_locator(work_id, dev_num, 0.5, 0.5,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
      call gks$request_locator(work_id, dev_num, input_status,
     1     xform, x, y)
      if( input_status .ne. 1 ) then
c        Input was cancelled, mark marker as free
         marker_notes(marker_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else
         if( marker_notes(marker_id)%use_graph_coords ) then
            call anno_norm_to_graph_coords(x, y, 1,
     1           marker_notes(marker_id)%xloc,
     1           marker_notes(marker_id)%yloc)
         else
            marker_notes(marker_id)%xloc = x
            marker_notes(marker_id)%yloc = y
         endif
      endif
c
c     Now, echo marker to workstation!
      call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                               GKS$K_DETECTABLE)
      call anno_draw_marker(marker_id)
c
      marker_notes(marker_id)%segment = cur_segment_id
c
1000  continue
c     Deactivate window
      call deactivate_plot_device
c
      return
      end
c
      subroutine anno_add_text_note(window_id, err_stat)
      implicit none
c
      integer window_id, err_stat
c
c     Get annotation text
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'io.cmn'
      include 'annotations.cmn'
      include 'defaults.cmn'
      include 'gui.cmn'
c
c     locals
c
      integer text_id, work_id, int_vec(1),
     1        xform, pet_type, dev_num, data_record(1),
     2        record_buffer_length, input_status
      logical error_occurred
c
      integer lookup_ws_id, anno_alloc_note_struct,
     1        pm_color_to_index
      real    echo_area(4), real_vec(1), x, y
      character*1 ch
c
c     Menu stuff
      integer item_number, i, ilen, string_len
      character*80 string
      character*32 temp_str
      character*10 ch_orient
      character*6  ch_just
      logical eof, reuse_last_input, color0_invisible
c
c
c     Initialize
      reuse_last_input = .FALSE.
c
      err_stat = PLT$NORMAL
      text_id = anno_alloc_note_struct(TEXT_NOTE_TYPE, err_stat)
      if( err_stat .ne. PLT$NORMAL ) return
c
c     mark as used
      text_notes(text_id)%window = window_id
c
      if( lgui ) then
c       Get stuff from gui area
         if( gui_xfer_icount .ne. 3 .or. gui_xfer_ccount .ne. 1 .or.
     1       gui_xfer_rcount .ne. 1 ) then
            err_stat = PLT$BAD_GUI_GET
            text_notes(text_id)%window = -1
            return
         endif
c
         text_notes(text_id)%text   = gui_xfer_cvector(1)  ! (character)
         text_notes(text_id)%color  = gui_xfer_ivector(1)  ! (integer)
         text_notes(text_id)%orient = gui_xfer_ivector(2)  ! (integer)
         text_notes(text_id)%just   = gui_xfer_ivector(3)  ! (integer)
         text_notes(text_id)%scale  = gui_xfer_rvector(1)  ! (real)
         text_notes(text_id)%use_x_graph_coords = .FALSE.    ! for now
         text_notes(text_id)%use_y_graph_coords = .FALSE.    ! for now
      else
c
100   call clear_screen
      call display_string(1 ,1 ,'  Annotate text menu',20,0)
      call display_string(3 ,1 ,' 1) Label', 9,0)
      call display_string(4 ,1 ,' 2) Justification',17,0)
      call display_string(5 ,1 ,' 3) Orientation',15,0)
      call display_string(6 ,1 ,' 4) Size scale',14,0)
      call display_string(7 ,1 ,' 5) Color',9,0)
      call display_string(8 ,1 ,' 6) Attach to ',14,0)
c
      ilen = string_len(text_notes(text_id)%text)
      call display_string(3, 19,text_notes(text_id)%text,ilen,1)
      if( text_notes(text_id)%just .eq. GKS$K_TEXT_HALIGN_LEFT ) then
         ch_just = 'left'
      elseif(text_notes(text_id)%just .eq. GKS$K_TEXT_HALIGN_CENTER )
     1   then
         ch_just = 'center'
      else
         ch_just = 'right'
      endif
      call display_string(4, 19,ch_just,6,1)
      if( text_notes(text_id)%orient .eq. 0 ) then
         ch_orient = 'horizontal'
      else
         ch_orient = 'vertical'
      endif
      call display_string(5 ,19,ch_orient,10,1)
      call display_real  (6 ,15,text_notes(text_id)%scale,1)
      i = text_notes(text_id)%color
      if( i .lt. 0 .or. i .gt. MAX_RGB_VALUES ) i = MAX_RGB_VALUES
      call display_string(7 ,19,color_names(i),15,1)
      call display_intp  (7 ,33,i,3)
c
c     For now, we only let the interactive user set both
c     x and y graph coordinates flags
      if( text_notes(text_id)%use_x_graph_coords ) then
         temp_str = 'graph'
      else
         temp_str = 'background'
      endif
      call display_string(8 ,19,temp_str,10,1)
c
200   call display_prompt(
     1 'Enter number of item to modify, or Repaint, Add, Quit:')
      if( reuse_last_input ) then
         reuse_last_input = .FALSE.
      else
         call read_from_input_area(string, eof)
      endif
      if( eof ) goto 200
      call upcase(string)
      if( string(1:1) .eq. 'Q' ) then
c        Mark text note as free
         text_notes(text_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else if (string(1:1) .eq. 'A' ) then
         goto 300
      else if (string(1:1) .eq. 'R' ) then
         goto 100
      else
         read(string,*,err=250) item_number
         if ( item_number .eq. 1 ) then
c           Label
            call get_string_with_prompt(text_notes(text_id)%text,
     1           'Enter annotation text')
            ilen = string_len(text_notes(text_id)%text)
            call display_string(3, 19,text_notes(text_id)%text,ilen,1)
         else if ( item_number .eq. 2 ) then
c           Justification
            call get_string_with_prompt(ch,
     1         'Enter justfication (left,center,right)')
            call upcase(ch)
            if( ch .eq. 'L' ) then
               text_notes(text_id)%just = GKS$K_TEXT_HALIGN_LEFT
               ch_just = 'left'
            else if (ch .eq. 'C' ) then
               text_notes(text_id)%just = GKS$K_TEXT_HALIGN_CENTER
               ch_just = 'center'
            else if( ch .eq. 'R' ) then
               text_notes(text_id)%just = GKS$K_TEXT_HALIGN_RIGHT
               ch_just = 'right'
            else
               call display_message('Invalid justification')
            endif
            call display_string(4, 19,ch_just,6,1)
         else if ( item_number .eq. 3 ) then
c           Orientation
            if( text_notes(text_id)%orient .eq. 0 ) then
               text_notes(text_id)%orient = 1
               ch_orient = 'vertical'
            else
               text_notes(text_id)%orient = 0
               ch_orient = 'horizontal'
            endif
            call display_string(5 ,19,ch_orient,10,1)
         else if ( item_number .eq. 4 ) then
            real_vec(1) = text_notes(text_id)%scale
            call get_reals_with_prompt(real_vec,1,
     1              'Enter text scale (0.1 < x < 10.0)')
            if( real_vec(1) .lt. 0.1 .or. real_vec(1) .gt. 10.0 ) then
               call display_message('Invalid text scale factor')
            else
               text_notes(text_id)%scale = real_vec(1)
            endif
            call display_real  (6 ,15,text_notes(text_id)%scale,1)
         else if ( item_number .eq. 5 ) then
            call get_string_with_prompt(temp_str,
     1      'Enter color name (enter ? for list of colors)')
            if( temp_str .eq. '?' ) then
c              Display color names and then repaint screen
               color0_invisible = .FALSE.
               call pm_display_color_list(color0_invisible)
               reuse_last_input = .TRUE.
               goto 100
            endif
            int_vec(1) = pm_color_to_index(temp_str)
            if( int_vec(1) .lt. 0 ) then
               call display_message('Illegal value')
            else
               text_notes(text_id)%color = int_vec(1)
               i = text_notes(text_id)%color
               call display_string(7 ,19,color_names(i),15,1)
               call display_intp  (7 ,33,i,3)
            endif
         else if ( item_number .eq. 6 ) then
            text_notes(text_id)%use_x_graph_coords =
     1           .NOT. text_notes(text_id)%use_x_graph_coords
            text_notes(text_id)%use_y_graph_coords =
     1           .NOT. text_notes(text_id)%use_y_graph_coords
            if( text_notes(text_id)%use_x_graph_coords ) then
               temp_str = 'graph'
            else
               temp_str = 'background'
            endif
            call display_string(8, 19, temp_str, 10, 1)
         else
            call display_message('Item number out of range')
         endif
      endif
      goto 200
c
250   call display_message('Illegal input')
      goto 200
c
300   continue
c
      write(luttyo,301) PM_CANCEL_BUTTON
301   format(' ','Enter text location with mouse.'/
     1       ' ','Use ',a,' mouse button to cancel input')
      endif
c
c     Activate window and set up normalization transformations
      work_id = lookup_ws_id(window_id)
      if( work_id .eq. -1 ) then
         err_stat = PLT$BAD_WINDOW_ID
         text_notes(text_id)%window = -1
         return
      endif
c
      call anno_setup_ws_for_locator(window_id, echo_area, err_stat)
c
c     Put locator at initial point
c     Use echo type 2 to get cross hairs
      dev_num = 1
      xform = 1
      pet_type = 2
      record_buffer_length = 0
      call gks$init_locator(work_id, dev_num, 0.5, 0.5,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
      call gks$request_locator(work_id, dev_num, input_status,
     1     xform, x, y)
      if( input_status .ne. 1 ) then
c        Input was cancelled, mark text as free
         text_notes(text_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else
c        Note: change code below if we let the interactive user
c        change both x and y graph flags
         if( text_notes(text_id)%use_x_graph_coords ) then
            call anno_norm_to_graph_coords(x, y, 1,
     1           text_notes(text_id)%xloc, text_notes(text_id)%yloc)
         else
            text_notes(text_id)%xloc = x
            text_notes(text_id)%yloc = y
         endif
      endif
c
c     Now, echo text to workstation!
c
      call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                               GKS$K_DETECTABLE)
      call anno_draw_text(text_id, work_id, error_occurred)
      if( error_occurred ) then
c        Illegal mathmode input, mark text as free
         text_notes(text_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      endif
c
      text_notes(text_id)%segment = cur_segment_id
c
1000  continue
c     Deactivate window
      call deactivate_plot_device
c
      return
      end
c
      subroutine anno_add_ellipse_note(window_id, err_stat)
      implicit none
c
c     Get elliptical curve
c
      integer window_id, err_stat
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'io.cmn'
      include 'annotations.cmn'
      include 'gui.cmn'
c
c     locals
c
      integer ellipse_id, work_id,
     1        xform, pet_type, dev_num, data_record(2),
     1        record_buffer_length, input_status
      integer lookup_ws_id, anno_alloc_note_struct
      integer last_segment_id
      real    x1, x2, x3, y1, y2, y3, xmid, ymid, echo_area(4),
     1        timeout, x, y
c
c     Menu stuff
      integer item_number, i, ilen, string_len
      character*80 string
      character*32 temp_str
      logical eof, reuse_last_input
c
c     Variables for event mode input
      logical start_segment, lfirst
      integer echo_mode, input_mode, write_mode, class
c
      err_stat = PLT$NORMAL
      ellipse_id = anno_alloc_note_struct(ELLIPSE_NOTE_TYPE, err_stat)
      if( err_stat .ne. PLT$NORMAL ) return
c
c     mark as used
      ellipse_notes(ellipse_id)%window = window_id
c
      ellipse_notes(ellipse_id)%color = 1
      ellipse_notes(ellipse_id)%thickness = 1.0
      if( lgui ) then
         ellipse_notes(ellipse_id)%use_graph_coords = .FALSE.  ! Not yet
      else
c
100   call clear_screen
      call display_string(1 ,1 ,'  Annotate elliptical arc menu',20,0)
      call display_string(3 ,1 ,' 1) Attach to ',14,0)
c
      if( ellipse_notes(ellipse_id)%use_graph_coords ) then
         temp_str = 'graph'
      else
         temp_str = 'background'
      endif
      call display_string(3 ,19,temp_str,10,1)
c
200   call display_prompt(
     1 'Enter number of item to modify, or Repaint, Add, Quit:')
      if( reuse_last_input ) then
         reuse_last_input = .FALSE.
      else
         call read_from_input_area(string, eof)
      endif
      if( eof ) goto 200
      call upcase(string)
      if( string(1:1) .eq. 'Q' ) then
c        Mark text note as free
         ellipse_notes(ellipse_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      else if (string(1:1) .eq. 'A' ) then
         goto 300
      else if (string(1:1) .eq. 'R' ) then
         goto 100
      else
         read(string,*,err=250) item_number
         if ( item_number .eq. 1 ) then
            ellipse_notes(ellipse_id)%use_graph_coords =
     1           .NOT. ellipse_notes(ellipse_id)%use_graph_coords
            if( ellipse_notes(ellipse_id)%use_graph_coords ) then
               temp_str = 'graph'
            else
               temp_str = 'background'
            endif
            call display_string(3, 19, temp_str, 10, 1)
         else
            call display_message('Item number out of range')
         endif
      endif
      goto 200
c
250   call display_message('Illegal input')
      goto 200
c
300   continue
c
         call clear_screen
         write(luttyo,400) PM_CANCEL_BUTTON
400      format(//
     1      ' ','Step 1: Enter bounding box for elliptical arc:'/
     1      ' ','Use mouse button one to enter lower left and upper ',
     1          'right corners.'/
     1      ' ','Use ',a,' mouse button to cancel input')
      endif
c
c     Activate window and set up normalization transformations
      work_id = lookup_ws_id(window_id)
      if( work_id .eq. -1 ) then
         err_stat = PLT$BAD_WINDOW_ID
         ellipse_notes(ellipse_id)%window = -1
         return
      endif
c
      call anno_setup_ws_for_locator(window_id, echo_area, err_stat)
c
c     Put locator at initial point
c     Use echo type 2 to get cross hairs
      dev_num = 1
      xform = 1
      pet_type = 2
c     gks$init_locator modifies record_buffer_length.
c     Reset it to expected value.
      record_buffer_length = 0
      call gks$init_locator(work_id, dev_num, 0.5, 0.5,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
      call gks$request_locator(work_id, dev_num, input_status,
     1     xform, x1, y1)
      if( input_status .ne. 1 ) then
c        Input was cancelled, mark ellipse as free
         ellipse_notes(ellipse_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      endif
c
c     Get upper right corner
c     Use echo type 5 to get rubber band box
      pet_type = 5
      record_buffer_length = 8
      data_record(1) = GKS$K_ACF_POLYLINE
      data_record(2) = GKS$K_ACF_CURRENT
      call gks$init_locator(work_id, dev_num,
     1     x1, y1,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
      call gks$request_locator(work_id, dev_num, input_status,
     1     xform, x2, y2)
      if( input_status .ne. 1 ) then
c        Input was cancelled, mark ellipse as free
         ellipse_notes(ellipse_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      endif
c
c     Now, echo ellipse to workstation!
      if( ellipse_notes(ellipse_id)%use_graph_coords ) then
         call anno_norm_to_graph_coords(x1, y1, 1, x, y)
         ellipse_notes(ellipse_id)%x1 = x
         ellipse_notes(ellipse_id)%y1 = y
         call anno_norm_to_graph_coords(x2, y2, 1, x, y)
         ellipse_notes(ellipse_id)%x2 = x
         ellipse_notes(ellipse_id)%y2 = y
      else
         ellipse_notes(ellipse_id)%x1 = x1
         ellipse_notes(ellipse_id)%x2 = x2
         ellipse_notes(ellipse_id)%y1 = y1
         ellipse_notes(ellipse_id)%y2 = y2
      endif
**      call anno_draw_ellipse(ellipse_id, .FALSE.)
      last_segment_id = cur_segment_id
      call deactivate_plot_device ! Closes segment
c
      if( .NOT. lgui ) then
         write(luttyo,410)
410      format(' ','Step 2:'/
     1          ' ','Cut ellipse by positioning mouse:'/
     1          ' ','Click mouse button one to accept'/
     1          ' ','Click mouse button two to cancel input')
      endif

c
c     Start up three locators
c     First locator triggers on mouse press (device_num=1)
c     Do not start a segment yet, so all drawing during event mode is not
c     put into a segment (and replayed during resizing!)
      start_segment = .FALSE.
      call anno_setup_ws_for_locator_new(window_id,
     1     start_segment, echo_area, err_stat)
c     
c     Device 1 triggers on mouse button 1 press
      dev_num = 1
      pet_type = 2
      record_buffer_length = 0
      call gks$init_locator(work_id, dev_num,
     1     0.5, 0.5,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
      echo_mode = GKS$K_NOECHO
      input_mode = GKS$K_INPUT_MODE_EVENT
      call gks$set_locator_mode(work_id, dev_num,
     1     input_mode, echo_mode)
c     
c     Device 5 triggers on mouse button 2 press
      dev_num = 5
      pet_type = 2
      record_buffer_length = 0
      call gks$init_locator(work_id, dev_num,
     1     0.5, 0.5,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
      echo_mode = GKS$K_NOECHO
      input_mode = GKS$K_INPUT_MODE_EVENT
      call gks$set_locator_mode(work_id, dev_num,
     1     input_mode, echo_mode)
c
c     Device 8 triggers on mouse movement
      dev_num = 8
c     Use echo type 4 to get rubber band line
      pet_type = 4
      record_buffer_length = 4
      data_record(1) = GKS$K_ACF_CURRENT
      xmid = (x1+x2)/2.0
      ymid = (y1+y2)/2.0
      call gks$init_locator(work_id, dev_num,
     1     xmid, ymid,
     1     xform, pet_type, echo_area,
     1     data_record, record_buffer_length)
**    Things seem to go haywire if I put the locator into ECHO mode
**      echo_mode = GKS$K_ECHO
      echo_mode = GKS$K_NOECHO
      input_mode = GKS$K_INPUT_MODE_EVENT
      call gks$set_locator_mode(work_id, dev_num,
     1     input_mode, echo_mode)
c
c     Get line cutting ellipse (starting point at center of ellipse)
c
c     Draw in XOR mode
      write_mode = 1
      call pm_escape_set_writing_mode(write_mode)
c
      lfirst = .TRUE.
      timeout = 0.0
      do while(.TRUE.)
c        Check the event queue
         call gks$await_event(timeout, work_id, class, dev_num)
         if ( class .ne. GKS$K_INPUT_CLASS_NONE ) then
            if ( dev_num .eq. 8 ) then
               call gks$get_locator(xform, x3, y3)
c              Re-draw elliptical arc to erase it
               if( lfirst ) then
                  lfirst = .FALSE.
               else
                  call anno_draw_ellipse(ellipse_id, .TRUE.)
               endif
c              Draw new elliptical arc
               if( ellipse_notes(ellipse_id)%use_graph_coords ) then
                  call anno_norm_to_graph_coords(x3, y3, 1, x, y)
                  ellipse_notes(ellipse_id)%x3 = x
                  ellipse_notes(ellipse_id)%y3 = y
               else
                  ellipse_notes(ellipse_id)%x3 = x3
                  ellipse_notes(ellipse_id)%y3 = y3
               endif
               call anno_draw_ellipse(ellipse_id, .TRUE.)
               call gks$update_ws(work_id, GKS$K_POSTPONE_FLAG)
            else if ( dev_num .eq. 1 ) then
c              Mouse button 1 press exits event loop
c              Re-draw ellipse in XOR mode, so it is erased
               call anno_draw_ellipse(ellipse_id, .TRUE.)
               call gks$update_ws(work_id, GKS$K_POSTPONE_FLAG)
               input_status = 1
               goto 500
            else if ( dev_num .eq. 5 ) then
c              Mouse button 2 press exits event loop, user is cancelling input
c              Re-draw ellipse in XOR mode, so it is erased
               call anno_draw_ellipse(ellipse_id, .TRUE.)
               call gks$update_ws(work_id, GKS$K_POSTPONE_FLAG)
               input_status = 0
               goto 500
            endif
         endif
      end do
c
500   continue
c
c     Switch locators out of event mode
      dev_num = 1
      input_mode = GKS$K_INPUT_MODE_REQUEST
      echo_mode = GKS$K_ECHO
      call gks$set_locator_mode(work_id, dev_num, input_mode,
     1                          echo_mode)
      dev_num = 5
      input_mode = GKS$K_INPUT_MODE_REQUEST
      echo_mode = GKS$K_ECHO
      call gks$set_locator_mode(work_id, dev_num, input_mode,
     1                          echo_mode)
      dev_num = 8
      input_mode = GKS$K_INPUT_MODE_REQUEST
      echo_mode = GKS$K_ECHO
      call gks$set_locator_mode(work_id, dev_num, input_mode,
     1                          echo_mode)
c
c     Switch back to normal writing mode
      write_mode = 0
      call pm_escape_set_writing_mode(write_mode)
c
      if( input_status .ne. 1 ) then
c        Input was cancelled, mark ellipse as free
         ellipse_notes(ellipse_id)%window = -1
         err_stat = PLT$INPUT_CANCELLED
         goto 1000
      endif
c
c     Draw the final ellipse in a segment, so we can repaint/resize
c     correctly...
      call GKS$CREATE_SEG(cur_segment_id)
      call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                               GKS$K_DETECTABLE)
      call anno_draw_ellipse(ellipse_id, .TRUE.)
      call gks$update_ws(work_id, GKS$K_POSTPONE_FLAG)
      ellipse_notes(ellipse_id)%segment = cur_segment_id
c
1000  continue
c     Deactivate window
      call deactivate_plot_device
c
      return
      end
c
      subroutine anno_replay_annotations(from_window_id, to_window_id,
     1                                   activate_window)
      implicit none
c
c     "Replay" annotations from a particular window onto another window.
c     Used to replay annotations onto hardcopy devices.
c
c     Activate window is a logical flag. If .true., subroutine
c     activate the window attached to "to_window_id", replays the
c     annotations, and then deactivates it. If .false., the subroutine
c     assumes that the window is already active, and does not
c     activate/deactivate it. This flag is used to save time and calls
c     in certain uses.
c
      integer from_window_id, to_window_id
      logical activate_window
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'annotations.cmn'
c
c     locals
c
      integer i, work_id, lookup_ws_id
c
c     xt, yt for GKS bug workaround
      real xt(2),yt(2)
      logical lbug
c     End for GKS bug workaround
      logical error_occurred
c
c     xt, yt for GKS bug workaround
      data xt/0.0,0.0001/,yt/0.0,0.0001/
c     End for GKS bug workaround
c
      work_id = lookup_ws_id(to_window_id)
      if( work_id .EQ. PLT$EMPTY_WINDOW_SLOT ) then
         call plt$error_message('replay_annotations',
     1        'destination window_id is bad')
         return
      endif
c
      if( from_window_id .eq. to_window_id ) then
         call plt$error_message('replay_annotations',
     1        'internal error: from and to window ids are the same')
         return
      endif
c
      if( activate_window .AND. ws_active ) then
c        Current workstation is active, close it
         call deactivate_plot_device
      else if( .NOT. activate_window .AND. .NOT. ws_active) then
c        No window is active, but we were told not to activate a window
         call plt$error_message('replay_annotations',
     1        'Cannot replay: no window is active')
         return
      endif
c
      if( activate_window ) then
c        Activate window, do not open a segment, do not clear window
         call activate_plot_device(to_window_id, .false., .false.)
         call init_device_depend
      endif
c
      call gks$set_window(1,0.0,1.0,0.0,1.0)
c     ratio_x and ratio_y are in plot common
      call gks$set_viewport(1,0.0,ratio_x,0.0,ratio_y)
      call gks$select_xform(1)
c
c     Do boxes first, since they may be filled
      do i=1, MAX_BOX_NOTES
         if( box_notes(i)%window .eq. from_window_id ) then
            call anno_draw_box(i)
         endif
      end do
c
c     Do text notes
c
      do i=1, MAX_TEXT_NOTES
         if( text_notes(i)%window .eq. from_window_id ) then
            call anno_draw_text(i, work_id, error_occurred)
         endif
      end do
c
c     Markers
      do i=1, MAX_MARKER_NOTES
         if( marker_notes(i)%window .eq. from_window_id ) then
            call anno_draw_marker(i)
         endif
      end do
c
c     Lines
      do i=1, MAX_LINE_NOTES
         if( line_notes(i)%window .eq. from_window_id ) then
            call anno_draw_line(i)
         endif
      end do
c
c     Elliptical curves
c     Workaround for GKS not always setting linetype back to solid
c     for elliptical arcs for the PostScript output device.
c     Workaround: Emit a small polyline
c     to force setting of linetype back to solid
      lbug = .FALSE.
      do i=1, MAX_ELLIPSE_NOTES
         if( ellipse_notes(i)%window .eq. from_window_id ) then
            lbug = .TRUE.
         endif
      end do
      if( lbug ) then
         call GKS$SET_PLINE_COLOR_INDEX(1)
         call GKS$SET_PLINE_LINETYPE(1)
         call GKS$POLYLINE(2,xt,yt)
      endif
c     END workaround
      do i=1, MAX_ELLIPSE_NOTES
         if( ellipse_notes(i)%window .eq. from_window_id ) then
            call anno_draw_ellipse(i, .TRUE.)
         endif
      end do
c
      if( activate_window ) then
         call deactivate_plot_device
      endif
c
      return
      end
c
      integer function anno_alloc_note_struct(struct_type, err_stat)
      implicit none
c
c     Get a free note structure, if available.
c     All we return is the index into the appropriate table
c     for the particular type of structure the caller wants.
c     It is up the the caller to use the index in the right table.
c     It is also up to the caller to mark the structure as
c     "used" by modifying the window field.
c
c     All structures are "freed" merely by setting the window field
c     to the null value -1.
c
      integer struct_type, err_stat
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'annotations.cmn'
c
c     locals
c
      integer i
c
      anno_alloc_note_struct = -1
      err_stat = PLT$OUT_OF_NOTE_STORAGE
c
      if( struct_type .eq. TEXT_NOTE_TYPE ) then
         do i=1,MAX_TEXT_NOTES
            if( text_notes(i)%window .eq. -1 ) then
               anno_alloc_note_struct = i
               text_notes(i)%segment = 0
               text_notes(i)%text = ' '
               text_notes(i)%just = GKS$K_TEXT_HALIGN_LEFT
               text_notes(i)%orient = 0
               text_notes(i)%xloc = 0.0
               text_notes(i)%yloc = 0.0
               text_notes(i)%scale = 1.0
               text_notes(i)%color = 1
               text_notes(i)%use_x_graph_coords = .FALSE.
               text_notes(i)%use_y_graph_coords = .FALSE.
               err_stat = PLT$NORMAL
               goto 1000
            endif
         end do
      else if(struct_type .eq. MARKER_NOTE_TYPE) then
         do i=1,MAX_MARKER_NOTES
            if( marker_notes(i)%window .eq. -1 ) then
               anno_alloc_note_struct = i
               marker_notes(i)%segment = 0
               marker_notes(i)%type = 1
               marker_notes(i)%color = 1
               marker_notes(i)%size = 1.0
               marker_notes(i)%xloc = 0.0
               marker_notes(i)%yloc = 0.0
               marker_notes(i)%use_graph_coords = .FALSE.
               err_stat = PLT$NORMAL
               goto 1000
            endif
         end do
      else if(struct_type .eq. BOX_NOTE_TYPE) then
         do i=1,MAX_BOX_NOTES
            if( box_notes(i)%window .eq. -1 ) then
               anno_alloc_note_struct = i
               box_notes(i)%segment = 0
               box_notes(i)%color = 1
               box_notes(i)%fill_color = 1
               box_notes(i)%filled = .FALSE.
               box_notes(i)%thickness = 1.0
               box_notes(i)%x1 = 0.0
               box_notes(i)%y1 = 0.0
               box_notes(i)%x2 = 0.0
               box_notes(i)%y2 = 0.0
               box_notes(i)%use_graph_coords = .FALSE.
               err_stat = PLT$NORMAL
               goto 1000
            endif
         end do
      else if(struct_type .eq. LINE_NOTE_TYPE) then
         do i=1,MAX_LINE_NOTES
            if( line_notes(i)%window .eq. -1 ) then
               anno_alloc_note_struct = i
               line_notes(i)%segment = 0
               line_notes(i)%type  = 1
               line_notes(i)%color = 1
               line_notes(i)%thickness = 1.0
               line_notes(i)%arrow = 0
               line_notes(i)%x1 = 0.0
               line_notes(i)%y1 = 0.0
               line_notes(i)%x2 = 0.0
               line_notes(i)%y2 = 0.0
               line_notes(i)%use_graph_coords = .FALSE.
               err_stat = PLT$NORMAL
               goto 1000
            endif
         end do
      else if(struct_type .eq. ELLIPSE_NOTE_TYPE) then
         do i=1,MAX_ELLIPSE_NOTES
            if( ellipse_notes(i)%window .eq. -1 ) then
               anno_alloc_note_struct = i
               ellipse_notes(i)%segment = 0
               ellipse_notes(i)%color = 1
               ellipse_notes(i)%thickness = 1.0
               ellipse_notes(i)%x1 = 0.0
               ellipse_notes(i)%y1 = 0.0
               ellipse_notes(i)%x2 = 0.0
               ellipse_notes(i)%y2 = 0.0
               ellipse_notes(i)%x3 = 0.0
               ellipse_notes(i)%x3 = 0.0
               ellipse_notes(i)%use_graph_coords = .FALSE.
               err_stat = PLT$NORMAL
               goto 1000
            endif
         end do
      else
         err_stat = PLT$BAD_NOTE_TYPE
      endif
c
1000  return
      end
c
      subroutine anno_free_note_structs(window_id, err_stat)
      implicit none
c
c     Free all note structures associated with a window.
c
c     All structures are "freed" merely by setting the window field
c     to the null value -1.
c
      integer window_id, err_stat
c
      include 'annotations.cmn'
c
c     locals
c
      integer i
c
      do i=1,MAX_TEXT_NOTES
         if( text_notes(i)%window .eq. window_id ) then
            text_notes(i)%window = -1
         endif
      end do
c
      do i=1,MAX_MARKER_NOTES
         if( marker_notes(i)%window .eq. window_id ) then
            marker_notes(i)%window = -1
         endif
      end do
c
      do i=1,MAX_BOX_NOTES
         if( box_notes(i)%window .eq. window_id ) then
            box_notes(i)%window = -1
         endif
      end do
c
      do i=1,MAX_LINE_NOTES
         if( line_notes(i)%window .eq. window_id ) then
            line_notes(i)%window = -1
         endif
      end do
c
      do i=1,MAX_ELLIPSE_NOTES
         if( ellipse_notes(i)%window .eq. window_id ) then
            ellipse_notes(i)%window = -1
         endif
      end do
c
      err_stat = .FALSE.
c
      return
      end
c
      subroutine anno_free_note(note_type, note_id, err_stat)
      implicit none
c
c     Free a note structure
c
c     All structures are "freed" merely by setting the window field
c     to the null value -1.
c
      integer note_type, note_id, err_stat
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'annotations.cmn'
      include 'plot.cmn'
c
c     locals
c
      if( note_type .eq. TEXT_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_TEXT_NOTES) then
            err_stat = PLT$BAD_NOTE_ID
         else if( text_notes(note_id)%window .eq. -1 ) then
c           Already free
            err_stat = PLT$NOTE_ALREADY_FREE
         else
            text_notes(note_id)%window = -1
            err_stat = PLT$NORMAL
         endif
         return
      else if( note_type .eq. MARKER_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_MARKER_NOTES) then
            err_stat = PLT$BAD_NOTE_ID
         else if( marker_notes(note_id)%window .eq. -1 ) then
c           Already free
            err_stat = PLT$NOTE_ALREADY_FREE
         else
            marker_notes(note_id)%window = -1
            err_stat = PLT$NORMAL
         endif
         return
      else if( note_type .eq. BOX_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_BOX_NOTES) then
            err_stat = PLT$BAD_NOTE_ID
         else if( box_notes(note_id)%window .eq. -1 ) then
c           Already free
            err_stat = PLT$NOTE_ALREADY_FREE
         else
            box_notes(note_id)%window = -1
            err_stat = PLT$NORMAL
         endif
         return
      else if( note_type .eq. LINE_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_LINE_NOTES) then
            err_stat = PLT$BAD_NOTE_ID
         else if( line_notes(note_id)%window .eq. -1 ) then
c           Already free
            err_stat = PLT$NOTE_ALREADY_FREE
         else
            line_notes(note_id)%window = -1
            err_stat = PLT$NORMAL
         endif
         return
      else if( note_type .eq. ELLIPSE_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_ELLIPSE_NOTES) then
            err_stat = PLT$BAD_NOTE_ID
         else if( ellipse_notes(note_id)%window .eq. -1 ) then
c           Already free
            err_stat = PLT$NOTE_ALREADY_FREE
         else
            ellipse_notes(note_id)%window = -1
            err_stat = PLT$NORMAL
         endif
         return
      else
         err_stat = PLT$BAD_NOTE_TYPE
      endif
c
      return
      end
c
      subroutine anno_init_note_structs
      implicit none
c
c     Mark all structures "free" by setting the window field
c     to the null value -1.
c
      include 'annotations.cmn'
c
c     locals
c
      integer i
c
      do i=1,MAX_TEXT_NOTES
         text_notes(i)%window = -1
      end do
c
      do i=1,MAX_MARKER_NOTES
         marker_notes(i)%window = -1
      end do
c
      do i=1,MAX_BOX_NOTES
         box_notes(i)%window = -1
      end do
c
      do i=1,MAX_LINE_NOTES
         line_notes(i)%window = -1
      end do
c
      do i=1,MAX_ELLIPSE_NOTES
         ellipse_notes(i)%window = -1
      end do
c
      return
      end
c
      subroutine anno_setup_ws_for_locator(window_id,
     1                                       echo_area, err_stat)
      implicit none
c
c     Sets up the window for input from the locator device.
c     The entire window is mapped to a world coordinate system
c     of zero to one in both X and Y directions. Subroutine
c     returns echo area of window (entire device).
c
      integer window_id, err_stat
      real    echo_area(4)
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
c
c     locals
c
      integer dev_num, error_status, gks_units,
     1        ras_units_x, ras_units_y,
     1        work_id, lookup_ws_id
      real    dev_size_x, dev_size_y

c
      err_stat = PLT$NORMAL
      work_id = lookup_ws_id(window_id)
      if( work_id .eq. -1 ) then
         err_stat = PLT$BAD_WINDOW_ID
         return
      endif
c
      dev_num = 1
c     Activate window, do not clear it, start a segment on VAXstations
      call activate_plot_device(window_id, .false., .true.)
      call init_device_depend
      call gks$set_window(1,0.0,1.0,0.0,1.0)
c     ratio_x and ratio_y are in plot common
      call gks$set_viewport(1,0.0,ratio_x,0.0,ratio_y)
      call gks$select_xform(1)
      call gks$set_viewport_priority(1,0,
     1     GKS$K_INPUT_PRIORITY_HIGHER)
      call gks$inq_max_ds_size(full_ws_type, error_status, gks_units,
     1         dev_size_x, dev_size_y, ras_units_x, ras_units_y)
      echo_area(1) = 0.0
      echo_area(2) = dev_size_x
      echo_area(3) = 0.0
      echo_area(4) = dev_size_y
      call gks$set_locator_mode(work_id, dev_num,
     1     GKS$K_INPUT_MODE_REQUEST, GKS$K_ECHO)
c
      return
      end
c
      subroutine anno_setup_ws_for_locator_new(window_id,
     1           start_segment, echo_area, err_stat)
      implicit none
c
c     Sets up the window for input from the locator device.
c     The entire window is mapped to a world coordinate system
c     of zero to one in both X and Y directions. Subroutine
c     returns echo area of window (entire device).
c
      integer window_id, err_stat
      logical start_segment
      real    echo_area(4)
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
c
c     locals
c
      integer error_status, gks_units,
     1        ras_units_x, ras_units_y,
     1        work_id, lookup_ws_id
      real    dev_size_x, dev_size_y

c
      err_stat = PLT$NORMAL
      work_id = lookup_ws_id(window_id)
      if( work_id .eq. -1 ) then
         err_stat = PLT$BAD_WINDOW_ID
         return
      endif
c
c     Activate window, do not clear it, start segment if requested
      call activate_plot_device(window_id, .false., start_segment)
      call init_device_depend
      call gks$set_window(1,0.0,1.0,0.0,1.0)
c     ratio_x and ratio_y are in plot common
      call gks$set_viewport(1,0.0,ratio_x,0.0,ratio_y)
      call gks$select_xform(1)
      call gks$set_viewport_priority(1,0,
     1     GKS$K_INPUT_PRIORITY_HIGHER)
      call gks$inq_max_ds_size(full_ws_type, error_status, gks_units,
     1         dev_size_x, dev_size_y, ras_units_x, ras_units_y)
      echo_area(1) = 0.0
      echo_area(2) = dev_size_x
      echo_area(3) = 0.0
      echo_area(4) = dev_size_y
c
      return
      end
c
      subroutine anno_delete_notes(window_id, err_stat)
      implicit none
c
      integer window_id, err_stat
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'io.cmn'
      include 'annotations.cmn'
      include 'gui.cmn'
c
      integer work_id, dev_num, pet_type, record_buffer_length,
     1        init_status, init_segment, init_pick, input_status, 
     2        segment, pick_id, note_type, note_id
      integer lookup_ws_id
      real pick_aperture, echo_area(4)
c
c     For inq/set defer_state
      integer error_status, def_mode, regen_mode, surf_empty,
     1        new_frame
c
      work_id = lookup_ws_id(window_id)
      if( work_id .eq. -1 ) then
         err_stat = PLT$BAD_WINDOW_ID
         goto 1000
      endif
c
      if( .NOT. lgui ) then
         write(luttyo,100) PM_CANCEL_BUTTON
100      format(' ','Position mouse over item you wish to delete'/
     1       ' ','A box will appear over the item'/
     1       ' ','Press left button to delete item'/
     1       ' ','Press ',a,' button to exit delete loop')
      endif
c
c     Top of delete loop:
c
      do while(.TRUE.)
      call anno_setup_ws_for_pick(window_id, echo_area, pick_aperture,
     1                            err_stat)
c
      dev_num = 1
      pet_type = 3
      record_buffer_length = 4
      init_status = GKS$K_STATUS_NOPICK
      init_segment = 0
      init_pick = 0
      call gks$init_pick(work_id, dev_num,
     1                   init_status, init_segment, init_pick,
     1                   pet_type, echo_area,
     1                   pick_aperture, record_buffer_length)
      call gks$request_pick(work_id, dev_num,
     1                      input_status, segment, pick_id)
      call deactivate_plot_device
      if( input_status .eq. GKS$K_STATUS_NONE) then
c        Input break, exit move loop
         goto 1000
      else if( input_status .eq. GKS$K_STATUS_OK ) then
         call anno_find_note_from_segment(segment, note_type, note_id)
         if( note_type .eq. -1 ) then
            call plt$error_message('anno_delete_notes',
     1        'Picked segment does not correspond to an annotation')
            goto 1000
         endif
c
c        Delete segment
c        Set deferral state to "as soon as possible", to tell GKS
c        to reflect the segment deletion immediately on the workstation.
         call gks$inq_ws_defer_and_update(work_id, error_status,
     1           def_mode, regen_mode, surf_empty, new_frame)
         call gks$set_defer_state(work_id, GKS$K_ASAP,
     1           GKS$K_IRG_ALLOWED)
         call gks$delete_seg(segment)
c        Restore deferral mode
         call gks$set_defer_state(work_id, def_mode, regen_mode)
c
c        Free note structure
         call anno_free_note(note_type, note_id, err_stat)
      endif
c     We must ignore case of GKS$K_STATUS_NOPICK, since we told
c     init_pick to initialize pick position on null segment (0)
      end do
c
1000  continue
      return
      end
c
      subroutine anno_position_notes(window_id, err_stat)
      implicit none
c
      integer window_id, err_stat
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'io.cmn'
      include 'annotations.cmn'
      include 'gui.cmn'
c
      integer work_id, error_status,
     1        dev_num, pet_type, record_buffer_length,
     2        init_segment, init_pick, init_status,
     3        input_status, segment, pick_id,
     4        note_type, note_id,
     5        xform, box_loc_rb_length
      integer lookup_ws_id
      real echo_area(4), pick_aperture, seg_bbox(4), box_loc_size(2),
     1     x1, y1, x2, y2
c
c     For inq/set defer_state
      integer def_mode, regen_mode, surf_empty, new_frame
c
      work_id = lookup_ws_id(window_id)
      if( work_id .eq. -1 ) then
         err_stat = PLT$BAD_WINDOW_ID
         goto 1000
      endif
c
      if( .NOT. lgui ) then
         write(luttyo,100) PM_CANCEL_BUTTON, PM_CANCEL_BUTTON
100      format(' ','Position mouse over item you wish to move'/
     1       ' ','A box will appear over the item'/
     1       ' ','Press and release the left button to select the item'/
     1       ' ','The cursor will change to a box which is the'/
     1       ' ','    same size as the item you picked'/
     1       ' ','Move the box to the new location using the mouse,'/
     1       ' ','then press the left button to complete the move.'/
     1       ' ','To cancel a move, press the ',a,' button.'//
     1       ' ','You can perform moves any number of times'/
     1       ' ','When you are satisfied, press the ',a,' button.')
      endif
c
c     Top of move loop:
c
      do while(.TRUE.)
         call anno_setup_ws_for_pick(window_id, echo_area,
     1                               pick_aperture, err_stat)
c
         dev_num = 1
         pet_type = 3
         record_buffer_length = 4
         init_segment = 0
         init_pick = 0
         init_status = GKS$K_STATUS_NOPICK
         call gks$init_pick(work_id, dev_num,
     1                 init_status, init_segment, init_pick,
     1                 pet_type, echo_area,
     1                 pick_aperture, record_buffer_length)
         call gks$request_pick(work_id, dev_num,
     1                         input_status, segment, pick_id)
         call deactivate_plot_device
         if( input_status .eq. GKS$K_STATUS_NONE) then
c           Input break, exit move loop
            goto 1000
         else if( input_status .eq. GKS$K_STATUS_OK ) then
            call anno_find_note_from_segment(segment,note_type,note_id)
            if( note_type .eq. -1 ) then
               call plt$error_message('move_notes',
     1            'Picked segment does not correspond to an annotation')
               goto 1000
            endif
c
c           Get bounding box of segment
            call pm_escape_inq_seg_extent(work_id,segment,
     1                                    seg_bbox,error_status)
c
c           Activate box locator
            call anno_setup_ws_for_locator(window_id, echo_area,
     1              err_stat)
c
c           Use echo type -1 to get box
            dev_num = 1
            xform = 1
            pet_type = -1
            box_loc_rb_length = 8
            box_loc_size(1) = (seg_bbox(2) - seg_bbox(1))
            box_loc_size(2) = (seg_bbox(4) - seg_bbox(3))
c           Initial position of locator is at middle of segment bounding box
            x1 = (seg_bbox(2) + seg_bbox(1))/2.0
            y1 = (seg_bbox(4) + seg_bbox(3))/2.0
            call gks$init_locator(work_id, dev_num, x1, y1,
     1           xform, pet_type, echo_area,
     1           box_loc_size, box_loc_rb_length)
            call gks$request_locator(work_id, dev_num, input_status,
     1           xform, x2, y2)
            if( input_status .ne. 1 ) then
c              Input was cancelled
               call beep_terminal
               write(luttyo,200)
200            format(' ','Input cancelled')
            else
c              Set deferral state to "as soon as possible", to tell GKS
c              to reflect the segment deletion immediately on the workstation.
               call gks$inq_ws_defer_and_update(work_id, error_status,
     1                 def_mode, regen_mode, surf_empty, new_frame)
               call gks$set_defer_state(work_id, GKS$K_ASAP,
     1                 GKS$K_IRG_ALLOWED)
               call gks$delete_seg(segment)
c              Restore deferral mode
               call gks$set_defer_state(work_id, def_mode, regen_mode)
c              Translate coordinates of note.
               call anno_translate_note(note_type, note_id,
     1                                  x1, x2, y1, y2, err_stat)
               call anno_redraw_note(window_id, note_type, note_id,
     1                               err_stat)
            endif
c        We must ignore case of GKS$K_STATUS_NOPICK, since we told
c        init_pick to initialize pick position on null segment (0)
         endif
c
      end do
c
1000  continue
      return
      end

      subroutine anno_setup_ws_for_pick(window_id, echo_area,
     1                                  pick_aperture, err_stat)
      implicit none
c
c     Sets up the window for input from the pick device.
c     The entire window is mapped to a world coordinate system
c     of zero to one in both X and Y directions. Subroutine
c     returns echo area of window (entire device).
c
      integer window_id, err_stat
      real    echo_area(4), pick_aperture
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
c
c     locals
c
      integer dev_num, error_status, gks_units,
     1        ras_units_x, ras_units_y,
     1        input_mode, echo_flag, init_status, init_seg, init_pick,
     1        init_pet, record_buffer_length, record_size,
     1        work_id, lookup_ws_id
      real    dev_size_x, dev_size_y, init_echo_area(4)

c
      err_stat = PLT$NORMAL
      work_id = lookup_ws_id(window_id)
      if( work_id .eq. -1 ) then
         err_stat = PLT$BAD_WINDOW_ID
         return
      endif
c
      dev_num = 1
c     Activate window, do not clear it, do not a segment on VAXstations
      call activate_plot_device(window_id, .false., .false.)
      call init_device_depend
      call gks$set_window(1,0.0,1.0,0.0,1.0)
c     ratio_x and ratio_y are in plot common
      call gks$set_viewport(1,0.0,ratio_x,0.0,ratio_y)
      call gks$select_xform(1)
      call gks$set_viewport_priority(1,0,
     1     GKS$K_INPUT_PRIORITY_HIGHER)
c     Get size of pick "hot spot"
      record_buffer_length = 4
      call gks$inq_pick_state(work_id, dev_num,
     1              GKS$K_VALUE_REALIZED, error_status, input_mode,
     1              echo_flag, init_status, init_seg, init_pick,
     1              init_pet, init_echo_area, pick_aperture,
     1              record_buffer_length, record_size)
c     Get size of echo area (entire workstation)
      call gks$inq_max_ds_size(full_ws_type, error_status, gks_units,
     1         dev_size_x, dev_size_y, ras_units_x, ras_units_y)
      echo_area(1) = 0.0
      echo_area(2) = dev_size_x
      echo_area(3) = 0.0
      echo_area(4) = dev_size_y
      call gks$set_pick_mode(work_id, dev_num,
     1     GKS$K_INPUT_MODE_REQUEST, GKS$K_ECHO)
c
      return
      end
c
      subroutine anno_find_note_from_segment(segment,
     1                                       note_type, note_id)
      implicit none
c
      integer segment, note_type, note_id
c
c     Given a segment id, search note lists and find note which has that
c     id. If no such note, return -1 in note_type.
c
c     Current algorithm is pretty kludgy (exhaustive search),
c     but it should perform OK since there are a limited number of notes...
c
      include 'annotations.cmn'
c
      integer i
c
      note_id = -1
c
      do i=1,MAX_BOX_NOTES
         if( box_notes(i)%segment .eq. segment ) then
            note_type = BOX_NOTE_TYPE
            note_id = i
            return
         endif
      end do
C
      do i=1,MAX_LINE_NOTES
         if( line_notes(i)%segment .eq. segment ) then
            note_type = LINE_NOTE_TYPE
            note_id = i
            return
         endif
      end do
c
      do i=1,MAX_MARKER_NOTES
         if( marker_notes(i)%segment .eq. segment ) then
            note_type = MARKER_NOTE_TYPE
            note_id = i
            return
         endif
      end do
c
      do i=1,MAX_TEXT_NOTES
         if( text_notes(i)%segment .eq. segment ) then
            note_type = TEXT_NOTE_TYPE
            note_id = i
            return
         endif
      end do
c
      do i=1,MAX_ELLIPSE_NOTES
         if( ellipse_notes(i)%segment .eq. segment ) then
            note_type = ELLIPSE_NOTE_TYPE
            note_id = i
            return
         endif
      end do
c
      return
      end
c
      subroutine anno_translate_note(note_type, note_id, x1, x2, y1, y2,
     1                               err_stat)
      implicit none
c
      integer note_type, note_id, err_stat
      real x1, x2, y1, y2
c
c     Translates the coordinates of a note in x by delx, and in y by dely
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'annotations.cmn'
      include 'plot.cmn'
c
      real delx, dely, x(2), y(2)
c
      if( note_type .eq. BOX_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_BOX_NOTES .or.
     1       box_notes(note_id)%window .eq. -1) then
            err_stat = PLT$BAD_NOTE_ID
         else
            if( box_notes(note_id)%use_graph_coords ) then
               call anno_norm_to_graph_coords(x1, y1, 1, x(1), y(1))
               call anno_norm_to_graph_coords(x2, y2, 1, x(2), y(2))
               delx = x(2) - x(1)
               dely = y(2) - y(1)
            else
               delx = x2 - x1
               dely = y2 - y1
            endif
            box_notes(note_id)%x1 = box_notes(note_id)%x1 + delx
            box_notes(note_id)%y1 = box_notes(note_id)%y1 + dely
            box_notes(note_id)%x2 = box_notes(note_id)%x2 + delx
            box_notes(note_id)%y2 = box_notes(note_id)%y2 + dely
            err_stat = PLT$NORMAL
         endif
      else if( note_type .eq. LINE_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_LINE_NOTES .or.
     1       line_notes(note_id)%window .eq. -1) then
            err_stat = PLT$BAD_NOTE_ID
         else
            if( line_notes(note_id)%use_graph_coords ) then
               call anno_norm_to_graph_coords(x1, y1, 1, x(1), y(1))
               call anno_norm_to_graph_coords(x2, y2, 1, x(2), y(2))
               delx = x(2) - x(1)
               dely = y(2) - y(1)
            else
               delx = x2 - x1
               dely = y2 - y1
            endif
            line_notes(note_id)%x1 = line_notes(note_id)%x1 + delx
            line_notes(note_id)%y1 = line_notes(note_id)%y1 + dely
            line_notes(note_id)%x2 = line_notes(note_id)%x2 + delx
            line_notes(note_id)%y2 = line_notes(note_id)%y2 + dely
            err_stat = PLT$NORMAL
         endif
      else if( note_type .eq. TEXT_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_TEXT_NOTES .or.
     1       text_notes(note_id)%window .eq. -1) then
            err_stat = PLT$BAD_NOTE_ID
         else
            if( text_notes(note_id)%use_x_graph_coords .and.
     1          text_notes(note_id)%use_y_graph_coords ) then
               call anno_norm_to_graph_coords(x1, y1, 1, x(1), y(1))
               call anno_norm_to_graph_coords(x2, y2, 1, x(2), y(2))
               delx = x(2) - x(1)
               dely = y(2) - y(1)
            else if( text_notes(note_id)%use_x_graph_coords ) then
               call anno_norm_to_graph_coords(x1, 1.0, 1, x(1), y(1))
               call anno_norm_to_graph_coords(x2, 1.0, 1, x(2), y(2))
               delx = x(2) - x(1)
               dely = y2 - y1
            else if( text_notes(note_id)%use_y_graph_coords ) then
               call anno_norm_to_graph_coords(1.0, y1, 1, x(1), y(1))
               call anno_norm_to_graph_coords(1.0, y2, 1, x(2), y(2))
               delx = x2 - x1
               dely = y(2) - y(1)
            else
               delx = x2 - x1
               dely = y2 - y1
            endif
            text_notes(note_id)%xloc = text_notes(note_id)%xloc + delx
            text_notes(note_id)%yloc = text_notes(note_id)%yloc + dely
            err_stat = PLT$NORMAL
         endif
      else if( note_type .eq. MARKER_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_MARKER_NOTES .or.
     1       marker_notes(note_id)%window .eq. -1) then
            err_stat = PLT$BAD_NOTE_ID
         else
            if( marker_notes(note_id)%use_graph_coords ) then
               call anno_norm_to_graph_coords(x1, y1, 1, x(1), y(1))
               call anno_norm_to_graph_coords(x2, y2, 1, x(2), y(2))
               delx = x(2) - x(1)
               dely = y(2) - y(1)
            else
               delx = x2 - x1
               dely = y2 - y1
            endif
            marker_notes(note_id)%xloc = marker_notes(note_id)%xloc +
     1                                   delx
            marker_notes(note_id)%yloc = marker_notes(note_id)%yloc +
     1                                   dely
            err_stat = PLT$NORMAL
         endif
      else if( note_type .eq. ELLIPSE_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_ELLIPSE_NOTES .or.
     1       ellipse_notes(note_id)%window .eq. -1) then
            err_stat = PLT$BAD_NOTE_ID
         else
            if( ellipse_notes(note_id)%use_graph_coords ) then
               call anno_norm_to_graph_coords(x1, y1, 1, x(1), y(1))
               call anno_norm_to_graph_coords(x2, y2, 1, x(2), y(2))
               delx = x(2) - x(1)
               dely = y(2) - y(1)
            else
               delx = x2 - x1
               dely = y2 - y1
            endif
            ellipse_notes(note_id)%x1 = ellipse_notes(note_id)%x1 + delx
            ellipse_notes(note_id)%y1 = ellipse_notes(note_id)%y1 + dely
            ellipse_notes(note_id)%x2 = ellipse_notes(note_id)%x2 + delx
            ellipse_notes(note_id)%y2 = ellipse_notes(note_id)%y2 + dely
            ellipse_notes(note_id)%x3 = ellipse_notes(note_id)%x3 + delx
            ellipse_notes(note_id)%y3 = ellipse_notes(note_id)%y3 + dely
            err_stat = PLT$NORMAL
         endif
      else
c        Bad note type
         err_stat = PLT$BAD_NOTE_TYPE
      endif
c
      return
      end
c
      subroutine anno_redraw_note(to_window_id, note_type, note_id,
     1                            err_stat)
      implicit none
c
      integer to_window_id, note_type, note_id, err_stat
c
c     Activates workstation, displays note, and deactivates workstation
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'annotations.cmn'
c
c     locals
c
      integer work_id, lookup_ws_id
      logical error_occurred
c
c
      work_id = lookup_ws_id(to_window_id)
      if( work_id .EQ. PLT$EMPTY_WINDOW_SLOT ) then
         call plt$error_message('redraw_note',
     1        'destination window_id is bad')
         return
      endif
c
c     Activate window,  do not clear window, open a segment on VAXstations
      call activate_plot_device(to_window_id, .false., .true.)
      call init_device_depend
c
      call gks$set_window(1,0.0,1.0,0.0,1.0)
c     ratio_x and ratio_y are in plot common
      call gks$set_viewport(1,0.0,ratio_x,0.0,ratio_y)
      call gks$select_xform(1)
c      
      if( note_type .eq. BOX_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_BOX_NOTES .or.
     1       box_notes(note_id)%window .eq. -1) then
            err_stat = PLT$BAD_NOTE_ID
         else
            call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                               GKS$K_DETECTABLE)
c           Segment has changed, make a note of it, will ya, Ridley?
            box_notes(note_id)%segment = cur_segment_id
            call anno_draw_box(note_id)
            err_stat = PLT$NORMAL
         endif
      else if( note_type .eq. LINE_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_LINE_NOTES .or.
     1       line_notes(note_id)%window .eq. -1) then
            err_stat = PLT$BAD_NOTE_ID
         else
c           Segment has changed, make a note of it, will ya, Ridley?
            line_notes(note_id)%segment = cur_segment_id
            call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                               GKS$K_DETECTABLE)
            call anno_draw_line(note_id)
            err_stat = PLT$NORMAL
         endif
      else if( note_type .eq. TEXT_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_TEXT_NOTES .or.
     1       text_notes(note_id)%window .eq. -1) then
            err_stat = PLT$BAD_NOTE_ID
         else
c           Segment has changed, make a note of it, will ya, Ridley?
            text_notes(note_id)%segment = cur_segment_id
            call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                               GKS$K_DETECTABLE)
            call anno_draw_text(note_id, work_id, error_occurred)
c           Since we can only input "correct" text, we don't check
c           error_occurred
            err_stat = PLT$NORMAL
         endif
      else if( note_type .eq. MARKER_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_MARKER_NOTES .or.
     1       marker_notes(note_id)%window .eq. -1) then
            err_stat = PLT$BAD_NOTE_ID
         else
c           Segment has changed, make a note of it, will ya, Ridley?
            marker_notes(note_id)%segment = cur_segment_id
            call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                               GKS$K_DETECTABLE)
            call anno_draw_marker(note_id)
            err_stat = PLT$NORMAL
         endif
      else if( note_type .eq. ELLIPSE_NOTE_TYPE ) then
         if( note_id .lt. 1 .or. note_id .gt. MAX_ELLIPSE_NOTES .or.
     1       ellipse_notes(note_id)%window .eq. -1) then
            err_stat = PLT$BAD_NOTE_ID
         else
c           Segment has changed, make a note of it, will ya, Ridley?
            ellipse_notes(note_id)%segment = cur_segment_id
            call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                                     GKS$K_DETECTABLE)
            call anno_draw_ellipse(note_id, .TRUE.)
         endif
      else
c        Bad note type
         err_stat = PLT$BAD_NOTE_TYPE
      endif
c
c     Deactivate window (closes segment)
      call deactivate_plot_device
c
      return
      end
c
      subroutine anno_draw_box(id)
      implicit none
c
      integer id
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
      real x_temp(5), y_temp(5), x1, x2, y1, y2,
     1     x1_ndc, y1_ndc, x2_ndc, y2_ndc
c
      call GKS$SET_PLINE_COLOR_INDEX(box_notes(id)%color)
      call GKS$SET_PLINE_LINEWIDTH(hw_tuned_width *
     1                             box_notes(id)%thickness)
      if( box_notes(id)%use_graph_coords ) then
c        Tell GKS to clip to the current main plot area
c        RELIES on the current plot type being set in the save area
         call pm_get_current_plot_ndc_space(save_plot_type,
     1           x1_ndc, y1_ndc, x2_ndc, y2_ndc)
         call GKS$SET_WINDOW(2, x1_ndc, x2_ndc, y1_ndc, y2_ndc)
c        create virtual plot window at 65% of the screen (NDC space)
         call GKS$SET_VIEWPORT(2, x1_ndc*ratio_x, x2_ndc*ratio_x,
     1                            y1_ndc*ratio_y, y2_ndc*ratio_y)
         call GKS$SET_CLIPPING(GKS$K_CLIP)
         call GKS$SELECT_XFORM(2)
         call anno_graph_to_norm_coords(
     1        box_notes(id)%x1, box_notes(id)%y1, 1, x1, y1)
         call anno_graph_to_norm_coords(
     1        box_notes(id)%x2, box_notes(id)%y2, 1, x2, y2)
      else
         x1 = box_notes(id)%x1
         x2 = box_notes(id)%x2
         y1 = box_notes(id)%y1
         y2 = box_notes(id)%y2
      endif
      x_temp(1) = x1
      x_temp(2) = x2
      x_temp(3) = x2
      x_temp(4) = x1
      x_temp(5) = x1
      y_temp(1) = y1
      y_temp(2) = y1
      y_temp(3) = y2
      y_temp(4) = y2
      y_temp(5) = y1
      if( box_notes(id)%filled ) then
         if( ncolors .eq. 1 ) then
            if( box_notes(id)%fill_color .eq. 0 .or.
     1          box_notes(id)%fill_color .eq. 1 ) then
               call GKS$SET_FILL_INT_STYLE(GKS$K_INTSTYLE_SOLID)
               call GKS$SET_FILL_COLOR_INDEX(box_notes(id)%fill_color)
            else
               call GKS$SET_FILL_INT_STYLE(GKS$K_INTSTYLE_HATCH)
c              GKS HATCH values are negative (device specific) -1 to -9
               call GKS$SET_FILL_STYLE_INDEX(
     1                 MAX(MIN(-1,-(box_notes(id)%fill_color-1)),-9))
            endif
         else
            call GKS$SET_FILL_COLOR_INDEX(box_notes(id)%fill_color)
            call GKS$SET_FILL_INT_STYLE(GKS$K_INTSTYLE_SOLID)
         endif
         call GKS$FILL_AREA(4,x_temp,y_temp)
      endif
      call GKS$POLYLINE(5,x_temp,y_temp)
c
      if( box_notes(id)%use_graph_coords ) then
c        Reset transformation
         call GKS$SET_CLIPPING(GKS$K_NOCLIP)
         call GKS$SELECT_XFORM(1)
      endif
c
      return
      end
c
      subroutine anno_draw_line(id)
      implicit none
c
      integer id
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
      real    x1, x2, y1, y2, delx, dely, theta, sintheta, costheta,
     1        arrow_w, arrow_l, xtemp(3), ytemp(3), x, y,
     1        x1_ndc, y1_ndc, x2_ndc, y2_ndc
c
      call GKS$SET_PLINE_COLOR_INDEX(line_notes(id)%color)
      call GKS$SET_PLINE_LINEWIDTH(hw_tuned_width * 
     1                             line_notes(id)%thickness)
      call set_pline_type(line_notes(id)%type)
      if( line_notes(id)%use_graph_coords ) then
c        Tell GKS to clip to the current main plot area
c        RELIES on the current plot type being set in the save area
         call pm_get_current_plot_ndc_space(save_plot_type,
     1           x1_ndc, y1_ndc, x2_ndc, y2_ndc)
         call GKS$SET_WINDOW(2, x1_ndc, x2_ndc, y1_ndc, y2_ndc)
c        create virtual plot window at 65% of the screen (NDC space)
         call GKS$SET_VIEWPORT(2, x1_ndc*ratio_x, x2_ndc*ratio_x,
     1                            y1_ndc*ratio_y, y2_ndc*ratio_y)
         call GKS$SET_CLIPPING(GKS$K_CLIP)
         call GKS$SELECT_XFORM(2)
         call anno_graph_to_norm_coords(
     1        line_notes(id)%x1, line_notes(id)%y1, 1, x1, y1)
         call anno_graph_to_norm_coords(
     1        line_notes(id)%x2, line_notes(id)%y2, 1, x2, y2)
      else
         x1 = line_notes(id)%x1
         x2 = line_notes(id)%x2
         y1 = line_notes(id)%y1
         y2 = line_notes(id)%y2
      endif
      xtemp(1) = x1
      xtemp(2) = x2
      ytemp(1) = y1
      ytemp(2) = y2
      call GKS$POLYLINE(2,xtemp,ytemp)
      call GKS$SET_PLINE_LINETYPE(1)
      if( line_notes(id)%arrow .eq. 1 .or.
     1    line_notes(id)%arrow .eq. 2 ) then
c        Draw in arrow head
c        Compute angle of line, rotate arrow head by angle
c        Use ratio_x/ratio_x to compensate for (possible)
c        unequal aspect ratio of drawing surface
         dely = ratio_y*(y1 - y2)
         delx = ratio_x*(x1 - x2)
         if( delx .eq. 0.0 .and. dely .eq. 0.0 ) then
            theta = 0.0
         else
            theta = atan2(dely,delx)
         endif
         costheta = cos(theta)
         sintheta = sin(theta)
c        Note: we used to use hw_tuned_width to scale the arrow head size,
c              but when combined with device specific linewidth tuning,
c              the arrow heads can out very large. Use just the global
c              linewidth scale. The sqrt() function is used to "damp"
c              the user defined width, otherwise arrow heads get too large.
         arrow_w = ARROW_WIDTH * sqrt(global_linewidth_scale *
     1             line_notes(id)%thickness)
         arrow_l = ARROW_LENGTH * sqrt(global_linewidth_scale *
     1             line_notes(id)%thickness)
         xtemp(1) = x2
         xtemp(2) = x2 + ratio_y*
     1              (arrow_l*costheta - arrow_w*sintheta)
         xtemp(3) = x2 + ratio_y*
     1              (arrow_l*costheta + arrow_w*sintheta)
         ytemp(1) = y2
         ytemp(2) = y2 + ratio_x*
     1              (arrow_l*sintheta + arrow_w*costheta)
         ytemp(3) = y2 + ratio_x*
     1              (arrow_l*sintheta - arrow_w*costheta)
c        Draw in filled arrow head. GKS will close polygon by itself,
c        so only 3 points are needed.
         call GKS$SET_FILL_COLOR_INDEX(line_notes(id)%color)
         call GKS$SET_FILL_INT_STYLE(GKS$K_INTSTYLE_SOLID)
         call GKS$FILL_AREA(3,xtemp,ytemp)
         call GKS$SET_FILL_COLOR_INDEX(1)
      endif
      if( line_notes(id)%arrow .eq. 2 ) then
c        Draw in other arrow head
c        Compute angle of line, rotate arrow head by angle
c        Use ratio_x/ratio_x to compensate for (possible)
c        unequal aspect ratio of drawing surface
         dely = ratio_y*(y2 - y1)
         delx = ratio_x*(x2 - x1)
         if( delx .eq. 0.0 .and. dely .eq. 0.0 ) then
            theta = 0.0
         else
            theta = atan2(dely,delx)
         endif
         costheta = cos(theta)
         sintheta = sin(theta)
c        Note: we used to use hw_tuned_width to scale the arrow head size,
c              but when combined with device specific linewidth tuning,
c              the arrow heads can out very large. Use just the global
c              linewidth scale. The sqrt() function is used to "damp"
c              the user defined width, otherwise arrow heads get too large.
         arrow_w = ARROW_WIDTH * sqrt(global_linewidth_scale *
     1             line_notes(id)%thickness)
         arrow_l = ARROW_LENGTH * sqrt(global_linewidth_scale *
     1             line_notes(id)%thickness)
         xtemp(1) = x1
         xtemp(2) = x1 + ratio_y*
     1              (arrow_l*costheta - arrow_w*sintheta)
         xtemp(3) = x1 + ratio_y*
     1              (arrow_l*costheta + arrow_w*sintheta)
         ytemp(1) = y1
         ytemp(2) = y1 + ratio_x*
     1              (arrow_l*sintheta + arrow_w*costheta)
         ytemp(3) = y1 + ratio_x*
     1              (arrow_l*sintheta - arrow_w*costheta)
c        Draw in filled arrow head. GKS will close polygon by itself,
c        so only 3 points are needed.
         call GKS$SET_FILL_COLOR_INDEX(line_notes(id)%color)
         call GKS$SET_FILL_INT_STYLE(GKS$K_INTSTYLE_SOLID)
         call GKS$FILL_AREA(3,xtemp,ytemp)
         call GKS$SET_FILL_COLOR_INDEX(1)
      endif
c
      if( line_notes(id)%use_graph_coords ) then
c        Reset transformation
         call GKS$SET_CLIPPING(GKS$K_NOCLIP)
         call GKS$SELECT_XFORM(1)
      endif
c
      return
      end
c
      subroutine anno_draw_marker(id)
      implicit none
c
      integer id
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
      real x, y, x1_ndc, y1_ndc, x2_ndc, y2_ndc
c
      call set_pmark_type(marker_notes(id)%type)
      call GKS$SET_PMARK_COLOR_INDEX(marker_notes(id)%color)
      call GKS$SET_PMARK_SIZE(marker_notes(id)%size*hw_tuned_pmark_size)
      if( line_notes(id)%use_graph_coords ) then
c        Tell GKS to clip to the current main plot area
c        RELIES on the current plot type being set in the save area
         call pm_get_current_plot_ndc_space(save_plot_type,
     1           x1_ndc, y1_ndc, x2_ndc, y2_ndc)
         call GKS$SET_WINDOW(2, x1_ndc, x2_ndc, y1_ndc, y2_ndc)
c        create virtual plot window at 65% of the screen (NDC space)
         call GKS$SET_VIEWPORT(2, x1_ndc*ratio_x, x2_ndc*ratio_x,
     1                            y1_ndc*ratio_y, y2_ndc*ratio_y)
         call GKS$SET_CLIPPING(GKS$K_CLIP)
         call GKS$SELECT_XFORM(2)
         call anno_graph_to_norm_coords(
     1        marker_notes(id)%xloc, marker_notes(id)%yloc, 1, x, y)
      else
         x = marker_notes(id)%xloc
         y = marker_notes(id)%yloc
      endif
      call GKS$POLYMARKER(1, x, y)
      call GKS$SET_PMARK_SIZE(hw_tuned_pmark_size)
c
      if( marker_notes(id)%use_graph_coords ) then
c        Reset transformation
         call GKS$SET_CLIPPING(GKS$K_NOCLIP)
         call GKS$SELECT_XFORM(1)
      endif
c
      return
      end
c
      subroutine anno_draw_text(id, work_id, error_occurred)
      implicit none
c
      integer id, work_id
      logical error_occurred
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'annotations.cmn'
c
      real scale, xpos, ypos
c
c     locals for inq_prim_attb, inq_indiv_attb
      integer list_bundle_indexes(4), char_path, char_align(2),
     1        pl_type, pl_index, pm_type, pm_index, text_index,
     1        interior_style, style_index, fill_index,
     1        text_font, text_prec, attrib_sflgs(13),
     1        error_status
      real    char_height, char_up_vector(2), char_width,
     2        text_base_vector(2), pat_width(2), pat_height(2),
     2        pat_ref_points(2),
     2        pl_width, pm_size, char_exp_fac, char_spacing
c
      call GKS$INQ_INDIV_ATTB(error_status, pl_type, pl_width, pl_index,
     1     pm_type, pm_size, pm_index,
     2     text_font, text_prec, char_exp_fac, char_spacing,
     3     text_index, interior_style, style_index, fill_index,
     4     attrib_sflgs)
      call gks$set_text_color_index(text_notes(id)%color)
c
      call gks$inq_prim_attb(error_status, list_bundle_indexes,
     1     char_height, char_up_vector, char_width,
     1     text_base_vector, char_path, char_align,
     1     pat_width, pat_height, pat_ref_points)
c
      call gks$set_text_align(text_notes(id)%just,
     1                        GKS$K_TEXT_VALIGN_NORMAL)
      if( text_notes(id)%orient .eq. 0 ) then
c        Horizontal orientation
         call gks$set_text_upvec(0.0,1.0)
      else
c        Vertical orientation
         call gks$set_text_upvec(-1.0,0.0)
      endif
c     Character sizes tuned for reasonable display with this
c     normalization transformation.
      scale = text_notes(id)%scale
      if( text_notes(id)%orient .eq. 0 ) then
         call tune_charsize(0.025*scale, 0.04*scale, -0.5*scale,
     1                      0.02*scale,  0.025*scale, 0.0)
      else
         call tune_charsize(0.04*scale, 0.02*scale, 0.0,
     1                      0.026*scale, 0.018*scale, 0.0)
      endif
      if( text_notes(id).use_x_graph_coords .and.
     1    text_notes(id).use_y_graph_coords ) then
c        NOTE, we don't clip text annotations, even if they are
c        attached to the graph.
         call anno_graph_to_norm_coords(text_notes(id)%xloc,
     1                                  text_notes(id)%yloc,1,xpos,ypos)
      else if( text_notes(id).use_x_graph_coords ) then
c        NOTE, we don't clip text annotations, even if they are
c        attached to the graph.
         call anno_graph_to_norm_coords(text_notes(id)%xloc,
     1                                  1.0,1,xpos,ypos)
         ypos = text_notes(id)%yloc
      else if( text_notes(id).use_y_graph_coords ) then
c        NOTE, we don't clip text annotations, even if they are
c        attached to the graph.
         call anno_graph_to_norm_coords(1.0,
     1                                  text_notes(id)%yloc,1,xpos,ypos)
         xpos = text_notes(id)%xloc
      else
         xpos = text_notes(id)%xloc
         ypos = text_notes(id)%yloc
      endif
      call mathmode(work_id, xpos, ypos,
     1              text_notes(id)%text, .FALSE., error_occurred)
c
      call gks$set_text_align(char_align(1),char_align(2))
      call gks$set_text_color_index(text_index)
      call gks$set_text_upvec(char_up_vector(1),char_up_vector(2))
c
      return
      end
c
      subroutine anno_draw_ellipse(id, arc)
      implicit none
c
      integer id
      logical arc
c
c     If arc is .TRUE., then draw elliptical arc, using x3 and y3 as the
c     cut vector (origin at center of ellipse). Otherwise, draw  a full
c     ellipse, and ignore values of x3 and y3.
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
      real x1, x2, x3, y1, y2, y3, x_temp(6), y_temp(6), xmid, ymid,
     1     x1_ndc, y1_ndc, x2_ndc, y2_ndc
c
      call GKS$SET_PLINE_COLOR_INDEX(ellipse_notes(id)%color)
      call GKS$SET_PLINE_LINEWIDTH(hw_tuned_width * 
     1                             ellipse_notes(id)%thickness)
      call GKS$SET_PLINE_LINETYPE(1)
c
      if( ellipse_notes(id)%use_graph_coords ) then
c        Tell GKS to clip to the current main plot area
c        RELIES on the current plot type being set in the save area
         call pm_get_current_plot_ndc_space(save_plot_type,
     1           x1_ndc, y1_ndc, x2_ndc, y2_ndc)
         call GKS$SET_WINDOW(2, x1_ndc, x2_ndc, y1_ndc, y2_ndc)
c        create virtual plot window at 65% of the screen (NDC space)
         call GKS$SET_VIEWPORT(2, x1_ndc*ratio_x, x2_ndc*ratio_x,
     1                            y1_ndc*ratio_y, y2_ndc*ratio_y)
         call GKS$SET_CLIPPING(GKS$K_CLIP)
         call GKS$SELECT_XFORM(2)
         call anno_graph_to_norm_coords(
     1        ellipse_notes(id)%x1, ellipse_notes(id)%y1, 1, x1, y1)
         call anno_graph_to_norm_coords(
     1        ellipse_notes(id)%x2, ellipse_notes(id)%y2, 1, x2, y2)
      else
         x1 = ellipse_notes(id)%x1
         x2 = ellipse_notes(id)%x2
         y1 = ellipse_notes(id)%y1
         y2 = ellipse_notes(id)%y2
      endif
      xmid = (x1+x2)/2.0
      x_temp(1) = xmid
      x_temp(2) = xmid
      x_temp(3) = x2
      x_temp(4) = xmid
c
      ymid = (y1+y2)/2.0
      y_temp(1) = ymid
      y_temp(2) = ymid
      y_temp(3) = ymid
      y_temp(4) = y2
c
      if( arc ) then
         if( ellipse_notes(id)%use_graph_coords ) then
            call anno_graph_to_norm_coords(
     1           ellipse_notes(id)%x3, ellipse_notes(id)%y3, 1, x3, y3)
         else
            x3 = ellipse_notes(id)%x3
            y3 = ellipse_notes(id)%y3
         endif
         if( ABS(y2-y1) .ge. ABS(x2-x1) ) then
c           Ellipse is up/down
            x_temp(5) = x3
            x_temp(6) = x3
c
            y_temp(5) = y1+y2 - y3
            y_temp(6) = y3
         else
c           Ellipse is left/right
            x_temp(5) = x1+x2 - x3
            x_temp(6) = x3
c
            y_temp(5) = y3
            y_temp(6) = y3
         endif
c
         call pm_gdp_ellipse(2, x_temp, y_temp, 6)
      else
         call pm_gdp_ellipse(1, x_temp, y_temp, 4)
      endif
c
      if( ellipse_notes(id)%use_graph_coords ) then
c        Reset transformation
         call GKS$SET_CLIPPING(GKS$K_NOCLIP)
         call GKS$SELECT_XFORM(1)
      endif
c
      return
      end
c
      subroutine anno_restore_notes_from_file(to_window_id, err_stat)
      implicit none
c
      integer to_window_id, err_stat
c
c     Activates workstation, reads annotations from a file,
c     displays notes, and deactivates workstation.
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
c     locals
c
      integer work_id
      integer lookup_ws_id
      logical err
      character*(PM_MAX_PATHLEN) note_file
      character*1 ch
c
      work_id = lookup_ws_id(to_window_id)
      if( work_id .EQ. PLT$EMPTY_WINDOW_SLOT ) then
         call plt$error_message('anno_restore_notes_from_file',
     1        'destination window_id is bad')
         return
      endif
c
      note_file = 'POSTMINI.NOTE'
      call get_str_with_default(note_file,
     1     'File which has annotations? ',1)
c
c     Parse annotations from save file
      call read_savefile(note_file,.TRUE.,err)
      if( err ) then
         call get_char(ch,'Hit return to continue...',0)
         return
      endif
c
      call anno_restore_notes_from_save(to_window_id, err_stat)
c
      return
      end
c
      subroutine anno_restore_notes_from_save(to_window_id, err_stat)
      implicit none
c
      integer to_window_id, err_stat
c
c     Activates workstation, copies annotations from save area to
c     annotations memory and displays them, then deactivates workstation.
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
c     locals
c
      integer work_id, note_id, i, ierr
      integer lookup_ws_id, anno_alloc_note_struct
c
c     xt, yt for GKS bug workaround
      real xt(2),yt(2)
      data xt/0.0,0.0001/,yt/0.0,0.0001/
c     End for GKS bug workaround
c
      work_id = lookup_ws_id(to_window_id)
      if( work_id .EQ. PLT$EMPTY_WINDOW_SLOT ) then
         call plt$error_message('anno_restore_notes_from_save',
     1        'destination window_id is bad')
         return
      endif
c
c     Activate window,  do not clear window, do not open a segment
      call activate_plot_device(to_window_id, .false., .false.)
      call init_device_depend
c
      call gks$set_window(1,0.0,1.0,0.0,1.0)
c     ratio_x and ratio_y are in plot common
      call gks$set_viewport(1,0.0,ratio_x,0.0,ratio_y)
      call gks$select_xform(1)
c
c     Do for all annotation types stored in "save" structures
c
      do 1000 i=1,num_boxes
         note_id = anno_alloc_note_struct(BOX_NOTE_TYPE, err_stat)
         if(err_stat .ne. PLT$NORMAL) then
            call plt$error_message('anno_restore_notes_from_file',
     1        'too many box notes')
            goto 1010
         endif
         box_notes(note_id)%color = box_notes_dat(i)%color
         box_notes(note_id)%fill_color = box_notes_dat(i)%fill_color
         box_notes(note_id)%thickness = box_notes_dat(i)%thickness
         box_notes(note_id)%x1 = box_notes_dat(i)%x1
         box_notes(note_id)%y1 = box_notes_dat(i)%y1
         box_notes(note_id)%x2 = box_notes_dat(i)%x2
         box_notes(note_id)%y2 = box_notes_dat(i)%y2
         box_notes(note_id)%filled = box_notes_dat(i)%filled
         box_notes(note_id)%use_graph_coords =
     1                           box_notes_dat(i)%use_graph_coords
         if( plot_device .ne. hardcopy_device ) then
            call GKS$CREATE_SEG(cur_segment_id)
            call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                                     GKS$K_DETECTABLE)
            box_notes(note_id)%window = to_window_id
            box_notes(note_id)%segment = cur_segment_id
            call anno_draw_box(note_id)
            call GKS$CLOSE_SEG
            cur_segment_id = cur_segment_id + 1
         else
            call anno_draw_box(note_id)
         endif
         err_stat = PLT$NORMAL
1000  continue
1010  continue
c
      do 2000 i=1,num_lines
         note_id = anno_alloc_note_struct(LINE_NOTE_TYPE, err_stat)
         if(err_stat .ne. PLT$NORMAL) then
            call plt$error_message('anno_restore_notes_from_file',
     1        'too many line notes')
            goto 2010
         endif
         line_notes(note_id)%color = line_notes_dat(i)%color
         line_notes(note_id)%type = line_notes_dat(i)%type
         line_notes(note_id)%thickness = line_notes_dat(i)%thickness
         line_notes(note_id)%arrow = line_notes_dat(i)%arrow
         line_notes(note_id)%x1 = line_notes_dat(i)%x1
         line_notes(note_id)%y1 = line_notes_dat(i)%y1
         line_notes(note_id)%x2 = line_notes_dat(i)%x2
         line_notes(note_id)%y2 = line_notes_dat(i)%y2
         line_notes(note_id)%use_graph_coords =
     1                            line_notes_dat(i)%use_graph_coords
         if( plot_device .ne. hardcopy_device ) then
            call GKS$CREATE_SEG(cur_segment_id)
            call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                                     GKS$K_DETECTABLE)
            line_notes(note_id)%window = to_window_id
            line_notes(note_id)%segment = cur_segment_id
            call anno_draw_line(note_id)
            call GKS$CLOSE_SEG
            cur_segment_id = cur_segment_id + 1
         else
            call anno_draw_line(note_id)
         endif
         err_stat = PLT$NORMAL
2000  continue
2010  continue
c
      do 3000 i=1,num_text
         note_id = anno_alloc_note_struct(TEXT_NOTE_TYPE, err_stat)
         if(err_stat .ne. PLT$NORMAL) then
            call plt$error_message('anno_restore_notes_from_file',
     1        'too many text notes')
            goto 3010
         endif
         text_notes(note_id)%text = text_notes_dat(i)%text
         text_notes(note_id)%just = text_notes_dat(i)%just
         text_notes(note_id)%orient = text_notes_dat(i)%orient
         text_notes(note_id)%xloc = text_notes_dat(i)%xloc
         text_notes(note_id)%yloc = text_notes_dat(i)%yloc
         text_notes(note_id)%scale = text_notes_dat(i)%scale
         text_notes(note_id)%color = text_notes_dat(i)%color
         text_notes(note_id)%use_x_graph_coords =
     1                       text_notes_dat(i)%use_x_graph_coords
         text_notes(note_id)%use_y_graph_coords =
     1                       text_notes_dat(i)%use_y_graph_coords
         if( plot_device .ne. hardcopy_device ) then
            call GKS$CREATE_SEG(cur_segment_id)
            call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                                  GKS$K_DETECTABLE)
            text_notes(note_id)%window = to_window_id
            text_notes(note_id)%segment = cur_segment_id
            call anno_draw_text(note_id, work_id, ierr)
            call GKS$CLOSE_SEG
            cur_segment_id = cur_segment_id + 1
         else
            call anno_draw_text(note_id, work_id, ierr)
         endif
         err_stat = PLT$NORMAL
3000  continue
3010  continue
c
      do 4000 i=1,num_markers
         note_id = anno_alloc_note_struct(MARKER_NOTE_TYPE, err_stat)
         if(err_stat .ne. PLT$NORMAL) then
            call plt$error_message('anno_restore_notes_from_file',
     1        'too many marker notes')
            goto 4010
         endif
         marker_notes(note_id)%type = marker_notes_dat(i)%type
         marker_notes(note_id)%color = marker_notes_dat(i)%color
         marker_notes(note_id)%xloc = marker_notes_dat(i)%xloc
         marker_notes(note_id)%yloc = marker_notes_dat(i)%yloc
         marker_notes(note_id)%size = marker_notes_dat(i)%size
         marker_notes(note_id)%use_graph_coords =
     1                         marker_notes_dat(i)%use_graph_coords
         if( plot_device .ne. hardcopy_device ) then
            call GKS$CREATE_SEG(cur_segment_id)
            call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                                     GKS$K_DETECTABLE)
            marker_notes(note_id)%window = to_window_id
            marker_notes(note_id)%segment = cur_segment_id
            call anno_draw_marker(note_id)
            call GKS$CLOSE_SEG
            cur_segment_id = cur_segment_id + 1
         else
            call anno_draw_marker(note_id)
         endif
         err_stat = PLT$NORMAL
4000  continue
4010  continue
c
c     Workaround for GKS not always setting linetype back to solid
c     for elliptical arcs for the PostScript output device.
c     Workaround: Emit a small (null) polyline
c     to force setting of linetype back to solid
      if( num_ellipses .ge. 1 ) then
         call GKS$SET_PLINE_COLOR_INDEX(1)
         call GKS$SET_PLINE_LINETYPE(1)
         call GKS$POLYLINE(2,xt,yt)
      endif
c     END workaround
      do 5000 i=1,num_ellipses
         note_id = anno_alloc_note_struct(ELLIPSE_NOTE_TYPE, err_stat)
         if(err_stat .ne. PLT$NORMAL) then
            call plt$error_message('anno_restore_notes_from_file',
     1        'too many ellipse notes')
            goto 5010
         endif
         ellipse_notes(note_id)%color = ellipse_notes_dat(i)%color
         ellipse_notes(note_id)%thickness =
     1      ellipse_notes_dat(i)%thickness
         ellipse_notes(note_id)%x1 = ellipse_notes_dat(i)%x1
         ellipse_notes(note_id)%y1 = ellipse_notes_dat(i)%y1
         ellipse_notes(note_id)%x2 = ellipse_notes_dat(i)%x2
         ellipse_notes(note_id)%y2 = ellipse_notes_dat(i)%y2
         ellipse_notes(note_id)%x3 = ellipse_notes_dat(i)%x3
         ellipse_notes(note_id)%y3 = ellipse_notes_dat(i)%y3
         ellipse_notes(note_id)%use_graph_coords =
     1                           ellipse_notes_dat(i)%use_graph_coords
         if( plot_device .ne. hardcopy_device ) then
            call GKS$CREATE_SEG(cur_segment_id)
            call GKS$SET_SEG_DETECTABILITY(cur_segment_id,
     1                                     GKS$K_DETECTABLE)
            ellipse_notes(note_id)%window = to_window_id
            ellipse_notes(note_id)%segment = cur_segment_id
            call anno_draw_ellipse(note_id, .TRUE.)
            call GKS$CLOSE_SEG
            cur_segment_id = cur_segment_id + 1
         else
            call anno_draw_ellipse(note_id, .TRUE.)
         endif
         err_stat = PLT$NORMAL
5000  continue
5010  continue
c
c     Deactivate window
      call deactivate_plot_device
c
      return
c
      end
c
      subroutine anno_write_notes_to_file(from_window_id,err_stat)
      implicit none
c
      integer from_window_id, err_stat
c
c     Write annotations to save file
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'plot.cmn'
      include 'compare.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
c
c     locals
c
      integer work_id, nrecl, ierr, ioerr, lookup_ws_id
      integer pm_put_error_msg, istat
      character*(PM_MAX_PATHLEN) note_file
c
      work_id = lookup_ws_id(from_window_id)
      if( work_id .EQ. PLT$EMPTY_WINDOW_SLOT ) then
         call plt$error_message('anno_write_notes_to_file',
     1        'destination window_id is bad')
         return
      endif
c
c     Load annotations into save memory area
      call copy_annotations_to_save(from_window_id)
c
      note_file = 'POSTMINI.NOTE'
      nrecl=0
      call pm_open_file(notefil, note_file,
     1                  'UNKNOWN','FORMATTED','READWRITE','LIST',
     2                  'NONSHARED',nrecl, ioerr, ierr)
      if( ierr .ne. 0 ) goto 1000
      rewind(notefil)
c
c     Write out a comment so if there are no notes, POSTMINI.NOTE will
c     be reset to an "empty" file.
      write(notefil,1010)
1010  format('!! ')
c
c     write annotations to save file
      call write_save_annotations(notefil)
c
      close(unit=notefil)
      err_stat = PLT$NORMAL
c
      return
c
1000  continue
      istat = pm_put_error_msg(
     1        'Error: could not open file to save annotations')
      err_stat = PLT$BAD_FILE_OPEN
      if( .NOT. lgui ) then
         istat = pm_put_error_msg('Press return to continue')
         read(luttyi,*)
      endif
      return
      end
c
      subroutine anno_graph_to_norm_coords(xgraph, ygraph, npts,
     1                                     xnorm, ynorm)
      implicit none
c
      integer npts
      real xnorm(npts), ynorm(npts), xgraph(npts), ygraph(npts)
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'plot.cmn'
c
      real x1_ndc, x2_ndc, y1_ndc, y2_ndc
      real h_win_min, h_win_max, v_win_min, v_win_max
      real x, y
      integer i, iaxis
      logical do_xlog, do_ylog, yinvert
c
c     NOTE WELL: this routine **RELIES** on the fact that the axis_dat
c     structure is filled in before every plot
c
c     Get current NDC space for the main plot area
      call pm_get_current_plot_ndc_space(save_plot_type,
     1                    x1_ndc, y1_ndc, x2_ndc, y2_ndc)
c
      if( save_plot_type .eq. PLOT_3D_COMMAND ) then
c        3D plots do not support attach to graph
         do i=1,npts
            xnorm(i) = xgraph(i)
            ynorm(i) = ygraph(i)
         end do
         return
      else
         if( save_plot_type .eq. PLOT_1D_COMMAND ) then
            yinvert = .FALSE.
         else if( save_plot_type .eq. PLOT_2D_COMMAND .or.
     1            save_plot_type .eq. PLOT_OVERLAY_COMMAND) then
            if( axis_dat(2).invert ) then
               yinvert = .TRUE.
            else
               yinvert = .FALSE.
            endif
         else
c           COMPARE PLOT
            yinvert = .FALSE.
         endif
c
         if( axis_dat(1).used ) then
            iaxis = 1
         else
            iaxis = 4
         endif
         h_win_min = axis_dat(iaxis)%min
         h_win_max = axis_dat(iaxis)%max
         do_xlog   = axis_dat(iaxis)%log
         if( do_xlog ) then
            h_win_min = LOG10(MAX(ABS(h_win_min),PM_MIN_FLOAT))
            h_win_max = LOG10(MAX(ABS(h_win_max),PM_MIN_FLOAT))
         else if( axis_dat(iaxis).exp .ne. 0.0 ) then
            h_win_min = h_win_min*10.0**axis_dat(iaxis).exp
            h_win_max = h_win_max*10.0**axis_dat(iaxis).exp
         endif
c
         if( axis_dat(2).used ) then
            iaxis = 2
         else
            iaxis = 5
         endif
         v_win_min = axis_dat(iaxis)%min
         v_win_max = axis_dat(iaxis)%max
         do_ylog   = axis_dat(iaxis)%log
         if( do_ylog ) then
            v_win_min = LOG10(MAX(ABS(v_win_min),PM_MIN_FLOAT))
            v_win_max = LOG10(MAX(ABS(v_win_max),PM_MIN_FLOAT))
         else if( axis_dat(iaxis).exp .ne. 0.0 ) then
            v_win_min = v_win_min*10.0**axis_dat(iaxis).exp
            v_win_max = v_win_max*10.0**axis_dat(iaxis).exp
         endif
      endif
c
      do i=1,npts
         if( do_xlog ) then
            x = LOG10(MAX(ABS(xgraph(i)),PM_MIN_FLOAT))
         else
            x = xgraph(i)
         endif
         if( do_ylog ) then
            y = LOG10(MAX(ABS(ygraph(i)),PM_MIN_FLOAT))
         else
            y = ygraph(i)
         endif
         xnorm(i) = (x2_ndc - x1_ndc)*(x - h_win_min)/
     1                                (h_win_max - h_win_min) + x1_ndc
         if( yinvert ) then
            ynorm(i) = (y2_ndc - y1_ndc)*(v_win_max - y)/
     1                 (v_win_max - v_win_min) + y1_ndc
         else
            ynorm(i) = (y2_ndc - y1_ndc)*(y - v_win_min)/
     1                 (v_win_max - v_win_min) + y1_ndc
         endif
      end do
c
      return
      end
c
      subroutine anno_norm_to_graph_coords(xnorm, ynorm, npts,
     1                                     xgraph, ygraph)
      implicit none
c
      integer npts
      real xnorm(npts), ynorm(npts), xgraph(npts), ygraph(npts)
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'annotations.cmn'
      include 'save.cmn'
      include 'plot.cmn'
c
      real x1_ndc, x2_ndc, y1_ndc, y2_ndc
      real h_win_min, h_win_max, v_win_min, v_win_max
      real x, y, logmin, logmax
      integer i, iaxis
      logical do_xlog, do_ylog, yinvert
c
c     NOTE WELL: this routine **RELIES** on the fact that the axis_dat
c     structure is filled in before every plot
c
c     Get current NDC space for the main plot area
      call pm_get_current_plot_ndc_space(save_plot_type,
     1                    x1_ndc, y1_ndc, x2_ndc, y2_ndc)
c
      if( save_plot_type .eq. PLOT_3D_COMMAND ) then
c        3D plots do not support attach to graph
         do i=1,npts
            xgraph(i) = xnorm(i)
            ygraph(i) = ynorm(i)
         end do
         return
      else
         if( save_plot_type .eq. PLOT_1D_COMMAND ) then
            yinvert = .FALSE.
         else if( save_plot_type .eq. PLOT_2D_COMMAND .or.
     1            save_plot_type .eq. PLOT_OVERLAY_COMMAND) then
            if( axis_dat(2).invert ) then
               yinvert = .TRUE.
            else
               yinvert = .FALSE.
            endif
         else
c           COMPARE PLOT
            yinvert = .FALSE.
         endif
c
         if( axis_dat(1).used ) then
            iaxis = 1
         else
            iaxis = 4
         endif
         h_win_min = axis_dat(iaxis)%min
         h_win_max = axis_dat(iaxis)%max
         do_xlog   = axis_dat(iaxis)%log
         if( do_xlog ) then
            logmin = LOG10(MAX(ABS(h_win_min),PM_MIN_FLOAT))
            logmax = LOG10(MAX(ABS(h_win_max),PM_MIN_FLOAT))
         else if( axis_dat(iaxis).exp .ne. 0.0 ) then
            h_win_min = h_win_min*10.0**axis_dat(iaxis).exp
            h_win_max = h_win_max*10.0**axis_dat(iaxis).exp
         endif
c
         if( axis_dat(2).used ) then
            iaxis = 2
         else
            iaxis = 5
         endif
         v_win_min = axis_dat(iaxis)%min
         v_win_max = axis_dat(iaxis)%max
         do_ylog   = axis_dat(iaxis)%log
         if( do_ylog ) then
            logmin = LOG10(MAX(ABS(v_win_min),PM_MIN_FLOAT))
            logmax = LOG10(MAX(ABS(v_win_max),PM_MIN_FLOAT))
         else if( axis_dat(iaxis).exp .ne. 0.0 ) then
            v_win_min = v_win_min*10.0**axis_dat(iaxis).exp
            v_win_max = v_win_max*10.0**axis_dat(iaxis).exp
         endif
      endif
c
      do i=1,npts
         if( do_xlog ) then
            x =  (xnorm(i) - x1_ndc)/(x2_ndc   - x1_ndc)
            xgraph(i) = 10.0**((logmax - logmin)*x + logmin)
         else         
            xgraph(i) = (h_win_max - h_win_min)*(xnorm(i) - x1_ndc)/
     1                               (x2_ndc   - x1_ndc) + h_win_min
         endif
         if( yinvert ) then
            if( do_ylog ) then
               y = (y2_ndc - ynorm(i))/(y2_ndc - y1_ndc)
               ygraph(i) = 10.0**((logmax - logmin)*y + logmin)
            else
               ygraph(i) = (v_win_max - v_win_min)*(y2_ndc - ynorm(i))/
     1                     (y2_ndc - y1_ndc) + v_win_min
            endif
         else
            if( do_ylog ) then
               y = (ynorm(i) - y1_ndc)/(y2_ndc - y1_ndc)
               ygraph(i) = 10.0**((logmax - logmin)*y + logmin)
            else
               ygraph(i) = (v_win_max - v_win_min)*(ynorm(i) - y1_ndc)/
     1                     (y2_ndc - y1_ndc) + v_win_min
           endif
         endif
      end do
c
      return
      end
c
      subroutine pm_get_current_plot_ndc_space(plot_type,
     1                    x1_ndc, y1_ndc, x2_ndc, y2_ndc)
      implicit none
c
      integer plot_type
      real x1_ndc, y1_ndc, x2_ndc, y2_ndc
c
      include 'const.h'
c
c     This function RELIES on having the current plot parameters stored
c     in the save area before each plot is executed.
c
      if( plot_type .eq. PLOT_1D_COMMAND ) then
         x1_ndc = 0.175
         x2_ndc = 0.825
         y1_ndc = 0.100
         y2_ndc = 0.800
      else if( plot_type .eq. PLOT_2D_COMMAND .or.
     1         plot_type .eq. PLOT_OVERLAY_COMMAND ) then
         x1_ndc = 0.175
         x2_ndc = 0.825
         y1_ndc = 0.100
         y2_ndc = 0.800
      else if( plot_type .eq. PLOT_COMPARE_COMMAND ) then
         call pm_get_compare_plot_ndc_space(x1_ndc, y1_ndc,
     1                                      x2_ndc, y2_ndc)
      else
c        This function isn't use for 3D plots, but return something
c        in any case...
         x1_ndc = 0.0
         x2_ndc = 1.0
         y1_ndc = 0.0
         y2_ndc = 1.0
      endif
c
      return
      end
