This is ShelfView.m in view mode; [Download] [Up]
#import "Fiend.h"
#import "ShelfView.h"
#import "IconView.h"
#import "IconDragView.h"
#import "ProgressView.h"
#import "Controller.h"
#import "compositeBackground.h"
#import <math.h>
#import <appkit/appkit.h>
#import <3Dkit/3Dkit.h>
#import <ansi/stdio.h>
#import <ansi/string.h>
@implementation ShelfView
- initFrame:(const NXRect *) aFrame
{
int screenCount;
char *backgroundString;
NXScreen *screens;
const char *fileString;
const char *colorString;
const char *const types[1] = {NXFilenamePboardType};
gridValue = atoi(NXGetDefaultValue([NXApp appName], SGRID_VALUE));
gridEnabled = !strcmp(NXGetDefaultValue([NXApp appName], GRID_ENABLE), "YES");
[super initFrame:aFrame];
[[self window] setDelegate:self];
[self registerForDraggedTypes:types count:1];
/*
* Determine the background color.
*/
useBGColor = NO;
[NXApp getScreens:&screens count:&screenCount];
if (screens[0].depth == NX_TwoBitGrayDepth)
backgroundString = "BWBackgroundColor";
else
backgroundString = "BackgroundColor";
colorString = NXGetDefaultValue("NeXT1", backgroundString);
if (colorString) {
float r, g, b;
sscanf(colorString, "%f %f %f", &r, &g, &b );
bgColor = NXConvertRGBAToColor(r, g, b, NX_NOALPHA);
useBGColor = YES;
}
/*
* Now that we've set up our view's appearance, do the rest of the
* initialization we need to do.
*/
[window disableFlushWindow];
[self readShelf:YES];
tileImage = !strcmp(NXGetDefaultValue([NXApp appName], TILE_IMAGE), "YES");
fileString = NXGetDefaultValue([NXApp appName], IMAGE_NAME);
if (fileString)
[self setImageFileName:fileString];
[[window reenableFlushWindow] flushWindow];
return self;
}
- free
{
if (theImage != nil)
[theImage free];
return [super free];
}
- (BOOL) acceptsFirstMouse
{
return YES;
}
- (NXColor) backgroundColor
{
if (useBGColor)
return bgColor;
else
return NX_COLORLTGRAY;
}
- (BOOL) isAnyViewAt:(NXPoint) aPoint besides:aView
{
id testView;
int i;
NXRect rect;
NXRect interRect;
int max = [subviews count];
for (i = 0; i < max; i++) {
if ((testView = [subviews objectAt:i]) == aView)
continue;
[testView getFrame:&rect];
NXSetRect(&interRect, aPoint.x, aPoint.y, gridValue, gridValue);
if (NXIntersectionRect(&rect, &interRect))
return YES;
}
return NO;
}
/*
* Align all of our IconViews on the grid. Take care so that none overlap.
*/
- (void) alignSubviews
{
int i;
int max = [subviews count];
for (i = 0; i < max; i++) {
id view = [[self subviews] objectAt:i];
NXRect rect;
NXPoint candidatePt;
int count;
if (![view isKindOf:[IconView class]])
continue;
/*
* Make the icon the right size, and then compute the new origin.
*/
[view getFrame:&rect];
candidatePt.x = gridValue * (int)(rect.origin.x/gridValue);
candidatePt.y = gridValue * (int)(rect.origin.y/gridValue);
count = bounds.size.height * bounds.size.width / gridValue;
while (count-- > 0 && [self isAnyViewAt:candidatePt besides:view]) {
candidatePt.x -= gridValue;
if (candidatePt.x < 0) {
candidatePt.x = gridValue;
candidatePt.y -= gridValue;
if (candidatePt.y < gridValue) {
candidatePt.y = gridValue;
candidatePt.x -= gridValue;
}
}
}
[view moveTo:candidatePt.x :candidatePt.y];
}
[self writeShelf];
[self display];
}
- (BOOL)tileImage
{
return tileImage;
}
- setTileImage:(BOOL)flag
{
tileImage = flag;
NXWriteDefault([NXApp appName], TILE_IMAGE, (flag)?"YES":"NO");
return self;
}
- (char *)getImageFileName
{
return imageFileName;
}
- setImageFileName:(const char *)theName
{
id image;
id repList;
int i;
NXSize imageSize;
NXImageRep *rep;
if (!theName || !strlen(theName)) {
theImage = nil;
imageFileName[0] = '\0';
}
else {
image = [[NXImage alloc] initFromFile:theName];
if (image == nil) {
NXBeep();
return nil;
}
[theImage free];
theImage = image;
[theImage getSize:&imageSize];
if (!tileImage || NX_WIDTH(&frame) < imageSize.width ||
NX_HEIGHT(&frame) < imageSize.height) {
[theImage setScalable:YES];
[theImage setSize:&frame.size];
}
strcpy(imageFileName, theName);
repList = [theImage representationList];
for(i = 0; i < [repList count]; i++) {
rep = [repList objectAt:i];
if ([rep isKindOf:[N3DRIBImageRep class]]) {
[(N3DRIBImageRep *)rep setSurfaceType:N3D_FacetedSolids];
break;
}
}
}
(void) NXWriteDefault([NXApp appName], IMAGE_NAME, imageFileName);
[self display];
return self;
}
- (BOOL) gridEnabled
{
return gridEnabled;
}
- (void)setGridEnabled:(BOOL) flag
{
gridEnabled = flag;
(void) NXWriteDefault([NXApp appName], GRID_ENABLE, flag ? "YES" : "NO");
}
- (int)gridValue
{
return gridValue;
}
- setGridValue:(int)aValue
{
char gridString[20];
if (aValue == gridValue)
return self;
gridValue = aValue;
if (gridValue < MIN_GRID_VALUE)
gridValue = MIN_GRID_VALUE;
else if (gridValue > MAX_GRID_VALUE)
gridValue = MAX_GRID_VALUE;
[window disableFlushWindow];
[[self subviews] freeObjects];
[IconView resetCachedShelfImages];
[[self readShelf:NO] display];
[[window reenableFlushWindow] flushWindow];
sprintf(gridString, "%d", gridValue);
NXWriteDefault([NXApp appName], SGRID_VALUE, gridString);
return self;
}
- drawSelf:(const NXRect *) rects :(int) rectCount
{
int i;
int j;
int rectIndex;
int vertCount;
int horizCount;
NXPoint thePoint;
NXRect interRect;
NXRect theRect = {{0.0, 0.0}, {0.0, 0.0}};
if (useBGColor) {
NXSetColor(bgColor);
NXRectFill(rects);
}
else
compositeFromWorkspaceWindow(rects->origin.x, rects->origin.y,
rects->size.width, rects->size.height);
if (theImage != nil) {
[theImage getSize:&theRect.size];
vertCount = NX_HEIGHT(&frame)/NX_HEIGHT(&theRect);
horizCount = NX_WIDTH(&frame)/NX_WIDTH(&theRect);
for(rectIndex = 0; rectIndex < rectCount; rectIndex++) {
for(i = 0; i < horizCount+1; i++) {
for(j = 0; j < vertCount+1; j++) {
NXSetRect(&interRect, NX_WIDTH(&theRect)*i, NX_HEIGHT(&theRect)*j,
NX_WIDTH(&theRect), NX_HEIGHT(&theRect));
if (NXIntersectionRect(&rects[rectIndex], &interRect)) {
thePoint = interRect.origin;
NX_X(&interRect) = fmod(NX_X(&interRect), NX_WIDTH(&theRect));
NX_Y(&interRect) = fmod(NX_Y(&interRect), NX_HEIGHT(&theRect));
[theImage composite:NX_SOVER fromRect:&interRect toPoint:&thePoint];
}
}
}
}
}
return self;
}
- deselectAll:sender
{
NXRect away = {{-100.0, -100.0}, {1.0, 1.0}};
[self selectViewsInRect:&away deselect:YES];
return NO;
}
- removeView:aView
{
NXRect viewFrame;
[aView getFrame:&viewFrame];
[aView removeFromSuperview];
[self display:&viewFrame :1 :NO];
return self;
}
- addView:aView
{
NXRect viewFrame;
[aView getFrame:&viewFrame];
[self addSubview:aView];
[self display:&viewFrame :1 :NO];
return self;
}
- deleteView:aView
{
[self removeView:aView];
[aView free];
return self;
}
/*
* Return true if the point is in the area we use to get rid of views
*/
- (BOOL) isDeadZone:(NXPoint *) aPoint
{
NXRect goodZone = bounds;
NXInsetRect(&goodZone, 2, 2);
return !NXMouseInRect(aPoint, &goodZone, NO);
}
- (void) createViewForPath:(const char *) path at:(NXPoint *) point
{
id image;
id newView;
struct stat st;
NXRect aRect = {{0.0, 0.0}, {gridValue, gridValue}};
if (stat(path, &st) < 0)
return;
image = [IconView getImageForPath:path fileIcon:NO];
newView = [[IconDragView alloc] initFrame:&aRect image:image
data:path andLength:strlen(path)+1 useSize:YES onDock:NO];
aRect.origin = *point;
[[newView setFrame:&aRect] display];
[self addSubview:newView];
[newView getFrame:&aRect];
[self display:&aRect :1 :NO];
}
static BOOL
prefix(const char *prefix, const char *string)
{
while (*prefix && *string && *prefix == *string) {
prefix++;
string++;
}
return *prefix == '\0';
}
- (void) removeViewForPath:(const char *) fullPath
{
int i = [[self subviews] count];
while (i > 0) {
char *path;
unsigned int len;
id view = [[self subviews] objectAt:i];
if ([view isKindOf:[IconView class]]) {
[view getData:(void *) &path andLength:&len];
if (prefix(fullPath, path))
[self deleteView:view];
}
i--;
}
}
/*
* Find the right position for the new image, based on the grid and the
* mouse's location.
*/
- (NXPoint) viewLocationForContext:(id <NXDraggingInfo>)dragContext
{
NXPoint newLoc;
NXPoint imagePt = [dragContext draggedImageLocation];
NXPoint mousePt = [dragContext draggingLocation];
NXPoint imageOffset;
[draggedView getImagePoint:&imageOffset andHilitePoint:NULL];
if (gridEnabled) {
NXRect rect;
[draggedView getFrame:&rect];
newLoc.x = mousePt.x - ((int) mousePt.x % gridValue) +
(gridValue - rect.size.width) / 2;
newLoc.y = mousePt.y - (int) mousePt.y % gridValue;
}
else {
newLoc.x = imagePt.x - imageOffset.x;
newLoc.y = imagePt.y - imageOffset.y;
}
return newLoc;
}
/*
* Make a ghost image to indicate that we're really a destination.
*/
- (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
{
NXSize aSize;
NXPoint newLoc;
if ([sender draggingSourceOperationMask] == NX_DragOperationNone)
return NX_DragOperationNone;
else if ([sender draggingSourceOperationMask] == NX_DragOperationPrivate)
return NX_DragOperationNone;
aSize.width = [self gridValue];
aSize.height = aSize.width;
draggedView = [[IconView allocFromZone:[self zone]]
initFromDragContext:sender andSize:&aSize onDock:NO];
newLoc = [self viewLocationForContext:sender];
[draggedView moveTo:newLoc.x :newLoc.y];
[draggedView setGhost:YES];
if (gridEnabled)
[self addView:draggedView];
return NX_DragOperationLink;
}
/*
* Move the dragged image, but only do it if we need to (that is, if the
* mouse moved to a new grid cell).
*/
- (NXDragOperation)draggingUpdated:(id <NXDraggingInfo>)sender
{
NXPoint mouseLoc;
NXPoint newLoc;
NXRect aFrame;
if ([sender draggingSourceOperationMask] == NX_DragOperationNone)
return NX_DragOperationNone;
newLoc = [self viewLocationForContext:sender];
if (!gridEnabled)
return NX_DragOperationLink;
/*
* If the icon was dragged off the edge, hide it somewhere!
*/
mouseLoc = [sender draggingLocation];
if ([self isDeadZone:&mouseLoc]) {
newLoc.x = -100;
newLoc.y = -100;
}
if (gridEnabled) {
[draggedView getFrame:&aFrame];
if (aFrame.origin.x != newLoc.x || aFrame.origin.y != newLoc.y) {
[draggedView moveTo:newLoc.x :newLoc.y];
[self display:&aFrame :1 :NO]; /* erase old */
aFrame.origin = newLoc;
[self display:&aFrame :1 :NO]; /* draw new */
}
}
return NX_DragOperationLink;
}
/*
* Get rid of the resources we used to drag the image around.
*/
- draggingExited:(id <NXDraggingInfo>)sender
{
if ([sender draggingSourceOperationMask] == NX_DragOperationNone)
return NX_DragOperationNone;
if (gridEnabled)
[self removeView:draggedView];
[draggedView free];
return self;
}
/*
* Eat the result...
*/
- (BOOL) prepareForDragOperation:sender
{
return YES;
}
- (BOOL) performDragOperation:sender
{
NXPoint mouseLoc;
NXPoint newLoc;
/*
* If the dragged item landed in the dead zone, get rid of it.
* Don't accept drag.
*/
newLoc = [self viewLocationForContext:sender];
mouseLoc = [sender draggingLocation];
if ([self isDeadZone:&mouseLoc]) {
[self removeView:draggedView];
[draggedView free];
draggedView = nil;
return NO;
}
[draggedView moveTo:newLoc.x :newLoc.y];
return YES;
}
- selectViewsInRect:(NXRect *)theRect deselect:(BOOL)flag
{
id theView;
int i;
NXRect viewRect;
NXPoint thePoint;
int count = [subviews count];
BOOL found = NO;
[window disableFlushWindow];
for(i = 0; i < count; i++) {
theView = [subviews objectAt:i];
if (theView == nil)
continue;
[theView getFrame:&viewRect];
thePoint.x = NX_MIDX(&viewRect);
thePoint.y = NX_MIDY(&viewRect);
if (NXIntersectsRect(&viewRect, theRect)) {
if (!flag)
[theView setState:![theView state]];
else
[theView setState:YES];
found = YES;
}
else if (flag)
[theView setState:NO];
}
[[window reenableFlushWindow] flushWindow];
if (found)
[NXApp unhide:self];
return self;
}
- nukeViewsInRect:(NXRect *)theRect
{
id theView;
int i;
NXRect viewRect;
NXPoint thePoint;
int count = [subviews count];
id killList = [[List alloc] init];
BOOL useSound = !strcmp(NXGetDefaultValue([NXApp appName], USE_SOUND), "YES");
for(i = 0; i < count; i++) {
theView = [subviews objectAt:i];
if (theView == nil)
continue;
[theView getFrame:&viewRect];
thePoint.x = NX_MIDX(&viewRect);
thePoint.y = NX_MIDY(&viewRect);
if (NXIntersectsRect(&viewRect, theRect))
[killList addObject:theView];
}
count = [killList count];
for(i = 0; i < count; i++)
[self deleteView:[killList objectAt:i]];
[killList free];
if (useSound)
[[Sound findSoundFor:"Destroy"] play];
[self writeShelf];
return self;
}
- mouseDown:(NXEvent *)event
{
BOOL alt;
BOOL ctrl;
BOOL shift;
BOOL command;
NXRect theRect;
NXPoint p;
NXPoint origPt;
BOOL started = NO;
int mask = NX_MOUSEDRAGGEDMASK|NX_MOUSEUPMASK;
alt = (event->flags & NX_ALTERNATEMASK) ? YES : NO;
ctrl = (event->flags & NX_CONTROLMASK) ? YES : NO;
shift = (event->flags & NX_SHIFTMASK) ? YES : NO;
command = (event->flags & NX_COMMANDMASK) ? YES : NO;
origPt = event->location;
[window convertBaseToScreen:&origPt];
if (event->data.mouse.click == 2) {
[NXApp unhide:self];
return self;
}
[window addToEventMask:NX_MOUSEDRAGGEDMASK];
do {
if (!started) {
[self lockFocus];
PSsetgray(NX_BLACK);
PSsetinstance(YES);
started = YES;
}
p = event->location;
NX_X(&theRect) = (origPt.x < p.x) ? origPt.x : p.x;
NX_Y(&theRect) = (origPt.y < p.y) ? origPt.y : p.y;
NX_WIDTH(&theRect) = fabs(origPt.x - p.x);
NX_HEIGHT(&theRect) = fabs(origPt.y - p.y);
PSnewinstance();
NXFrameRect(&theRect);
event = [NXApp getNextEvent:mask];
} while (event && event->type != NX_MOUSEUP);
if (started) {
PSnewinstance();
PSsetinstance(NO);
[self unlockFocus];
PSsetgray(NX_BLACK);
if (alt)
[self nukeViewsInRect:&theRect];
else {
[[NXApp delegate] deselectDock];
[self selectViewsInRect:&theRect deselect:!shift];
}
}
return self;
}
/*
* Actually write the stuff way down here. It's completely at the end
* of the operation, so a slow write won't hose the UI.
*/
- concludeDragOperation:(id <NXDraggingInfo>)sender
{
int len;
int horizLimit;
int horizCount;
char *ptr;
char *path;
char *dragString;
NXRect newFrame;
NXRect viewFrame;
NXPoint newPoint;
BOOL useSound = !strcmp(NXGetDefaultValue([NXApp appName], USE_SOUND), "YES");
[draggedView getFrame:&viewFrame];
newFrame = viewFrame;
newPoint = viewFrame.origin;
[draggedView getData:(void **)&dragString andLength:&len];
horizCount = 0;
horizLimit = 1000;
if ([sender draggingSourceOperationMask] & NX_DragOperationLink) {
horizLimit = 0;
ptr = dragString;
while(*ptr) {
if (*ptr == '\t')
horizLimit++;
ptr++;
}
horizLimit = (int)sqrt((float)horizLimit);
}
path = strtok(dragString, "\t");
while(path && strlen(path)) {
while([self isAnyViewAt:newPoint besides:draggedView]) {
if (newPoint.x >= gridValue && horizCount < horizLimit) {
newPoint.x -= gridValue;
horizCount++;
}
else {
horizCount = 0;
newPoint.x = NX_X(&viewFrame);
if (newPoint.y >= gridValue && newPoint.y <= NX_Y(&viewFrame))
newPoint.y -= gridValue;
else if (newPoint.y >= gridValue)
newPoint.y += gridValue;
else
newPoint.y = NX_Y(&viewFrame) + gridValue;
}
}
newFrame.origin = newPoint;
[self createViewForPath:path at:&newFrame.origin];
NXPing();
path = strtok(NULL, "\t");
}
if (useSound && ![sender isDraggingSourceLocal])
[[Sound findSoundFor:"Fiend"] play];
if (draggedView != nil) {
[self removeView:draggedView];
[draggedView free];
}
[self writeShelf];
return self;
}
/*
* Be a drag source, too
*/
- setDragView:aView onEvent:(NXEvent *) e withOffset:(NXPoint *) offset
atLocation:(const NXPoint *) location
{
id pb = [Pasteboard newName:NXDragPboard];
void *data;
unsigned int length;
NXPoint myLoc;
/*
* Initiate a drag operation. Copy stuff into the pasteboard,
* then start dragging. To simplify matters elsewhere, we try
* to make a local dragging operation look just like a non-local
* one.
*/
dragSourceView = aView;
keepSourceOnShelf = (e->flags & NX_SHIFTMASK) ? YES : NO;
[aView getData:&data andLength:&length];
[pb declareTypes:&NXFilenamePboardType num:1 owner:nil];
[pb writeType:NXFilenamePboardType data:data length:length];
myLoc = *location;
[aView convertPoint:&myLoc toView:self];
[self dragImage:[aView image] at:&myLoc
offset:offset event:e pasteboard:pb
source:self slideBack:YES];
return self;
}
- draggedImage:(NXImage *)image beganAt:(NXPoint *)screenPoint
{
NXRect theFrame;
[dragSourceView getFrame:&theFrame];
[self display:&theFrame :1 :NO];
if (!keepSourceOnShelf)
[self removeView:dragSourceView];
return self;
}
/*
* A drag operation, with us as the source, finished. If it was an
* unsuccessful drag then, put the source back! If it was a successful
* drag, and we weren't the destination, then remove the thing from the
* shelf.
*/
- draggedImage:(NXImage *)image endedAt:(NXPoint *)screenPoint
deposited:(BOOL)didDeposit
{
char *path;
unsigned int len;
struct stat st;
/*
* Check to see if we should keep the source dir on the shelf. We
* do this if the keepSourceOnShelf flag is set, and if the file
* under the icon still exists.
*/
[dragSourceView getData:(void **) &path andLength:&len];
if (keepSourceOnShelf && path && stat(path, &st) == 0) {
keepSourceOnShelf = NO;
return self;
}
/*
* The source isn't on the screen, so either get rid of the source, or
* put it back.
*/
if (didDeposit)
[self deleteView:dragSourceView];
else
[self addView:dragSourceView];
return self;
}
- (NXDragOperation) draggingSourceOperationMaskForLocal:(BOOL)flag
{
return NX_DragOperationAll;
}
- (BOOL)hasSelectedCells
{
int i;
int count = [subviews count];
for(i = 0; i < count; i++) {
if ([[subviews objectAt:i] state])
return YES;
}
return NO;
}
- copy:sender andCut:(BOOL)cutFlag
{
id aView;
int i;
int junk;
char *viewPath;
char cutString[10000];
int count = [subviews count];
id pb = [Pasteboard newName:NXGeneralPboard];
id cutList = [[List alloc] init];
const char *types[] = {NXFilenamePboardType, NXAsciiPboardType};
BOOL useSound = !strcmp(NXGetDefaultValue([NXApp appName], USE_SOUND), "YES");
*cutString = '\0';
for(i = 0; i < count; i++) {
aView = [subviews objectAt:i];
if ([aView state]) {
[aView getData:(void **)&viewPath andLength:&junk];
strcat(cutString, viewPath);
strcat(cutString, "\t");
[cutList addObject:aView];
}
}
cutString[strlen(cutString)-1] = '\0';
[pb declareTypes:types num:2 owner:nil];
[pb writeType:NXFilenamePboardType data:cutString length:strlen(cutString)];
for(i = 0; i < strlen(cutString); i++) {
if (cutString[i] == '\t')
cutString[i] = '\n';
}
strcat(cutString, "\n");
[pb writeType:NXAsciiPboardType data:cutString length:strlen(cutString)];
if (cutFlag) {
if (useSound)
[[Sound findSoundFor:"Destroy"] play];
count = [cutList count];
for(i = 0; i < count; i++)
[self deleteView:[cutList objectAt:i]];
}
[cutList free];
[self writeShelf];
return self;
}
- paste:sender
{
int len;
int horizLimit;
int horizCount;
char *ptr;
char *path;
char *dragString;
BOOL ctrl;
NXRect newFrame;
NXEvent *event;
NXPoint newPoint;
NXPoint locus;
id pb = [Pasteboard newName:NXGeneralPboard];
NXRect viewFrame = {{0.0, 0.0}, {gridValue, gridValue}};
BOOL useSound = !strcmp(NXGetDefaultValue([NXApp appName], USE_SOUND), "YES");
[pb readType:NXFilenamePboardType data:&dragString length:&len];
if (!len)
return self;
[NXIBeam push];
do {
event = [NXApp getNextEvent:NX_MOUSEDOWNMASK|NX_MOUSEDRAGGEDMASK];
} while (event && event->type != NX_MOUSEDOWN);
ctrl = (event->flags & NX_CONTROLMASK) ? YES : NO;
[NXIBeam pop];
locus = event->location;
locus.x = locus.x - (int)locus.x % gridValue;
locus.y = locus.y - (int)locus.y % gridValue;
newPoint = locus;
viewFrame.origin = locus;
newFrame = viewFrame;
horizCount = 0;
horizLimit = 10000;
if (len && !ctrl) {
horizLimit = 0;
ptr = dragString;
while(*ptr) {
if (*ptr == '\t')
horizLimit++;
ptr++;
}
horizLimit = (int)sqrt((float)horizLimit);
}
[window disableFlushWindow];
path = strtok(dragString, "\t");
while(path && strlen(path)) {
while([self isAnyViewAt:newPoint besides:nil]) {
if (newPoint.x >= gridValue && horizCount < horizLimit) {
newPoint.x -= gridValue;
horizCount++;
}
else {
horizCount = 0;
newPoint.x = NX_X(&viewFrame);
if (newPoint.y >= gridValue && newPoint.y <= NX_Y(&viewFrame))
newPoint.y -= gridValue;
else if (newPoint.y >= gridValue)
newPoint.y += gridValue;
else
newPoint.y = NX_Y(&viewFrame) + gridValue;
}
}
newFrame.origin = newPoint;
[self createViewForPath:path at:&newFrame.origin];
NXPing();
path = strtok(NULL, "\t");
}
[[window reenableFlushWindow] flushWindow];
if (useSound)
[[Sound findSoundFor:"Fiend"] play];
[pb deallocatePasteboardData:dragString length:len];
return self;
}
/*
* Open the shelf file.
*/
- (FILE *) openShelfFor:(char *) how
{
char path[MAXPATHLEN];
sprintf(path, "%s/%s", NXHomeDirectory(), FIENDSHELF_FILE);
return fopen(path, how);
}
/*
* Close it.
*/
- closeShelf:(FILE *) file
{
fclose(file);
return self;
}
/*
* Read the contents of the shelf in from a file. The file's format consists
* of lines of the form:
*
* x y path
*
* where the two numbers x,y specify the origin of the particular view on the
* shelf, and path specifies the path to the workspace. Somewhat bogusly,
* we assume the path starts at character 14.
*/
- readShelf:(BOOL)showProgress
{
float i;
float count;
FILE *file;
char line[MAXPATHLEN + 30];
char *path;
NXPoint point;
file = [self openShelfFor:"r"];
if (file == NULL)
return self;
count = 0.0;
if (showProgress) {
while(fgets(line, sizeof(line), file))
count++;
rewind(file);
[[NXApp delegate] setProgressViewRatio:0.0];
}
i = 1.0;
while (fgets(line, sizeof(line), file)) {
if (showProgress)
[[NXApp delegate] setProgressViewRatio:0.9*i++/count];
/*
* Parse the line in the shelf. It's too bad that we can't use
* sscanf to parse the whole line!
*/
sscanf(line, "%f %f", &point.x, &point.y);
/* file string starts after second number, char 14 */
if (strlen(line) > 14) {
path = line + 14;
if (rindex(path, '\n') != NULL)
*rindex(path, '\n') = '\0';
}
else
continue;
/*
* Make a spot for this guy...
*/
[self createViewForPath:path at:&point];
}
[self closeShelf:file];
return self;
}
/*
* Write the contents of the shelf out to the shelf file.
*/
- writeShelf
{
FILE *file;
NXRect rect;
int i;
file = [self openShelfFor:"w"];
if (file == NULL)
return self;
for (i = 0; i < [[self subviews] count]; i++) {
id view = [[self subviews] objectAt:i];
unsigned int length;
char *path;
if (![view isKindOf:[IconView class]] || [view isOnRemovableMedia])
continue;
[view getData:(void **) &path andLength:&length];
[view getFrame:&rect];
fprintf(file, "%6.0f %6.0f %s\n", rect.origin.x, rect.origin.y, path);
}
[self closeShelf:file];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.