Annotation of Examples/AppKit/Draw/Image.m, revision 1.1

1.1     ! root        1: #import "draw.h"
        !             2: 
        !             3: /* Optimally viewed in a wide window.  Make your window big enough so that this comment fits on one line without wrapping. */
        !             4: 
        !             5: /*
        !             6:  * Image is a simple graphic which takes PostScript or
        !             7:  * TIFF images and draws them in a bounding box (it scales
        !             8:  * the image if the bounding box is changed).  It is
        !             9:  * implemented using the NXImage class.  Using NXImage
        !            10:  * here is especially nice since it images its PostScript
        !            11:  * in a separate context (thus, any errors that PostScript
        !            12:  * generates will not affect our main drawing context).
        !            13:  */
        !            14: 
        !            15: @implementation Image : Graphic
        !            16: 
        !            17: /* Initialize the class */
        !            18: 
        !            19: + initialize
        !            20: {
        !            21:     [Image setVersion:7];
        !            22:     return self;
        !            23: }
        !            24: 
        !            25: /* Factory methods. */
        !            26: 
        !            27: + highlightedLinkButtonImage:(NXSize *)size
        !            28: /*
        !            29:  * Just makes an NXLinkButtonH NXImage the same size as
        !            30:  * the size passed in.  I suppose this could just be a
        !            31:  * function.
        !            32:  */
        !            33: {
        !            34:     static NXImage *retval = nil;
        !            35:     if (!retval) {
        !            36:        retval = [[NXImage findImageNamed:"NXLinkButtonH"] copy];
        !            37:        [retval setScalable:YES];
        !            38:        [retval setDataRetained:YES];
        !            39:     }
        !            40:     [retval setSize:size];
        !            41:     return retval;
        !            42: }
        !            43: 
        !            44: + (BOOL)canInitFromPasteboard:(Pasteboard *)pboard
        !            45: {
        !            46:     return [NXImage canInitFromPasteboard:pboard];
        !            47: }
        !            48: 
        !            49: static BOOL checkImage(NXImage *anImage)
        !            50: /*
        !            51:  * Locking focus on an NXImage forces it to draw and thus verifies
        !            52:  * whether there are any PostScript or TIFF errors in the source of
        !            53:  * the image.  lockFocus returns YES only if there are no errors.
        !            54:  */
        !            55: {
        !            56:     if ([anImage lockFocus]) {
        !            57:        [anImage unlockFocus];
        !            58:        return YES;
        !            59:     }
        !            60:     return NO;
        !            61: }
        !            62: 
        !            63: /* Creation/Initialization Methods */
        !            64: 
        !            65: - init
        !            66: /*
        !            67:  * This creates basically an "empty" Image.
        !            68:  * This is the designated initializer for Image.
        !            69:  * Be careful, however, because by the time this
        !            70:  * returns, a newly initialized Image may not be
        !            71:  * fully initialized (it'll be "valid," just not
        !            72:  * necessarily fully initialized).  If you want that
        !            73:  * behaviour, override finishedWithInit.
        !            74:  */
        !            75: {
        !            76:     [super init];
        !            77:     originalSize.width = originalSize.height = 1.0;
        !            78:     bounds.size = originalSize;
        !            79:     return self;
        !            80: }
        !            81: 
        !            82: - finishedWithInit
        !            83: /*
        !            84:  * Called when a newly initialized Image is fully
        !            85:  * initialized and ready to roll.  For subclassers
        !            86:  * only.
        !            87:  */
        !            88: {
        !            89:     return self;
        !            90: }
        !            91: 
        !            92: - initEmpty
        !            93: /*
        !            94:  * Creates a blank Image.
        !            95:  */
        !            96: {
        !            97:     [self init];
        !            98:     return [self finishedWithInit];
        !            99: }
        !           100: 
        !           101: - initFromStream:(NXStream *)stream
        !           102: /*
        !           103:  * Creates a new NXImage and sets it to be scalable and to retain
        !           104:  * its data (which means that when we archive it, it will actually
        !           105:  * write the TIFF or PostScript data into the stream).
        !           106:  */
        !           107: {
        !           108:     [self init];
        !           109: 
        !           110:     if (stream) {
        !           111:        image = [NXImage allocFromZone:[self zone]];
        !           112:        if ((image = [image initFromStream:stream])) {
        !           113:            [image setDataRetained:YES];
        !           114:            if (checkImage(image)) {
        !           115:                [image getSize:&originalSize];
        !           116:                [image setScalable:YES];
        !           117:                bounds.size = originalSize;
        !           118:                return [self finishedWithInit];
        !           119:            }
        !           120:        }
        !           121:     }
        !           122: 
        !           123:     [self free];
        !           124: 
        !           125:     return nil;
        !           126: }
        !           127: 
        !           128: - initFromPasteboard:(Pasteboard *)pboard;
        !           129: /*
        !           130:  * Creates a new NXImage and sets it to be scalable and to retain
        !           131:  * its data (which means that when we archive it, it will actually
        !           132:  * write the TIFF or PostScript data into the stream).
        !           133:  */
        !           134: {
        !           135:     [self init];
        !           136: 
        !           137:     if (pboard) {
        !           138:        image = [NXImage allocFromZone:[self zone]];
        !           139:        if ((image = [image initFromPasteboard:pboard])) {
        !           140:            [image setDataRetained:YES];
        !           141:            if (checkImage(image)) {
        !           142:                [image getSize:&originalSize];
        !           143:                [image setScalable:YES];
        !           144:                bounds.size = originalSize;
        !           145:                return [self finishedWithInit];
        !           146:            }
        !           147:        }
        !           148:     }
        !           149: 
        !           150:     [self free];
        !           151: 
        !           152:     return nil;
        !           153: }
        !           154: 
        !           155: - initFromFile:(const char *)file
        !           156: /*
        !           157:  * Creates an NXImage by reading data from an .eps or .tiff file.
        !           158:  */
        !           159: {
        !           160:     [self init];
        !           161: 
        !           162:     image = [[NXImage allocFromZone:[self zone]] init];
        !           163:     if ([image loadFromFile:file]) {
        !           164:        [image setDataRetained:YES];
        !           165:        if (checkImage(image)) {
        !           166:            [image getSize:&originalSize];
        !           167:            [image setScalable:YES];
        !           168:            bounds.size = originalSize;
        !           169:            return [self finishedWithInit];
        !           170:        }
        !           171:     }
        !           172: 
        !           173:     [self free];
        !           174: 
        !           175:     return nil;
        !           176: }
        !           177: 
        !           178: - doInitFromImage:(NXImage *)anImage
        !           179: /*
        !           180:  * Common code for initFromImage: and unarchiving.
        !           181:  */
        !           182: {
        !           183:     if (anImage) {
        !           184:        image = anImage;
        !           185:        [image getSize:&originalSize];
        !           186:        [image setScalable:YES];
        !           187:        [image setDataRetained:YES];
        !           188:        bounds.size = originalSize;
        !           189:     } else {
        !           190:        [self free];
        !           191:        self = nil;
        !           192:     }
        !           193:     return self;
        !           194: }
        !           195: 
        !           196: - initFromImage:(NXImage *)anImage
        !           197: /*
        !           198:  * Initializes an Image from a specific NXImage.
        !           199:  */
        !           200: {
        !           201:     [self init];
        !           202:     return [[self doInitFromImage:anImage] finishedWithInit];
        !           203: }
        !           204: 
        !           205: - initFromIcon:(NXImage *)anImage
        !           206: /*
        !           207:  * Same as initFromImage:, but we remember that this particular
        !           208:  * NXImage was actually a file icon (which enables us to double-click
        !           209:  * on it to open the icon, see handleEvent:).
        !           210:  */
        !           211: {
        !           212:     if ([self initFromImage:anImage]) {
        !           213:        amIcon = YES;
        !           214:        return self;
        !           215:     } else {
        !           216:        return nil;
        !           217:     }
        !           218: }
        !           219: 
        !           220: - initWithLinkButton
        !           221: /*
        !           222:  * Creates an image which is just the link button.
        !           223:  * This is only applicable with Object Links.
        !           224:  */
        !           225: {
        !           226:     if ([self initFromImage:[[NXImage findImageNamed:"NXLinkButton"] copy]]) {
        !           227:        amLinkButton = YES;
        !           228:        return self;
        !           229:     } else {
        !           230:        return nil;
        !           231:     }
        !           232: }
        !           233: 
        !           234: - (NXRect)resetImage:(NXImage *)newImage
        !           235: /*
        !           236:  * Called by the "reinit" methods to reset all of our instance
        !           237:  * variables based on using a new NXImage for our image.
        !           238:  */
        !           239: {
        !           240:     NXRect eBounds, neBounds;
        !           241: 
        !           242:     [image free];
        !           243:     image = newImage;
        !           244:     [self getExtendedBounds:&eBounds];
        !           245:     [image getSize:&neBounds.size];
        !           246:     neBounds.size.width *= bounds.size.width / originalSize.width;
        !           247:     neBounds.size.height *= bounds.size.height / originalSize.height;
        !           248:     neBounds.origin.x = bounds.origin.x - floor((neBounds.size.width - bounds.size.width) / 2.0 + 0.5);
        !           249:     neBounds.origin.y = bounds.origin.y - floor((neBounds.size.height - bounds.size.height) / 2.0 + 0.5);
        !           250:     [self setBounds:&neBounds];
        !           251:     [self getExtendedBounds:&neBounds];
        !           252:     NXUnionRect(&eBounds, &neBounds);
        !           253:     [image setDataRetained:YES];
        !           254:     [image getSize:&originalSize];
        !           255:     [image setScalable:YES];
        !           256: 
        !           257:     return neBounds;
        !           258: }
        !           259: 
        !           260: - (NXRect)reinitFromPasteboard:(Pasteboard *)pboard
        !           261: /*
        !           262:  * Reset all of our instance variable based on extract an
        !           263:  * NXImage from data in the the passed pboard.  Happens when
        !           264:  * we update a link through Object Links.
        !           265:  */
        !           266: {
        !           267:     NXRect neBounds;
        !           268:     NXImage *newImage;
        !           269: 
        !           270:     newImage = [NXImage allocFromZone:[self zone]];
        !           271:     if ((newImage = [newImage initFromPasteboard:pboard])) {
        !           272:        [newImage setDataRetained:YES];
        !           273:        if (checkImage(newImage)) return [self resetImage:newImage];
        !           274:     }
        !           275: 
        !           276:     [newImage free];
        !           277:     neBounds.origin.x = neBounds.origin.y = 0.0;
        !           278:     neBounds.size.width = neBounds.size.height = 0.0;
        !           279: 
        !           280:     return neBounds;
        !           281: }
        !           282: 
        !           283: - (NXRect)reinitFromFile:(const char *)file
        !           284: /*
        !           285:  * Reset all of our instance variable based on extract an
        !           286:  * NXImage from the data in the passed file.  Happens when
        !           287:  * we update a link through Object Links.
        !           288:  */
        !           289: {
        !           290:     NXRect neBounds;
        !           291:     NXImage *newImage;
        !           292: 
        !           293:     newImage = [[NXImage allocFromZone:[self zone]] init];
        !           294:     if ([newImage loadFromFile:file]) {
        !           295:        [newImage setDataRetained:YES];
        !           296:        if (checkImage(newImage)) return [self resetImage:newImage];
        !           297:     }
        !           298: 
        !           299:     [newImage free];
        !           300:     neBounds.origin.x = neBounds.origin.y = 0.0;
        !           301:     neBounds.size.width = neBounds.size.height = 0.0;
        !           302: 
        !           303:     return neBounds;
        !           304: }
        !           305: 
        !           306: /* All those allocation/initialization method and only this one free method. */
        !           307: 
        !           308: - free
        !           309: {
        !           310:     [image free];
        !           311:     return [super free];
        !           312: }
        !           313: 
        !           314: /* Link methods */
        !           315: 
        !           316: - setLink:(NXDataLink *)aLink
        !           317: /*
        !           318:  * It's "might" be linked because we're linked now, but might
        !           319:  * have our link broken in the future and the mightBeLinked flag
        !           320:  * is only advisory and is never cleared.  It is used just so that
        !           321:  * we know we might want to try to reestablish a link with this
        !           322:  * Graphic after a cut/paste.  No biggie if there really is no
        !           323:  * link associated with this any more.  In gvLinks.m, see
        !           324:  * readLinkForGraphic:fromPasteboard:useNewIdentifier:, and in
        !           325:  * gvPasteboard.m, see pasteFromPasteboard:andLink:at:.
        !           326:  * If this Image is a link button, then we obviously never need
        !           327:  * to update the link because we don't actually show the data
        !           328:  * associated with the link (we just show that little link button).
        !           329:  */
        !           330: {
        !           331:     NXDataLink *oldLink = link;
        !           332:     link = aLink;
        !           333:     gFlags.mightBeLinked = YES;
        !           334:     if (amLinkButton) [link setUpdateMode:NX_UpdateNever];
        !           335:     return oldLink;
        !           336: }
        !           337: 
        !           338: - (NXDataLink *)link
        !           339: {
        !           340:     return link;
        !           341: }
        !           342: 
        !           343: /* Event-handling */
        !           344: 
        !           345: - trackLinkButton:(NXEvent *)event at:(const NXPoint *)startPoint inView:(View *)view
        !           346: /*
        !           347:  * This method tracks that little link button.  Note that the link button is a diamond,
        !           348:  * but we track the whole rectangle.  This is unfortunate, but we can't be sure that,
        !           349:  * in the future, the shape of the link button might not change (thus, what we really
        !           350:  * need is a NeXTSTEP function to track the thing!).  Anyway, we track it and if the 
        !           351:  * mouse goes up inside the button, we openSource on the link (we wouldn't be here if
        !           352:  * we didn't have a link).
        !           353:  */
        !           354: {
        !           355:     NXPoint p;
        !           356:     NXImage *realImage, *highImage, *imageToDraw;
        !           357: 
        !           358:     p = *startPoint;
        !           359:     realImage = image;
        !           360:     highImage = [[self class] highlightedLinkButtonImage:&bounds.size];
        !           361:     image = imageToDraw = highImage;
        !           362:     [self draw];
        !           363:     [[view window] flushWindow];
        !           364:     do {
        !           365:        event = [NXApp getNextEvent:NX_MOUSEDRAGGEDMASK|NX_MOUSEUPMASK];
        !           366:        p = event->location;
        !           367:        [view convertPoint:&p fromView:nil];
        !           368:        imageToDraw = NXMouseInRect(&p, &bounds, NO) ? highImage : realImage;
        !           369:        if (imageToDraw != image) {
        !           370:            image = imageToDraw;
        !           371:            [self draw];
        !           372:            [[view window] flushWindow];
        !           373:        }
        !           374:     } while (event->type != NX_MOUSEUP);
        !           375: 
        !           376:     if (imageToDraw == highImage) {
        !           377:        [link openSource];
        !           378:        image = realImage;
        !           379:        [self draw];
        !           380:        [[view window] flushWindow];
        !           381:     }
        !           382: 
        !           383:     return self;
        !           384: }
        !           385: 
        !           386: - (BOOL)handleEvent:(NXEvent *)event at:(const NXPoint *)p inView:(View *)view
        !           387: {
        !           388:     if (NXMouseInRect(p, &bounds, NO)) {
        !           389:        if (amLinkButton && !gFlags.selected && !(event->flags & (NX_CONTROLMASK|NX_SHIFTMASK|NX_ALTERNATEMASK))) {
        !           390:            [self trackLinkButton:event at:p inView:view];
        !           391:            return YES;
        !           392:        } else if (link && (event->data.mouse.click == 2) && (amIcon || (event->flags & NX_CONTROLMASK))) {
        !           393:            [NXApp getNextEvent:NX_MOUSEUPMASK];
        !           394:            [link openSource];
        !           395:            return YES;
        !           396:        }
        !           397:     }
        !           398:     return NO;
        !           399: }
        !           400: 
        !           401: /* Methods overridden from superclass to support links. */
        !           402: 
        !           403: - (int)cornerMask
        !           404: /*
        !           405:  * Link buttons are too small to have corners AND sides, so
        !           406:  * we only let link buttons have knobbies on the corners.
        !           407:  */
        !           408: {
        !           409:     if (amLinkButton) {
        !           410:        return LOWER_LEFT_MASK|UPPER_LEFT_MASK|UPPER_RIGHT_MASK|LOWER_RIGHT_MASK;
        !           411:     } else {
        !           412:        return [super cornerMask];
        !           413:     }
        !           414: }
        !           415: 
        !           416: - (NXRect *)getExtendedBounds:(NXRect *)theRect
        !           417: /*
        !           418:  * We have to augment this because we might have a link frame
        !           419:  * (if show links is on), so we have to extend our extended bounds
        !           420:  * a bit.
        !           421:  */
        !           422: {
        !           423:     NXRect linkBounds, *retval;
        !           424:     float linkFrameThickness = NXLinkFrameThickness();
        !           425: 
        !           426:     linkBounds = bounds;
        !           427:     linkBounds.origin.x -= linkFrameThickness;
        !           428:     linkBounds.size.width += linkFrameThickness * 2.0;
        !           429:     linkBounds.origin.y -= linkFrameThickness;
        !           430:     linkBounds.size.height += linkFrameThickness;
        !           431: 
        !           432:     retval = [super getExtendedBounds:theRect];
        !           433: 
        !           434:     return NXUnionRect(&linkBounds, retval);
        !           435: }
        !           436: 
        !           437: - (BOOL)constrainByDefault;
        !           438: /*
        !           439:  * Icons and link buttons look funny outside their natural
        !           440:  * aspect ratio, so we constrain them (by default) to keep
        !           441:  * their natural ratio.  You can still use the Alternate key
        !           442:  * to NOT constrain these.
        !           443:  */
        !           444: {
        !           445:     return (amLinkButton || amIcon);
        !           446: }
        !           447: 
        !           448: /* Methods overridden from superclass */
        !           449: 
        !           450: - (BOOL)isValid
        !           451: {
        !           452:     return image ? YES : NO;
        !           453: }
        !           454: 
        !           455: - (BOOL)isOpaque
        !           456: {
        !           457:     return [[image bestRepresentation] isOpaque];
        !           458: }
        !           459: 
        !           460: - (float)naturalAspectRatio
        !           461: {
        !           462:     if (!originalSize.height) return 0.0;
        !           463:     return originalSize.width / originalSize.height;
        !           464: }
        !           465: 
        !           466: - draw
        !           467: /*
        !           468:  * If we are resizing, we just draw a gray box.
        !           469:  * If not, then we simply see if our bounds have changed
        !           470:  * and update the NXImage object if they have.  Then,
        !           471:  * if we do not allow alpha (i.e. this is a TIFF image),
        !           472:  * we paint a white background square (we don't allow
        !           473:  * alpha in our TIFF images since it won't print and
        !           474:  * Draw is WYSIWYG).  Finally, we SOVER the image.
        !           475:  * If we are not keeping the cache around, we tell
        !           476:  * NXImage to toss its cached version of the image
        !           477:  * via the message recache.
        !           478:  *
        !           479:  * If we are linked to something and the user has chosen
        !           480:  * "Show Links", then linkOutlinesAreVisible, so we must
        !           481:  * draw a link border around ourself.
        !           482:  */
        !           483: {
        !           484:     NXRect r;
        !           485:     NXPoint p;
        !           486:     NXSize currentSize;
        !           487: 
        !           488:     if (bounds.size.width < 1.0 || bounds.size.height < 1.0) return self;
        !           489: 
        !           490:     if (DrawStatus == Resizing) {
        !           491:        PSsetgray(NX_DKGRAY);
        !           492:        PSsetlinewidth(0.0);
        !           493:        PSrectstroke(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
        !           494:     } else if (image) {
        !           495:        p = bounds.origin;
        !           496:        [image getSize:&currentSize];
        !           497:        if (currentSize.width != bounds.size.width || currentSize.height != bounds.size.height) {
        !           498:            if ([image isScalable]) {
        !           499:                [image setSize:&bounds.size];
        !           500:            } else {
        !           501:                p.x = bounds.origin.x + floor((bounds.size.width - currentSize.width) / 2.0 + 0.5);
        !           502:                p.y = bounds.origin.y + floor((bounds.size.height - currentSize.height) / 2.0 + 0.5);
        !           503:            }
        !           504:        }
        !           505:        if ([[image bestRepresentation] isOpaque]) {
        !           506:            PSsetgray(NX_WHITE);
        !           507:            NXRectFill(&bounds);
        !           508:        }
        !           509:        [image composite:NX_SOVER toPoint:&p];
        !           510:        if (dontCache && NXDrawingStatus == NX_DRAWING) [image recache];
        !           511:        if ((NXDrawingStatus == NX_DRAWING) && !amLinkButton && [[link manager] areLinkOutlinesVisible]) {
        !           512:            r.origin.x = floor(bounds.origin.x);
        !           513:            r.origin.y = floor(bounds.origin.y);
        !           514:            r.size.width = floor(bounds.origin.x + bounds.size.width + 0.99) - r.origin.x;
        !           515:            r.size.height = floor(bounds.origin.y + bounds.size.height + 0.99) - r.origin.y;
        !           516:            NXFrameLinkRect(&r, YES);   // YES means "is a destination link"
        !           517:        }
        !           518:     }
        !           519: 
        !           520:     return self;
        !           521: }
        !           522: 
        !           523: /* Direct writing of EPS or TIFF. */
        !           524: 
        !           525: - (BOOL)canEmitEPS
        !           526: /*
        !           527:  * If we have a representation that can provide EPS directly, then,
        !           528:  * if we are copying PostScript to the Pasteboard and this Image is the
        !           529:  * only Graphic selected, then we might as well just have the EPS which
        !           530:  * represents this Image go straight to the Pasteboard rather than
        !           531:  * wrapping it up in the copyPSCodeInside: wrappers.  Of course, we
        !           532:  * can only do that if we haven't been resized.
        !           533:  *
        !           534:  * See gvPasteboard.m's writePSToStream:.
        !           535:  */
        !           536: {
        !           537:     List *reps = [image representationList];
        !           538:     int i = [reps count];
        !           539: 
        !           540:     if (originalSize.width == bounds.size.width && originalSize.height == bounds.size.height) {
        !           541:        while (i--) {
        !           542:            if ([[reps objectAt:i] respondsTo:@selector(getEPS:length:)]) {
        !           543:                return YES;
        !           544:            }
        !           545:        }
        !           546:     }
        !           547: 
        !           548:     return NO;
        !           549: }
        !           550: 
        !           551: - writeEPSToStream:(NXStream *)stream
        !           552: /*
        !           553:  * If canEmitEPS above returns YES, then we can write ourself out directly
        !           554:  * as EPS.  This method does that.
        !           555:  */
        !           556: {
        !           557:     List *reps = [image representationList];
        !           558:     int i = [reps count];
        !           559:     char *data;
        !           560:     int length;
        !           561: 
        !           562:     while (i--) {
        !           563:        if ([[reps objectAt:i] respondsTo:@selector(getEPS:length:)]) {
        !           564:            [[reps objectAt:i] getEPS:&data length:&length];
        !           565:            NXWrite(stream, data, length);
        !           566:            return self;                        // should I free data before returning?
        !           567:        }
        !           568:     }
        !           569: 
        !           570:     return self;
        !           571: }
        !           572: 
        !           573: - (BOOL)canEmitTIFF
        !           574: /*
        !           575:  * Similar to canEmitEPS, except its for TIFF.
        !           576:  */
        !           577: {
        !           578:     return (originalSize.width == bounds.size.width && originalSize.height == bounds.size.height);
        !           579: }
        !           580: 
        !           581: - writeTIFFToStream:(NXStream *)stream
        !           582: /*
        !           583:  * Ditto above.
        !           584:  */
        !           585: {
        !           586:     [image writeTIFF:stream allRepresentations:YES];
        !           587:     return self;
        !           588: }
        !           589: 
        !           590: /* Caching. */
        !           591: 
        !           592: - setCacheable:(BOOL)flag
        !           593: {
        !           594:     dontCache = flag ? NO : YES;
        !           595:     return self;
        !           596: }
        !           597: 
        !           598: - (BOOL)isCacheable
        !           599: {
        !           600:     return !dontCache;
        !           601: }
        !           602: 
        !           603: /* Archiving. */
        !           604: 
        !           605: - write:(NXTypedStream *)stream
        !           606: /*
        !           607:  * All that is needed to archive the NXImage.
        !           608:  */
        !           609: {
        !           610:     [super write:stream];
        !           611:     NXWriteType(stream, "c", &amLinkButton);
        !           612:     NXWriteType(stream, "c", &amIcon);
        !           613:     if (!amLinkButton) {
        !           614:        NXWriteObject(stream, image);
        !           615:        NXWriteSize(stream, &originalSize);
        !           616:     }
        !           617:     return self;
        !           618: }
        !           619: 
        !           620: - read:(NXTypedStream *)stream
        !           621: /*
        !           622:  * This contains lots of compatibility code for
        !           623:  * interim versions.  See if you can figure out the
        !           624:  * various ways we approached archiving link info!
        !           625:  */
        !           626: {
        !           627:     BOOL alphaOk;
        !           628:     NXRect savedBounds;
        !           629:     int version, linkNumber;
        !           630: 
        !           631:     [super read:stream];
        !           632:     version = NXTypedStreamClassVersion(stream, "Image");
        !           633:     if (version > 5) NXReadType(stream, "c", &amLinkButton);
        !           634:     if (version > 6) NXReadType(stream, "c", &amIcon);
        !           635:     if (amLinkButton) {
        !           636:        savedBounds = bounds;
        !           637:        [self doInitFromImage:[[NXImage findImageNamed:"NXLinkButton"] copy]];
        !           638:        bounds = savedBounds;
        !           639:     } else {
        !           640:        image = NXReadObject(stream);
        !           641:        NXReadSize(stream, &originalSize);
        !           642:     }
        !           643:     if (version <= 2) NXReadTypes(stream, "c", &alphaOk);
        !           644:     if (version == 4) {
        !           645:        NXReadObject(stream);   // used to be the NXDataLink
        !           646:     } else if (version > 2 && version < 6) {
        !           647:        NXReadTypes(stream, "i", &linkNumber);
        !           648:     }
        !           649: 
        !           650:     return self;
        !           651: }
        !           652: 
        !           653: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.