This is IconView.m in view mode; [Download] [Up]
#import <GKappkit/GKappkit.h> #import "IconView.h" #import "ShelfView.h" #import "MonsterShelf.h" #import <appkit/workspaceRequest.h> #import <appkit/appkit.h> #import <mach/mach.h> #import <bsd/sys/file.h> #define IMAGE_INSET 2 @implementation NXImage(UsefulMethod) - scaleToFitInside:(NXSize) size max:(NXSize) maxSize { NXSize imageSize; float scale; [self getSize:&imageSize]; scale = MIN(size.width/imageSize.width, size.height/imageSize.height); size.width = (scale * (float)imageSize.width); size.height = (scale * (float)imageSize.height); if (size.width > maxSize.width) size.width = maxSize.width; if (size.height > maxSize.height) size.height = maxSize.height; [self setSize:&size]; return self; } @end @implementation IconView : View static id scaledHilite; static id scaledTile; + initialize { scaledHilite = nil; scaledTile = nil; [self resetCachedImages]; return self; } + resetCachedImages { [scaledTile free]; scaledTile = [[NXImage findImageNamed:"NXAppTile"] copyFromZone:[self zone]]; [scaledHilite free]; scaledHilite = [[self module]loadImage:"hilite"]; return self; } + hilite { return scaledHilite; } + appTile { return scaledTile; } /* * Create a copy of an IconView (or an IconView subclass). Note that this * method cheats by potentially changing the class of the copied image. */ + copyIconView:aView { NXRect aFrame; void *oldData; unsigned int len; [aView getFrame:&aFrame]; [aView getData:&oldData andLength:&len]; return [[self allocFromZone:[aView zone]] initFrame:&aFrame image:[[aView image] copy] data:oldData andLength:len useSize:YES useTile:[aView useTile]]; } /* * Initialize a new IconView. The only thing sneaky about this * method is that we may interpret the size of the frame as the * max size for the frame. */ - initFrame:(const NXRect *) newFrame image:anImage data:(const void *) someData andLength:(unsigned int) newLength useSize:(BOOL) sizeValid useTile:(BOOL) showTile { NXSize imageSize = {48, 48}; tempImage = NULL; selected = NO; ghost = NO; useTile = showTile; appTile = [IconView appTile]; [appTile getSize:&tileMax]; hilite = [IconView hilite]; [hilite getSize:&hiliteMax]; image = anImage; imageMax = imageSize; /* * Copy the data, with null termination if it's not already. */ if (newLength > 0 && *((char *)someData + newLength - 1)) length = newLength + 1; else length = newLength; data = NXZoneMalloc([self zone], length); bcopy(someData, data, length); *((char *)data + length - 1) = '\0'; /* * Allocate a cell, and slam the filename into it. Make sure to use * only the last component of the path. */ titleCell = [[TextFieldCell allocFromZone:[self zone]] init]; [titleCell setAlignment:NX_CENTERED]; [titleCell setBackgroundTransparent:YES]; if (rindex(data, '/')) { const char *p; if((p=strstr(data,"/PB.project"))&&(p>(char *)data)&&(p[11]==0)) { // project!!! char *tmp; char *wp; tmp=malloc(strlen(data)+1); strcpy(tmp,data); wp=strrchr(tmp,'/'); *wp=0; if(wp=strrchr(tmp,'/')) { wp++; } else { wp=tmp; } [titleCell setStringValue:wp]; free(tmp); } else { [titleCell setStringValue:rindex(data, '/') + 1]; } } else [titleCell setStringValue:data]; /* * If there's no frame, make one that's the right size to hold * everything. */ if (!sizeValid) { NXSize titleSize; NXRect aRect = { {0,0}, {0,0} }; if (useTile) { [appTile getSize:&imageSize]; if (newFrame) aRect.origin = newFrame->origin; aRect.size.height = imageSize.height; aRect.size.width = imageSize.width; } else { [hilite getSize:&imageSize]; [titleCell calcCellSize:&titleSize]; if (newFrame) aRect.origin = newFrame->origin; aRect.size.height = imageSize.height + titleSize.height; aRect.size.width = MAX(titleSize.width, imageSize.width); } [super initFrame:&aRect]; } else [super initFrame:newFrame]; [self setImageSize]; return self; } - initFromDragContext:(id <NXDraggingInfo>)context andSize:(NXSize *) aSize isOn:(BOOL)showTile; { NXImage *copiedImage = [context draggedImageCopy]; Pasteboard *pb = [Pasteboard newName:NXDragPboard]; char *pbData; NXRect aRect = { {0,0}, {0,0} }; NXRect *rectPtr = NULL; unsigned int len; [pb readType:NXFilenamePboardType data:&pbData length:&len]; if (aSize != NULL) { rectPtr = &aRect; aRect.size = *aSize; } [self initFrame:rectPtr image:copiedImage data:pbData andLength:len+1 useSize:aSize != NULL useTile:showTile]; return self; } - free { free(data); [image free]; [titleCell free]; [tempImage free]; return [super free]; } - (NXCoord) cellHeight { NXSize cellSize; [titleCell calcCellSize:&cellSize]; return cellSize.height; } - getImagePoint:(NXPoint *) imageLoc andTilePoint:(NXPoint *)tileLoc andHilitePoint:(NXPoint *) hiliteLoc { NXCoord cellHeight; NXPoint baseSpot; NXSize hiliteSize, imageSize, tileSize; cellHeight = [self cellHeight]; [appTile getSize:&tileSize]; [image getSize:&imageSize]; [hilite getSize:&hiliteSize]; /* Two ways to calculate where everybody goes. If we are going to use the background tile, then find out where that goes, and center the image on that, shifted vertically so that the cell can fit underneath. */ if (useTile) { baseSpot.x = (bounds.size.width - tileSize.width) / 2; baseSpot.y = (bounds.size.height - tileSize.height) / 2; if (tileLoc) { tileLoc->x = baseSpot.x; tileLoc->y = baseSpot.y; } /* The image then needs to be put in the upper center of the background tile, with enough space underneath to fit the cell. */ if (imageLoc) { imageLoc->x = baseSpot.x + (tileSize.width - imageSize.width) / 2; imageLoc->y = baseSpot.y + cellHeight + ((tileSize.height - (imageSize.height + cellHeight + IMAGE_INSET)) / 2); } if (hiliteLoc) { hiliteLoc->x = (bounds.size.width - hiliteSize.width) / 2; hiliteLoc->y = (bounds.size.height - hiliteSize.height) / 2; } } else { baseSpot.x = (bounds.size.width - imageSize.width) / 2; baseSpot.y = cellHeight + (bounds.size.height - imageSize.height - cellHeight) / 2; if (imageLoc) { imageLoc->x = baseSpot.x; imageLoc->y = baseSpot.y; } if (hiliteLoc) { hiliteLoc->x = baseSpot.x - ((hiliteSize.width - imageSize.width) / 2)+1.5; hiliteLoc->y = baseSpot.y - ((hiliteSize.height - imageSize.height) / 2); } } return self; } - (void) setImageSize { NXSize imageSize; [image setScalable:YES]; [hilite setScalable:YES]; [appTile setScalable:YES]; imageSize = bounds.size; /* If we are using the background tile, then we need to make sure that the image size is slightly less than the real size, or it could completely obscure a smaller tile. */ if (useTile) { [appTile scaleToFitInside:imageSize max:tileMax]; [hilite scaleToFitInside:imageSize max:hiliteMax]; imageSize.width -= IMAGE_INSET; imageSize.height -= (IMAGE_INSET + [self cellHeight]); [image scaleToFitInside:imageSize max:imageMax]; } else { imageSize.height -= [self cellHeight]; [hilite scaleToFitInside:imageSize max:hiliteMax]; [image scaleToFitInside:imageSize max:imageMax]; } } - sizeTo:(NXCoord) width :(NXCoord) height { [super sizeTo:width :height]; [self setImageSize]; [self display]; return self; } - drawSelf:(const NXRect *) rects :(int) rectCount { NXPoint tilePoint, imagePoint, hilitePoint; NXRect cellRect, tileRect; NXSize tileSize, tempSize; if (tempImage == NULL) tempImage = [[NXImage alloc] initSize:&bounds.size]; else { [tempImage getSize:&tempSize]; if ((tempSize.width != bounds.size.width) || (tempSize.height != bounds.size.height)) { [tempImage free]; tempImage = [[NXImage alloc] initSize:&bounds.size]; } } [self getImagePoint:&imagePoint andTilePoint:&tilePoint andHilitePoint:&hilitePoint]; NXSetRect(&cellRect, 0, hilitePoint.y - [self cellHeight], bounds.size.width, [self cellHeight]); if (useTile) { [appTile getSize:&tileSize]; NXSetRect(&tileRect, tilePoint.x, tilePoint.y, tileSize.width, tileSize.height); NXSetRect(&cellRect, 0, tilePoint.y + IMAGE_INSET, tileSize.width, [self cellHeight]); } /* Tweak the color of the text to make sure that it is visible. */ if (NXBrightnessComponent([superview backgroundColor]) < NX_DKGRAY + 0.01) [titleCell setTextGray:[self isGhost] ? NX_LTGRAY : NX_WHITE]; else [titleCell setTextGray:[self isGhost] ? NX_DKGRAY : NX_BLACK]; /* Are we a ghost? If so, create a transparent version of ourselves. */ if ([self isGhost]) { /* Create the composite image used for ghosting. */ if (useTile) { if ([tempImage lockFocus]) { PSsetalpha(0); PSsetgray(1); NXRectFill(&bounds); [appTile composite:NX_SOVER toPoint:&tilePoint]; [image composite:NX_SOVER toPoint:&imagePoint]; [tempImage unlockFocus]; } [tempImage dissolve:0.666 toPoint:&bounds.origin]; } else { if ([tempImage lockFocus]) { PSsetalpha(0); PSsetgray(0); NXRectFill(&bounds); [image dissolve:0.666 toPoint:&imagePoint]; [tempImage unlockFocus]; } [tempImage composite:NX_SOVER toPoint:&bounds.origin]; } } else { /* Are we highlighting ourselves? If we are using background tiles, then we have to create another temporary image, set it's background to transparent, then draw a white, non-transparent rectangle on it, and then draw in the ghost. */ if ([self state]) { if (useTile) { if ([tempImage lockFocus]) { PSsetalpha(1); PSsetgray(0); NXRectFill(&bounds); [appTile composite:NX_DOUT toPoint:&tilePoint]; [tempImage unlockFocus]; } [appTile composite:NX_SOVER toPoint:&tilePoint]; [image composite:NX_SOVER toPoint:&imagePoint]; [titleCell drawInside:&cellRect inView:self]; [tempImage dissolve:0.666 toPoint:&bounds.origin]; } else { [hilite composite:NX_SOVER toPoint:&hilitePoint]; [image composite:NX_SOVER toPoint:&imagePoint]; [titleCell drawInside:&cellRect inView:self]; } } else { NXRect aRect; aRect = bounds; [self convertRect:&aRect toView:superview]; [superview lockFocus]; [superview drawSelf:&aRect :1]; [superview unlockFocus]; if (useTile) { [appTile composite:NX_SOVER toPoint:&tilePoint]; } [image composite:NX_SOVER toPoint:&imagePoint]; [titleCell drawInside:&cellRect inView:self]; } } return self; } - image { return image; } - (BOOL) useTile { return useTile; } - getData:(void **) aPtr andLength:(unsigned int *) aLength { *aPtr = data; *aLength = length; return self; } - setGhost:(BOOL) newGhost { ghost = newGhost; return self; } - (BOOL) isGhost { return ghost; } - (int) state { return selected; } - setState:(int) flag { if (flag ^ selected) { selected = flag ? YES : NO; [self display]; } return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.