This is IconWell.m in view mode; [Download] [Up]
// IconWell.m // // Free software created 1 Feb 1992 // by Paul Burchard <burchard@math.utah.edu>. #import "IconWell.h" #import "IconWellControl.h" #import <appkit/appkit.h> #import <objc/Storage.h> @implementation IconWell static id windowList; static id wellsByWindow; + initialize { if(self == [IconWell class]) { windowList = [[List alloc] initCount:0]; wellsByWindow = [[List alloc] initCount:0]; } return self; } + wellListFor:aWindow { int index; index = [windowList indexOf:aWindow]; if(index == NX_NOT_IN_LIST) return nil; return [wellsByWindow objectAt:index]; } - initFrame:(const NXRect *)frameRect { id theCell; [super initFrame:frameRect]; theCell = [[ActionCell alloc] initIconCell:blankIconName]; [theCell setBezeled:YES]; [self setCell:theCell]; iconPath = [[Storage alloc] initCount:0 elementSize:sizeof(char) description:"c"]; sprintf((char *)iconName, "IconWell-%ld", (long)[self self]); isHoldOnDrag = YES; [self setDraggable:YES droppable:YES]; return self; } - free { int index; id list; [iconPath free]; if(list = [IconWell wellListFor:window]) { [list removeObject:self]; if([list count] <= 0) { index = [wellsByWindow indexOf:list]; [wellsByWindow removeObjectAt:index]; [windowList removeObjectAt:index]; [list free]; } } return [super free]; } - windowChanged:newWindow { id list; // Enter new well into global list. if(window || !newWindow) return nil;//!!! if(!(list = [IconWell wellListFor:newWindow])) { list = [[List alloc] initCount:0]; [windowList addObject:newWindow]; [wellsByWindow addObject:list]; } [list addObjectIfAbsent:self]; return self; } - setBezeled:(BOOL)flag { return [cell setBezeled:flag]; } - (BOOL)isBezeled { return [cell isBezeled]; } - setBordered:(BOOL)flag { return [cell setBordered:flag]; } - (BOOL)isBordered { return [cell isBordered]; } - setDraggable:(BOOL)dragFlag droppable:(BOOL)dropFlag { isDraggable = dragFlag; isDroppable = dropFlag; return self; } - (BOOL)isDraggable { return isDraggable; } - (BOOL)isDroppable { return isDroppable; } - setHoldOnDrag:(BOOL)flag { if(isDragging) return nil; isHoldOnDrag = flag; return self; } - (BOOL)isHoldOnDrag { return isHoldOnDrag; } - clear:sender { // This does not de-alloc Blank.tiff since it was not renamed. // This only affects this IconWell because of the unique iconName. [cell setIcon:blankIconName]; [self update]; //!!! make sure image really replaced before freeing [[NXImage findImageNamed:(const char *)iconName] free]; [iconPath setNumSlots:0]; return self; } - (const char *)stringValue { if([iconPath count] <= 0) return 0; return (const char *)[iconPath elementAt:0]; } - getTiffForPath:(const char *)pathString { int ok, length; char *tiff, *fakePath, *q; const char *p; NXStream *imageStream; id iconImage; // Ask WorkSpace for correct TIFF corresponding to path list pathString. // Since ``full paths'' are required, prepend '/' to each name if missing. if(!pathString) return nil; if(!(fakePath = (char *)malloc((strlen(pathString)+1)*sizeof(char)))) return nil; for(p=pathString, q=fakePath; *p; p++) { if(p==pathString && *p!='/') *q++ = '/'; *q++ = *p; if(*p=='\t' && *(p+1)!='/') *q++ = '/'; } *q = 0; [[NXApp appSpeaker] setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)]; [[NXApp appSpeaker] getFileIconFor:fakePath TIFF:&tiff TIFFLength:&length ok:&ok]; free(fakePath); // If no icon, use generic ".txt" icon. if(!ok) { [[NXApp appSpeaker] setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)]; [[NXApp appSpeaker] getFileIconFor:"/file.txt" TIFF:&tiff TIFFLength:&length ok:&ok]; if(!ok) return nil; } // Create NXImage from TIFF data. imageStream = NXOpenMemory(tiff, length, NX_READONLY); if(!imageStream) return nil; iconImage = [[NXImage alloc] initFromStream:imageStream]; NXClose(imageStream); return iconImage; } - setStringValue:(const char *)aString { id iconImage; // If path is NULL, clear well. if(!aString) [self clear:self]; // Ask WorkSpace for correct TIFF corresponding to path aString. if(!(iconImage = [self getTiffForPath:aString])) return nil; // Enter NXImage into cell, freeing previous image. // (Note: Common blank image is not freed as it was never renamed.) [cell setIcon:blankIconName]; [self update]; //!!! make sure image really replaced before freeing [[NXImage findImageNamed:(const char *)iconName] free]; [iconImage setName:(const char *)iconName]; [cell setIcon:(const char *)iconName]; // Enter new path into iconPath, notify target. [iconPath setNumSlots:(strlen(aString)+1)]; strcpy((char *)[iconPath elementAt:0], aString); [self sendAction:[cell action] to:[cell target]]; return self; } - takeStringValueFrom:sender { id oldTarget = nil; id rtn; // If sender is target, don't send action (to avoid circularity). if(sender == [self target]) { oldTarget = [self target]; [self setTarget:nil]; } rtn = [self setStringValue:[sender stringValue]]; if(oldTarget) [self setTarget:oldTarget]; return rtn; } - (BOOL)acceptsFirstMouse { return YES; } - (int)openFile:(const char *)fullPath ok:(int *)flag { int rtn; // Ask WorkSpace to open the file. No fudging paths now. [[NXApp appSpeaker] setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)]; rtn = [[NXApp appSpeaker] openFile:fullPath ok:flag]; if(rtn != 0) return(rtn); return 0; } - (int)prepFile:(const char *)fullPath ok:(int *)flag { // Default is no prep needed on drag-out. return 0; } - setDelegate:anObject { delegate = anObject; return self; } - delegate { return delegate; } - mouseDown:(NXEvent *)theEvent { int ok; char *fileName, *nxt; NXPoint mousePoint; NXRect iconRect; id success, handler; if(theEvent->data.mouse.click < 2) { // Single click means drag icon out. // Check if mouse actually clicked on icon. mousePoint = theEvent->location; [super convertPoint:&mousePoint fromView:nil]; [self getBounds:&iconRect]; [cell getIconRect:&iconRect]; NX_WIDTH(&iconRect) = NX_HEIGHT(&iconRect) = 48.0; if(!NXMouseInRect(&mousePoint, &iconRect, [self isFlipped])) return self; // Don't actually start the drag until mouse gets dragged a bit. if(isDraggable) { isDragging = YES; [window addToEventMask:NX_LMOUSEDRAGGEDMASK]; dragFromEvent = *theEvent; } return self; } else if(theEvent->data.mouse.click == 2) { // Double-click means open file(s). // Delegate this task if possible. if([delegate respondsTo:@selector(openFile:ok:)]) handler = delegate; else handler = self; // Open files one by one. if([iconPath count] <= 0) return nil; fileName = (char *)[iconPath elementAt:0]; nxt = strchr(fileName, '\t'); success = self; while(fileName) { if(nxt) *nxt = 0; [handler openFile:fileName ok:&ok]; if(!ok) success = nil; if(nxt) { *nxt = '\t'; fileName = nxt+1; nxt = strchr(fileName, '\t'); } else fileName = nxt = 0; } return success; } else { // Ignore higher multi-clicks. return self; } } - mouseDragged:(NXEvent *)theEvent { NXRect iconRect; int ok; char *fileName, *nxt; id success, handler; // Check if valid drag. if(!(isDragging && isDraggable && [cell icon] && [iconPath count]>0)) { isDragging = NO; return self; } // Prep file(s) for drag; delegate this task if possible. if([delegate respondsTo:@selector(prepFile:ok:)]) handler = delegate; else handler = self; if([iconPath count] <= 0) return nil; fileName = (char *)[iconPath elementAt:0]; nxt = strchr(fileName, '\t'); success = self; while(fileName) { if(nxt) *nxt = 0; [handler prepFile:fileName ok:&ok]; if(!ok) success = nil; if(nxt) { *nxt = '\t'; fileName = nxt+1; nxt = strchr(fileName, '\t'); } else fileName = nxt = 0; } if(!success) { isDragging = NO; return success; } // Try to drag icon out. [self getBounds:&iconRect]; [cell getIconRect:&iconRect]; NX_WIDTH(&iconRect) = NX_HEIGHT(&iconRect) = 48.0; success = [super dragFile:(const char *)[iconPath elementAt:0] fromRect:&iconRect slideBack:YES event:&dragFromEvent]; isDragging = NO; // Take care of no-hold-on-drag. if(!isHoldOnDrag) { // Successful drag: clear path and icon to initial state. if(success) [self clear:self]; // Unsuccessful drag: redisplay old icon in case it left. else [cell setIcon:(const char *)iconName]; } return success; } - mouseUp:(NXEvent *)theEvent { isDragging = NO; return self; } - (BOOL)isScreenPointInView:(double)x :(double)y { NXPoint point; NXRect rect; // If (x,y) is not in this IconWell, try next one in chain. point.x = x; point.y = y; [window convertScreenToBase:&point]; [self convertPoint:&point fromView:nil]; [self getBounds:&rect]; if(NXMouseInRect(&point, &rect, [self isFlipped])) return YES; else return NO; } - (int)iconEntered:(int)windowNum at:(double)x :(double)y iconWindow:(int)iconWindowNum iconX:(double)iconX iconY:(double)iconY iconWidth:(double)iconWidth iconHeight:(double)iconHeight pathList:(char *)pathList { // Temporarily display new image if (x,y) is in this IconWell. if(!isDroppable || ![self isScreenPointInView:x :y]) { isDropping = NO; return 0; } [cell setIcon:blankIconName]; [cell setIcon:newIconName]; isDropping = YES; return 0; } - (int)iconMovedTo:(double)x :(double)y { // Check if (x,y) moved in or out of this IconWell. if(!isDroppable) return 0; else if(![self isScreenPointInView:x :y]) { if(!isDropping) return 0; // Mouse left; restore old image (unless no-hold-on-drag thing). [cell setIcon:blankIconName]; if(!isDragging || isHoldOnDrag) [cell setIcon:(const char *)iconName]; isDropping = NO; return 0; } else if(!isDropping) { // Mouse entered; display new image. [cell setIcon:blankIconName]; [cell setIcon:newIconName]; isDropping = YES; return 0; } return 0; } - (int)iconExitedAt:(double)x :(double)y { if(!isDroppable || !isDropping) return 0; // Mouse left; restore old image (unless no-hold-on-drag thing). [cell setIcon:blankIconName]; if(!isDragging || isHoldOnDrag) [cell setIcon:(const char *)iconName]; isDropping = NO; return 0; } - (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag { const char *path; // Check if (x,y) moved in or out of this IconWell. *flag = 0; if(!isDroppable) return 0; else if(![self isScreenPointInView:x :y] || !(path = [[IconWellControl controlFor:window] newIconPath])) { if(!isDropping) return 0; // Mouse left; restore old image (unless no-hold-on-drag thing). [cell setIcon:blankIconName]; if(!isDragging || isHoldOnDrag) [cell setIcon:(const char *)iconName]; isDropping = NO; return 0; } else if(!isDropping) { // Mouse entered; display new image. [cell setIcon:blankIconName]; [cell setIcon:newIconName]; } // Replace path and icon with new ones; notify target. [iconPath setNumSlots:(strlen(path)+1)]; strcpy((char *)[iconPath elementAt:0], path); [cell setIcon:blankIconName]; [self update]; //!!! make sure image really replaced before freeing [[NXImage findImageNamed:(const char *)iconName] free]; [[NXImage findImageNamed:newIconName] setName:(const char *)iconName]; [cell setIcon:(const char *)iconName]; [self sendAction:[cell action] to:[cell target]]; // Accept icon and end drop. isDropping = NO; *flag = 1; return 0; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.