This is IconView.m in view mode; [Download] [Up]
#import "IconView.h"
#import "ShelfView.h"
#import "Controller.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 = [[NXImage findImageNamed:"hilite"]
copyFromZone:[self zone]];
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, '/'))
[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);
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.