home *** CD-ROM | disk | FTP | other *** search
/ Altsys Virtuoso 2.0K / virtuoso_20k.iso / DemoApps / Graphics / Viewers / Magnify / Source / MagnifyView.m < prev    next >
Encoding:
Text File  |  1993-01-26  |  6.7 KB  |  288 lines

  1. /* File: MagnifyView.m - View class for 'Magnify'
  2.  *
  3.  * By: Christopher Lane
  4.  * Symbolic Systems Resources Group
  5.  * Knowledge Systems Laboratory
  6.  * Stanford University
  7.  *
  8.  * Date: 9 January 1992
  9.  *
  10.  * Copyright: 1990, 1991 & 1992 by The Leland Stanford Junior University.
  11.  * This program may be distributed without restriction for non-commercial use.
  12.  */
  13.  
  14. #import "Magnify.h"
  15. #import "MagnifyView.h"
  16.  
  17. #import <appkit/Pasteboard.h>
  18.  
  19. #define GRIDLINEMODE NX_COPY
  20. #define GRIDLINEWIDTH ((float) 1.0)
  21.  
  22. #define NX_ALERTPANELLEVEL (NX_MAINMENULEVEL + 1)
  23. #define NXSetWindowLevel _NXSetWindowLevel
  24. extern int NXSetWindowLevel(int, int);
  25.  
  26. @implementation MagnifyView
  27.  
  28. + newFrame:(const NXRect *) frameRect;
  29. {
  30.     const char *string;
  31.  
  32.     self = [super newFrame:frameRect];
  33.  
  34.     frozen = NO;
  35.     lock = mutex_alloc();
  36.     mouse = frameRect->origin;
  37.     showCursor = (BOOL) (strncmp(getDefault(CURSORDEFAULTSTRING), YESSTRING, 1) == 0);
  38.     
  39.     if ((string = getDefault(SCALEDEFAULTSTRING)) == NULL || sscanf(string, FLOAT, &scale) != 1)
  40.         scale = DEFAULTSCALE;
  41.         
  42.     if ((string = getDefault(GRIDDEFAULTSTRING)) == NULL || sscanf(string, FLOAT, &grid) != 1)
  43.         grid = DEFAULTGRID;
  44.         
  45.     showGrid = (BOOL) (grid > 0.0);
  46.     
  47.     return [self createWindows];
  48. }
  49.  
  50. - (BOOL) acceptsFirstResponder { return YES; }
  51.  
  52. - copy:sender
  53. {
  54.     char *buffer;
  55.     NXStream *stream;
  56.     int length, maxLength;
  57.     Pasteboard *pasteboard = [Pasteboard new];
  58.     
  59.     [pasteboard declareTypes:&NXPostScriptPboardType num:1 owner:self];
  60.  
  61.     stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
  62.     [self copyPSCodeInside:&bounds to:stream];
  63.     NXFlush(stream);
  64.  
  65.     NXGetMemoryBuffer(stream, &buffer, &length, &maxLength);
  66.     [pasteboard writeType:NXPostScriptPboard data:buffer length:length];
  67.     NXCloseMemory(stream, NX_FREEBUFFER);
  68.         
  69.     return self;
  70. }
  71.  
  72. - drawSelf:(const NXRect *) rects :(int) rectCount
  73. {
  74.     mutex_lock(lock); {
  75.         NXImageBitmap(&virtualBounds, pixelsWide, pixelsHigh, bps, spp, config, mask, data[0], data[1], data[2], data[3], data[4]);
  76.         if(showGrid) [self drawGrid];
  77.         if(showCursor) [self drawCursor];
  78.         } mutex_unlock(lock);
  79.  
  80.     return self;
  81. }
  82.  
  83. - free
  84. {
  85.     unsigned int i;
  86.     
  87.     if (invisibleWindow != nil) [invisibleWindow close];
  88.  
  89.     for(i = 0; i < NX_MAXPLANES; i++) if (data[i] != NULL) free(data[i]);
  90.     
  91.     return [super free];
  92. }
  93.  
  94. - sizeTo:(NXCoord) newWidth :(NXCoord) newHeight;
  95. {    
  96.     id result;
  97.     
  98.     mutex_lock(lock); {
  99.         result = [super sizeTo:newWidth :newHeight];
  100.         } mutex_unlock(lock);
  101.     
  102.     [self createWindows];
  103.     
  104.     return result;
  105. }
  106.  
  107. - mouseMoved:(NXEvent *)theEvent
  108. {
  109.     int eventMask;
  110.     
  111.     if (mutex_try_lock(lock)) {
  112.         eventMask = [window removeFromEventMask:NX_MOUSEMOVEDMASK]; {
  113.             while([NXApp peekAndGetNextEvent:NX_MOUSEMOVEDMASK] != NULL);
  114.  
  115.             mouse = theEvent->location;
  116.             [window convertBaseToScreen:&mouse];
  117.  
  118.             } [window setEventMask:eventMask];
  119.             
  120.         mutex_unlock(lock);
  121.             
  122.         [[self updateBitmap:&mouse] display];
  123.         }
  124.  
  125.     return [nextResponder mouseMoved:theEvent];
  126. }
  127.  
  128. - drawCursor
  129. {
  130.     NXSize size;
  131.     NXPoint point; 
  132.     NXImage *image;
  133.     NXCursor *cursor;
  134.     const NXPoint origin = { 1, -1 }, *hotSpot = &origin;
  135.     
  136.     if((cursor = [NXCursor currentCursor]) == nil) return nil;
  137.     
  138.     [(image = [cursor image]) getSize:&size];
  139.         
  140. //    hotSpot = [cursor hotSpot]; /* NeXT left out this method! */
  141. //    (void) object_getInstanceVariable(cursor, "hotSpot", (void **) &hotSpot) /* should work, doesn't */
  142. //    hotSpot = (NXPoint *) (((void *) cursor) + 4); /* this hack works, 'but it would be wrong' */
  143.     
  144.     point.x = rint((bounds.size.width + scale) * HALF) - hotSpot->x; 
  145.     point.y = rint((bounds.size.height + scale) * HALF) - (size.height + hotSpot->y);
  146.  
  147.     [image composite:NX_SOVER toPoint:&point];
  148.  
  149.     return self;
  150. }
  151.  
  152. - drawGrid
  153. {    
  154.     float x, y, max;
  155.     
  156.     max = bounds.origin.y + bounds.size.height;
  157.     for(y = bounds.origin.y; y < max; y += grid)
  158.         PScompositerect(bounds.origin.x, y, bounds.size.width, GRIDLINEWIDTH, GRIDLINEMODE);
  159.         
  160.     max = bounds.origin.x + bounds.size.width;
  161.     for(x = bounds.origin.x; x < max; x += grid)
  162.         PScompositerect(x, bounds.origin.y, GRIDLINEWIDTH, bounds.size.height, GRIDLINEMODE);
  163.         
  164.     return self;
  165. }
  166.  
  167. - updateBitmap:(NXPoint *) point
  168. {
  169.     NXRect rect;
  170.     
  171.     mutex_lock(lock); {
  172.  
  173.         [invisibleView getFrame:&rect];
  174.  
  175.         [invisibleWindow moveTo:point->x - offset.width :point->y - offset.height];
  176.  
  177.         [invisibleWindow orderFront:self]; {
  178.             (void) [invisibleView lockFocus]; {
  179.                 NXReadBitmap(&rect, pixelsWide, pixelsHigh, bps, spp, config, mask, data[0], data[1], data[2], data[3], data[4]);
  180.                 } [invisibleView unlockFocus];
  181.             } [invisibleWindow orderOut:self];
  182.     
  183.         } mutex_unlock(lock);
  184.  
  185.     return self;
  186. }
  187.  
  188. - (float) scale { return scale; }
  189.  
  190. - setScale:(float) value
  191. {
  192.     mutex_lock(lock); {
  193.         scale = value;
  194.         } mutex_unlock(lock);
  195.     
  196.     return self;
  197. }
  198.  
  199. - (float) grid { return grid; }
  200.  
  201. - setGrid:(float) value
  202. {
  203.     mutex_lock(lock); {
  204.         showGrid = (BOOL) ((grid = value) > 0.0);
  205.         } mutex_unlock(lock);
  206.     
  207.     return self;
  208. }
  209.  
  210. - (BOOL) isFrozen { return frozen; }
  211.  
  212. - toggleFrozen:sender
  213. {
  214.     mutex_lock(lock); {
  215.         if (frozen = !frozen) (void) [window removeFromEventMask:NX_MOUSEMOVEDMASK];
  216.         else (void) [window addToEventMask:NX_MOUSEMOVEDMASK];
  217.         } mutex_unlock(lock);
  218.     
  219.     [[NXApp mainMenu] update];
  220.     
  221.     return self;
  222. }
  223.  
  224. - toggleCursor:sender
  225. {
  226.     mutex_lock(lock); {
  227.         showCursor = !showCursor;
  228.         } mutex_unlock(lock);
  229.  
  230.     return [self display];
  231. }
  232.  
  233. - createWindows
  234. {
  235.     NXRect rect;
  236.     size_t size;
  237.     unsigned int i;
  238.     
  239.     mutex_lock(lock); {
  240.     
  241.         rect = bounds;
  242.         
  243.         offset.width = (rect.size.width = sizeof(int) * ceil((bounds.size.width / scale) / sizeof(int))) * HALF;
  244.         offset.height = (rect.size.height = ceil(bounds.size.height / scale)) * HALF;
  245.  
  246.         virtualBounds = rect;
  247.         virtualBounds.size.width *= scale;
  248.         virtualBounds.size.height *= scale;
  249.         
  250.         if (invisibleWindow != nil) [invisibleWindow sizeWindow:rect.size.width :rect.size.height];
  251.         else {
  252.             invisibleWindow = [Window newContent:&rect style:NX_PLAINSTYLE backing:NX_NONRETAINED buttonMask:NX_NOBUTTONS defer:NO];
  253.             PSsetautofill(NO, [invisibleWindow windowNum]);
  254.             NXSetWindowLevel([invisibleWindow windowNum], NX_ALERTPANELLEVEL);
  255.             [invisibleWindow setEventMask:NX_NULLEVENTMASK];
  256.             [(invisibleView = [invisibleWindow contentView]) allocateGState];
  257.             }
  258.  
  259.         (void) [invisibleView lockFocus]; {
  260.             NXSizeBitmap(&rect, (int *) &size, &pixelsWide, &pixelsHigh, &bps, &spp, &config, &mask);
  261.             } [invisibleView unlockFocus];
  262.     
  263.         for(i = 0; i < NX_MAXPLANES; i++) {
  264.             if(data[i] == NULL) data[i] = malloc(size);
  265.             else if (size > malloc_size(data[i])) data[i] = realloc(data[i], size);
  266.             if(config == NX_MESHED) break;
  267.             }
  268.     
  269.         } mutex_unlock(lock);
  270.  
  271.     return [[self updateBitmap:&mouse] display];
  272. }
  273.  
  274. void timer(DPSTimedEntry teNumber, double now, void *id)
  275. {
  276.     MagnifyView *self = (MagnifyView *) id;
  277.     
  278.     if (![self isFrozen]) {
  279.         Window *window = [self window];
  280.         
  281.         [window getMouseLocation:&(self->mouse)];
  282.         [window convertBaseToScreen:&(self->mouse)];
  283.         [[self updateBitmap:&(self->mouse)] display];
  284.         }
  285. }
  286.  
  287. @end
  288.