home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / software / unix / saoimage / sao1_07.tar / csrgrab.c < prev    next >
C/C++ Source or Header  |  1990-04-20  |  8KB  |  257 lines

  1. #ifndef lint
  2. static char SccsId[] = "%W%  %G%";
  3. #endif
  4.  
  5. /* Module:    csrgrab.c (Cursor Grab)
  6.  * Purpose:    Surgically resize or delete annular cursors
  7.  * Subroutine:    size_annuli()            returns: void
  8.  * Subroutine:    delete_annulus()        returns: void
  9.  * Copyright:    1989 Smithsonian Astrophysical Observatory
  10.  *        You may do anything you like with this file except remove
  11.  *        this copyright.  The Smithsonian Astrophysical Observatory
  12.  *        makes no representations about the suitability of this
  13.  *        software for any purpose.  It is provided "as is" without
  14.  *        express or implied warranty.
  15.  * Modified:    {0} Michael VanHilst    initial version          4 June 1989
  16.  *        {n} <who> -- <does what> -- <when>
  17.  */
  18.  
  19. #include <stdio.h>        /* stderr, NULL, etc. */
  20. #include <math.h>        /* get trig functions and sqrt */
  21. #include <X11/Xlib.h>        /* X window stuff */
  22. #include <X11/Xutil.h>        /* X window manager stuff */
  23. #include "hfiles/color.h"    /* cursor colors needed by Cursor.h */
  24. #include "hfiles/constant.h"    /* define codes */
  25. #include "hfiles/cursor.h"    /* define cursor parameter structures */
  26. #include "hfiles/define.h"    /* SMALL_NUMBER, LARGE_NUMBER and more */
  27.  
  28. extern struct colorRec color;    /* need to know color.gcset */
  29.  
  30. #define GRAB_RANGE 5.0
  31. #define ANN_INSIDE 2
  32. #define ANN_ON 1
  33. #define ANN_BETWEEN 8
  34. #define ANN_OUTSIDE 4
  35.  
  36. /*
  37.  * Subroutine:    size_annuli
  38.  * Purpose:    Change size of cursor to intersect current mouse cursor
  39.  *        while keeping aspect ratio of cursor constant
  40.  */
  41. void size_annuli ( cursor, event )
  42.      struct cursorRec *cursor;
  43.      XEvent *event;        /* i: event for location of mouse */
  44. {
  45.   void draw_cursor(), make_cursor();
  46.   static void size_annulus(), grab_annulus();
  47.  
  48.   /* if this event is initiating tracking, don't erase the cursor */
  49.   if( event->type == MotionNotify )
  50.     /* erase existing cursor */
  51.     draw_cursor(cursor, &color.gcset.undraw);
  52.   size_annulus(cursor, event);
  53.   /* if this event is initiating tracking, decide which annulus to grab */
  54.   if( event->type == ButtonPress )
  55.     grab_annulus (cursor);
  56.   /* make new point list */
  57.   make_cursor(cursor);
  58.   /* draw it */
  59.   draw_cursor(cursor, &color.gcset.track);
  60. }
  61.  
  62. /*
  63.  * Subroutine:    delete_annulus
  64.  * Purpose:    Respond to a mouse request to delete an annulus
  65.  *
  66.  */
  67. void delete_annulus ( cursor, event )
  68.      struct cursorRec *cursor;
  69.      XEvent *event;        /* i: XMotionEvent or XButtonEvent */
  70. {
  71.   struct cursorRec *parent;
  72.   static int on_annulus();
  73.   static void size_annulus(), remove_annulus();
  74.  
  75.   /* if there are two or more annuli */
  76.   if( (cursor->next_annulus != 0) &&
  77.       (cursor->next_annulus->next_annulus != 0) ) {
  78.     /* size the cursor so we can compare its size with the annuli */
  79.     size_annulus(cursor, event);
  80.     if( on_annulus(cursor, &parent) != ANN_BETWEEN )
  81.       /* remove if ON. INSIDE, or OUTSIDE */
  82.       remove_annulus(parent);
  83.   }
  84. }
  85.  
  86. /*
  87.  * Subroutine:    size_annulus
  88.  * Purpose:    Change size of cursor to intersect current mouse cursor
  89.  *        while keeping aspect ratio of cursor constant
  90.  */
  91. static void size_annulus ( cursor, event )
  92.      struct cursorRec *cursor;
  93.      XEvent *event;        /* i: XMotionEvent for location of mouse */
  94. {
  95.   double rayX, rayY;
  96.   double axis_ratio;
  97.  
  98.   /* compute distance from center */
  99.   rayX = ((double)event->xmotion.x + 0.5) - cursor->win.X;
  100.   rayY = ((double)event->xmotion.y + 0.5) - cursor->win.Y;
  101.   if( (cursor->type == COP_Box) || (cursor->type == COP_Ellipse) ) {
  102.     double temp;
  103.     temp = (rayX * cursor->rot.cos) + (rayY * cursor->rot.sin);
  104.     rayY = (rayY * cursor->rot.cos) - (rayX * cursor->rot.sin);
  105.     rayX = temp;
  106.   }
  107.   if( rayX < 0.0 )
  108.     rayX = -rayX;
  109.   if( rayY < 0.0 )
  110.     rayY = -rayY;
  111.   axis_ratio = cursor->ctrl.axis_ratio;
  112.   switch( cursor->type ) {
  113.   case COP_Box:
  114.     /* size on the side which will touch the mouse position */
  115.     if( (rayX < SMALL_NUMBER) || ((rayY / rayX) > axis_ratio) ) {
  116.       cursor->win.rayY = rayY;
  117.       cursor->win.rayX = rayY / axis_ratio;
  118.     } else {
  119.       cursor->win.rayX = rayX;
  120.       cursor->win.rayY = rayX * axis_ratio;
  121.     }
  122.     break;
  123.   case COP_Ellipse:
  124.     /* this version of sizing tracks the ellipses edge */
  125.     rayX *= axis_ratio;
  126.     cursor->win.rayY = sqrt((rayX * rayX) + (rayY * rayY));
  127.     cursor->win.rayX = cursor->win.rayY / axis_ratio;
  128.     break;
  129.   case COP_Circle:
  130.     cursor->win.rayX = sqrt((rayX * rayX) + (rayY * rayY));
  131.     cursor->win.rayY = cursor->win.rayX;
  132.     break;
  133.   case COP_Polygon:
  134.   case COP_Point:
  135.   default:
  136.     (void)fprintf(stderr, "cursor type error\n");
  137.   }
  138. }
  139.  
  140. /*
  141.  * Subroutine:    remove_annulus
  142.  * Purpose:    Remove an annular ring from annulus linked list and screen
  143.  */
  144. static void remove_annulus ( parent )
  145.      struct cursorRec *parent;    /* i: annulus just before one to be removed */
  146. {
  147.   int index;
  148.   struct cursorRec *annulus;
  149.   void draw_cursor(), free_cursor();
  150.  
  151.   annulus = parent->next_annulus;
  152.   index = annulus->index;
  153.   /* remove annulus from linked list */
  154.   parent->next_annulus = annulus->next_annulus;
  155.   /* erase the grabbed annulus */
  156.   draw_cursor(annulus, &color.gcset.undraw);
  157.   /* free the grabbed annulus */
  158.   free_cursor(annulus);
  159.   /* reset index of annuli which were moved down */
  160.   annulus = parent->next_annulus;
  161.   while( annulus != 0 ) {
  162.     annulus->index = index++;
  163.     annulus = annulus->next_annulus;
  164.   }
  165. }
  166.  
  167. /*
  168.  * Subroutine:    grab_annulus
  169.  * Purpose:    Set up cursor to for a size annulus interaction
  170.  * Called by:    size_annuli()
  171.  */
  172. static void grab_annulus ( cursor )
  173.      struct cursorRec *cursor;
  174. {
  175.   double inc;
  176.   int code;
  177.   struct cursorRec *parent, *annulus;
  178.   static int on_annulus();
  179.   static void remove_annulus();
  180.  
  181.   code = on_annulus(cursor, &parent);
  182.   /* decide what to draw */
  183.   /* if grab, erase grabbed */
  184.   if( code == ANN_ON ) {
  185.     remove_annulus(parent);
  186.   } else if( code == ANN_INSIDE ) {
  187.     /* if inside all annuli, use next inc inward */
  188.     if( ((parent = parent->next_annulus) != 0) &&
  189.         ((annulus = parent->next_annulus) != 0) &&
  190.         ((inc = annulus->win.rayX - parent->win.rayX) < parent->win.rayX) ) {
  191.       cursor->win.rayX = parent->win.rayX - inc;
  192.       cursor->win.rayY = cursor->win.rayX * cursor->ctrl.axis_ratio;
  193.     }
  194.   } else if( code == ANN_OUTSIDE ) {
  195.     /* if outside all annuli, use smaller of next inc or mouse position */
  196.     if( ((annulus = parent->next_annulus) != 0) ) {
  197.       double rayX;
  198.       if( parent == cursor )
  199.     rayX = annulus->win.rayX + annulus->win.rayX;
  200.       else
  201.     rayX = annulus->win.rayX + annulus->win.rayX - parent->win.rayX;
  202.       if( rayX < cursor->win.rayX ) {
  203.     cursor->win.rayX = rayX;
  204.     cursor->win.rayY = cursor->win.rayX * cursor->ctrl.axis_ratio;
  205.       }
  206.     }
  207.   }
  208. }
  209.  
  210. /*
  211.  * Subroutine:    on_annulus
  212.  * Purpose:    Compare size of cursor with annuli
  213.  * Returns:    Code describing relation to annuli
  214.  * PostState:    Sets pointer to nearest annulus inside of cursor
  215.  */
  216. static int on_annulus ( cursor, pointer )
  217.      struct cursorRec *cursor;
  218.      struct cursorRec **pointer;
  219. {
  220.   double grabmax, grabmin;
  221.   struct cursorRec *last_ann, *annulus;
  222.   int code;
  223.  
  224.   last_ann = cursor;
  225.   /* is this the first annulus (probably an illegal state) */
  226.   if( cursor->next_annulus == 0 ) {
  227.     code = ANN_OUTSIDE;
  228.   } else {
  229.     /* set the capture limits */
  230.     grabmax = cursor->win.rayX + GRAB_RANGE;
  231.     grabmin = cursor->win.rayX - GRAB_RANGE;
  232.     annulus = cursor->next_annulus;
  233.     /* loop check for on or inside each successive ring */
  234.     code = 0;
  235.     do {
  236.       if( annulus->win.rayX > grabmax ) {
  237.     /* add inside this annulus */
  238.     if( last_ann == cursor )
  239.       code = ANN_INSIDE;
  240.     else
  241.       code = ANN_BETWEEN;
  242.       } else if( annulus->win.rayX > grabmin ) {
  243.     /* grab this annulus */
  244.     code = ANN_ON;
  245.       } else if( annulus->next_annulus == 0 ) {
  246.     /* add outside all annuli */
  247.     code = ANN_OUTSIDE;
  248.       } else {
  249.     last_ann = annulus;
  250.     annulus = annulus->next_annulus;
  251.       }
  252.     } while( code == 0 );
  253.   }
  254.   *pointer = last_ann;
  255.   return( code );
  256. }
  257.