home *** CD-ROM | disk | FTP | other *** search
/ Nebula / nebula.bin / SourceCode / Classes / Rubberview / Rubberband.m < prev    next >
Text File  |  1991-12-17  |  6KB  |  314 lines

  1.  
  2. /* Generated by Interface Builder */
  3. /* 
  4.     Augmented by Slugg Jello, 
  5.     Mouthing Flowers
  6.     152 20th Ave. #1
  7.     Seattle, WA. 98112
  8.     slugg@mouthers.nwnexus.wa.com
  9. */
  10.  
  11. #import "Rubberband.h"
  12. #import <appkit/Window.h>
  13. #import <appkit/View.h>
  14. #import <appkit/Application.h>
  15. #import <appkit/appkit.h>
  16. #include "Rubber.h" // psw stuff
  17. #include <math.h>
  18.  
  19. #define DRAG_MASK (NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK)
  20. //#define DEBUG_OUTPUT
  21. #define RUBBERBAND_WINDOW_WIDTH    1
  22.  
  23. @implementation Rubberband
  24.  
  25. /***** PRIVATE METHODS *****/
  26.  
  27. - (void)correctRect :(NXRect *)rect
  28. {
  29.     /* make sure it makes sense to NX routines which don't like negative 
  30.         size values */
  31.     if (rect->size.width < 0.0)
  32.     {
  33.         rect->origin.x += rect->size.width;
  34.         rect->size.width = -rect->size.width;
  35.     }
  36.     if (rect->size.height < 0.0)
  37.     {
  38.         rect->origin.y += rect->size.height;
  39.         rect->size.height = -rect->size.height;
  40.     }
  41. }
  42.  
  43. - setPosition
  44. /* Position and draw rubberband.  Assumes currentRect is set and rubberband
  45.     windows are initialized.  Also assumes currentRect is 'corrected'. */
  46. {
  47.     struct
  48.     {
  49.         NXRect top,left,bottom,right;
  50.     } points;
  51.     
  52.     NXRect tRect,screenRect=currentRect;
  53.     
  54.     [[myView window] convertBaseToScreen :&screenRect.origin];
  55.         
  56.     /**** set size of each rubberband side ****/
  57.     
  58.     /* left */
  59.     tRect = screenRect;
  60.     tRect.size.width = RUBBERBAND_WINDOW_WIDTH;
  61.     tRect.size.height = MAX(RUBBERBAND_WINDOW_WIDTH,screenRect.size.height);
  62.     points.left = tRect;
  63.     
  64.     /* right */
  65.     tRect.origin.x += screenRect.size.width - 1.0;
  66.     points.right = tRect;
  67.     
  68.     /* bottom */
  69.     tRect = screenRect;
  70.     tRect.origin.x += 1.0;
  71.     tRect.size.width = MAX(RUBBERBAND_WINDOW_WIDTH,screenRect.size.width-1.0);
  72.     tRect.size.height = RUBBERBAND_WINDOW_WIDTH;
  73.     points.bottom = tRect;
  74.     
  75.     /* top */
  76.     tRect.origin.y += screenRect.size.height - 1.0;
  77.     points.top = tRect;
  78.     
  79.     /* this'll erase old one and draw new one in new position */
  80.     PSWPositionRect((float *)&points);
  81.  
  82.    return self;
  83. }
  84.  
  85.  
  86. /***** PUBLIC METHODS *****/
  87.  
  88. - initWithView :aView
  89. {    
  90.     [self init];
  91.     [self setView :aView];
  92.     return self;
  93. }
  94.  
  95. - init
  96. {
  97.     [super init];
  98.     myView = nil;
  99.     
  100.     [self setPivot :RB_CORNER];
  101.     [self setInclusive :TRUE];
  102.     
  103.     return self;
  104. }
  105.  
  106. - setView :aView
  107. /* returns previous myView, sets bounds to those of aView */
  108. {
  109.     id oldView = myView;
  110.     NXRect rect;
  111.     
  112.     if (aView == nil)
  113.     {
  114.         [self setBounds :NULL];
  115.         return oldView;
  116.     }
  117.         
  118.     myView = aView;
  119.  
  120. #if defined(DEBUG_OUTPUT)
  121.     fprintf(stderr,"view == %p\n",myView);
  122. #endif
  123.     
  124.     [myView getBounds :&rect];
  125.     [self setBounds:&rect];
  126.         
  127.     return oldView;
  128. }
  129.  
  130.  
  131. - doStretch :(NXEvent *)event
  132. /* stretch the rubber band until user lets go of mouse */
  133. {
  134.     int oldMask;
  135.     NXEvent *nextEvent;
  136.     NXPoint mouseLocation;
  137.     NXPoint pivotPt;
  138.     NXRect tRect;
  139.  
  140.     if (myView == nil)
  141.         return self;
  142.         
  143. #if defined(DEBUG_OUTPUT)
  144.     fprintf(stderr,"we's a trackin\n");
  145. #endif
  146.     
  147.     currentRect.origin = event->location;
  148.     currentRect.size.width = currentRect.size.height = 0.0;
  149.     
  150.     if (flags.useBounds)
  151.     /* do nothing if first click isn't in bounds */
  152.         if (![myView mouse :¤tRect.origin inRect:&boundsRect])
  153.             return self;
  154.             
  155.         
  156.     mouseLocation = event->location;
  157.     
  158.   /* we want to grab mouse dragged events */
  159.    oldMask = [[myView window] addToEventMask:NX_MOUSEDRAGGEDMASK];
  160.     
  161.     if (flags.pivot == RB_CENTER)
  162.         pivotPt = currentRect.origin;
  163.         
  164.     PSWInitRubberband();
  165.     
  166.     [self setPosition];
  167.     
  168.     PSWMakeVisible(TRUE);
  169.         
  170.   /* start our event loop, looking for mouse-dragged or mouse-up events */
  171.     nextEvent = [NXApp getNextEvent:DRAG_MASK];
  172.     
  173.     tRect = currentRect;
  174.     
  175.     while (nextEvent->type != NX_MOUSEUP) 
  176.     {
  177.         if (flags.pivot == RB_CORNER)
  178.         {
  179.             tRect.size.width += nextEvent->location.x - mouseLocation.x;
  180.             tRect.size.height += nextEvent->location.y - mouseLocation.y;
  181.         }
  182.         else
  183.         {
  184.             tRect.size.width += 
  185.                     (nextEvent->location.x - mouseLocation.x) * 2;
  186.             tRect.size.height += 
  187.                     (nextEvent->location.y - mouseLocation.y) * 2;
  188.             tRect.origin.x = pivotPt.x - tRect.size.width / 2;
  189.             tRect.origin.y = pivotPt.y - tRect.size.height / 2;
  190.         }
  191.         
  192.         currentRect = tRect;
  193.         [self correctRect :¤tRect];
  194.         
  195.         if (flags.useBounds)
  196.             NXIntersectionRect(&boundsRect,¤tRect);
  197.         NXIntegralRect(¤tRect);
  198.  
  199.         mouseLocation = nextEvent->location;
  200.         
  201.         [self setPosition];
  202.  
  203. #if defined(DEBUG_OUTPUT)
  204.         fprintf(stderr,
  205.             "current rect: origin (%3.2lf,%3.2lf), size (%3.2lf,%3.2lf)\n",
  206.             currentRect.origin.x,currentRect.origin.y,
  207.             currentRect.size.width,currentRect.size.height);
  208. #endif
  209.         
  210.         nextEvent = [NXApp getNextEvent:DRAG_MASK];
  211.     }
  212.  
  213.   /* reset the event mask */
  214.     [[myView window] setEventMask:oldMask];
  215.      
  216. #if defined(DEBUG_OUTPUT)
  217.     fprintf(stderr,"we's a done trackin\n");
  218. #endif
  219.     
  220.     PSWMakeVisible(FALSE);
  221.     
  222.     return self;
  223. }
  224.  
  225. - currentRect :(NXRect *)rect
  226. /* return currentRect in rect in View coords */
  227. {
  228.     if (!rect)
  229.         return self;
  230.         
  231.     *rect = currentRect;
  232.         
  233.     if (!flags.inclusive)
  234.     {
  235.         ++rect->origin.x;
  236.         ++rect->origin.y;
  237.         rect->size.width -= 2.0;
  238.         rect->size.height -= 2.0;
  239.     }
  240.     
  241.     /* convert from Window to View coords */
  242.     [myView convertRect:rect fromView:nil];
  243.     
  244.    return self;
  245. }
  246.  
  247. - bounds :(NXRect *)rect
  248. /* return boundsRect in rect in View coords */
  249. {
  250.     if (!rect)
  251.         return self;
  252.     
  253.     *rect = boundsRect;
  254.         
  255.     /* convert from Window to View coords */
  256.     [myView convertRect:rect fromView:nil];
  257.     
  258.    return self;
  259. }
  260.  
  261. - setBounds :(const NXRect *)rect 
  262. /* set boundaries within which the rubberband may be dragged. 
  263.     rect is in myView coords.  if rect is NULL, then no bounds. */
  264. {
  265.     if (rect == NULL)
  266.     {
  267.         flags.useBounds = FALSE;
  268.         return self;
  269.     }
  270.         
  271.     flags.useBounds = TRUE;
  272.     boundsRect = *rect;
  273.     
  274.     /* convert from View to Window coords */
  275.     [myView convertRect:&boundsRect toView:nil];
  276.     
  277. #if defined(DEBUG_OUTPUT)
  278.     fprintf(stderr,"bounds: origin (%f %f) size (%f %f)\n",boundsRect.origin.x,
  279.         boundsRect.origin.y,boundsRect.size.width,boundsRect.size.height);
  280. #endif
  281.     
  282.     return self;
  283. }
  284.  
  285.  
  286. - setCurrentRectToBounds;
  287. {
  288.     flags.useBounds = TRUE;
  289.     boundsRect = currentRect;
  290.     return self;
  291. }
  292.  
  293. - (int)setPivot :(int)pivot
  294. {
  295.     int oldPivot = flags.pivot;
  296.     flags.pivot = pivot;
  297. #if defined(DEBUG_OUTPUT)
  298.     fprintf(stderr,"pivot == %s\n",
  299.             flags.pivot == RB_CORNER ? "CORNER":"CENTER");
  300. #endif
  301.     
  302.     return oldPivot;
  303. }
  304.  
  305. - (BOOL)setInclusive:(BOOL)onoff
  306. {
  307.     BOOL bPrev = flags.inclusive;
  308.     flags.inclusive = onoff;
  309.    return bPrev;
  310. }
  311.  
  312.  
  313. @end
  314.