This is HGraphicView.m in view mode; [Download] [Up]
/* Hippo Graphic View by Paul Kunz June 1991 * a subclass of GraphicView in /NextDeveloper/Examples/Draw * to add or over-ride so that it can handle hippo Graphic objects * * Copyright (C) 1991 The Board of Trustees of * The Leland Stanford Junior University. All Rights Reserved. */ #import "Draw.subproj/draw.h" #import "hippo.h" #import "HGraphicView.h" const char HGraphicView_h_rcsid[] = HGRAPHICVIEW_H_ID; const char HGraphicView_m_rcsid[] = "$Id: HGraphicView.m,v 2.47.2.3 1994/02/08 20:28:51 rensing Exp $"; #import "HDrawApp.h" #import "HTuple.h" #import "InspectCut.h" #import "InspectPlot.h" #import "InspectTuple.h" #import "NewInspector.h" #import "Plot.h" #import "Overlay.h" #import "PageMarker.h" #import "SaveWindow.h" #define DIRTY(condition) \ if (condition && !gvFlags.dirty) { \ gvFlags.dirty = YES; \ [window setDocEdited:YES]; \ } @interface HGraphicView(PrivateMethods) - placeGraphic:graphic at:(const NXPoint *)location; /* * Places the graphic centered at the given location on the page. * If the graphic is too big, the user is asked whether the graphic * should be scaled. */ - tupleList; /* * Returns a List object containing the HTuple objects needed * for the Plots in the View. */ @end #define DEFAULTCOLS "2" #define DEFAULTROWS "3" #define CURRENT_VERSION FIP_ARCHIVE_FIX @implementation HGraphicView : GraphicView + initialize { static NXDefaultsVector HippoDrawDefaults = { { "NumPlotCols", DEFAULTCOLS }, { "NumPlotRows", DEFAULTROWS }, { NULL, NULL } }; /* WARNING: GraphicView also has dependency on class version, * see its -read: method. Watch out of future releases of * that class, in case they conflict with our version numbering. */ [self setVersion:CURRENT_VERSION]; NXRegisterDefaults("HippoDraw", HippoDrawDefaults); return self; } + convert:(NXTypedStream *)ts to:(const char *)type using:(SEL)writer toPasteboard:pb /* * Over ride this method in order to make scrapper a HGraphicView */ { id w, list; NXZone *zone; NXStream *stream; HGraphicView *scrapper; NXRect scrapperFrame = {{0.0, 0.0}, {11.0*72.0, 14.0*72.0}}; if (!ts) return self; zone = NXCreateZone(vm_page_size, vm_page_size, NO); NXNameZone(zone, "Scrapper"); scrapper = [[HGraphicView allocFromZone:zone] initFrame:&scrapperFrame]; NXSetTypedStreamZone(ts, zone); list = NXReadObject(ts); [scrapper getBBox:&scrapperFrame of:list]; scrapperFrame.size.width += scrapperFrame.origin.x; scrapperFrame.size.height += scrapperFrame.origin.y; scrapperFrame.origin.x = scrapperFrame.origin.y = 0.0; [scrapper sizeTo:scrapperFrame.size.width :scrapperFrame.size.height]; w = [[Window allocFromZone:zone] initContent:&scrapperFrame style:NX_PLAINSTYLE backing:NX_NONRETAINED buttonMask:0 defer:NO]; [w reenableDisplay]; [w setContentView:scrapper]; stream = NXOpenMemory(NULL, 0, NX_WRITEONLY); [scrapper perform:writer with:(id)stream with:list]; [pb writeType:type fromStream:stream]; [list freeObjects]; [list free]; NXCloseMemory(stream, NX_FREEBUFFER); [w free]; NXDestroyZone(zone); return self; } - initFrame:(const NXRect *)frameRect { [super initFrame:frameRect]; rotateCursor = NULL; hippoDraw = NXGetNamedObject("HDrawInstance", NXApp); return self; } - (BOOL)validateCommand:menuCell { id g; SEL action; unsigned int i, scount, pcount; BOOL retval; retval = [super validateCommand:menuCell]; if ( retval == NO ) { return NO; } action = [menuCell action]; scount = [slist count]; if ( action == @selector(duplicate:) && scount == 0) { return NO; } else if ( action == @selector(overlay:) || action == @selector(alignXRange:) || action == @selector(alignXNumBins:) || action == @selector(alignYRange:) || action == @selector(alignYNumBins:) ) { if ( scount == 0 ) return NO; pcount = 0; for ( i = 0; i < scount && pcount < 2; i ++ ) { g = [slist objectAt:i]; if ( [g isKindOf:[Plot class]] ) { pcount++; } } if ( pcount < 2 ) { return NO; } } else if ( action == @selector(unoverlay:) ) { if ( scount == 0 ) return NO; for ( i = 0; i < scount; i++ ) { g = [slist objectAt:i]; if ( [g isKindOf:[Overlay class]] ) { return YES; } } return NO; } else if ( action == @selector(saveWindowTo:) ) { for ( i = 0; i < scount; i++ ) { g = [slist objectAt:i]; if ( [g isKindOf:[SaveWindow class]] ) { return YES; } } return NO; } return YES; } - addPages:(int) n { NXRect box; int i, j=n; id g; [[[self window] delegate] getPageFrame:&box]; while (j--) { /* * add a page marker * it is inserted at the very top of the document. */ [self notifyAncestorWhenFrameChanged:YES]; [[[PageMarker allocFromZone:[self zone]] init] addSelf: self]; /* * extend the document */ [ self sizeBy: 0.0 : box.size.height ]; } /* * the pages got added at the top, so move everything up */ box.size.width = 0.0; box.size.height *= n; i = [glist count]; while(i--) { g = [glist objectAt:i]; if (![g isKindOf:[PageMarker class]]) [g moveBy: (const NXPoint *) &box.size]; } [self getFrame:&box ]; [self cache:&box ]; [window flushWindow]; return self; } - (BOOL) hasCutsSelected { id g; int i; i = [slist count]; while (i-- ) { g = [slist objectAt:i]; if ( [g isKindOf:[Plot class]] ) { if ( [g isCutPlot] ) { if ( [g dependCount] ) { return YES; } } if ( [g hasCut] ) { return YES; } } } return NO; } - addPlotOfType:(graphtype_t) type { InspectTuple *inspector; Plot *plot; inspector = [hippoDraw inspectTuple]; [inspector load:self]; plot = [inspector addPlotOfType:type]; [self addPlot:plot andSelect:YES]; return plot; } - addPlot:plot andSelect:(BOOL) selFlag { id theInspector; NXRect bbox; NXPoint location; if ( selFlag ) { [ self deselectAll:self]; } [[[drawInstance inspectorPanel] delegate] initializeGraphic:plot]; [self calcDefaultPlotSize:&bbox]; [self calcPlacement: &(bbox.size) result: &location]; bbox.origin.x = location.x; bbox.origin.y = location.y; [ plot setBounds: &bbox ]; /* * add to cutplot list if needed */ if ([plot isCutPlot]) { /* using the method causes it to be initialized */ [[self cutList] addObject:plot]; } [plot setGraphicView: self]; if (selFlag) { [ self insertGraphic: plot]; } else { [ self insertGraphicNoSelect: plot]; [self recacheSelection]; } [self scrollRectToVisible: &bbox]; [window makeKeyWindow]; if ( selFlag ) { [NXApp updateWindows]; theInspector = [hippoDraw newInspector]; [theInspector orderFrontPanel:self]; } [self dirty]; return self; } - hTupleForFile:(const char *)filename index:(int) iValue { id inspectTuple; inspectTuple = [hippoDraw inspectTuple]; return [inspectTuple hTupleForFile:filename index:iValue]; } /* - addCut:plot { id inspectCut; inspectCut = [hippoDraw inspectCut]; [inspectCut addCut:plot]; return self; } */ - cutList { if ( !cutList ) { cutList = [[List allocFromZone:[self zone]] initCount:0]; } return cutList; } - plotList { volatile id plotList = nil; if ( !plotList ) { plotList = [[List allocFromZone:[self zone]] initCount:0]; } else { [plotList empty]; } [glist makeObjectsPerform:@selector(addPlotToList:) with:plotList]; return plotList; } - (display *) displayList; { List *plotList; Plot *g; static display *dispList = NULL; int i, count, num_disp; plotList = [self plotList]; count = [plotList count]; if ( dispList != NULL ) { NX_ZONEREALLOC( [self zone], dispList, display, count+1 ); } else { NX_ZONEMALLOC( [self zone], dispList, display, count+1 ); } num_disp = 0; for ( i = 0; i < count; i ++ ) { g = [plotList objectAt:i]; dispList[num_disp++] = [g histDisplay]; } dispList[num_disp] = NULL; return dispList; } - firstPlot { id g; if ([slist count] == 1) { g = [slist objectAt:0]; if ( [g isKindOf:[Overlay class]] ) { return [g firstPlot]; } if ( [ g isKindOf:[Plot class]] ) { return g; } } return nil; } - reDrawPlot { [self selectAll:self]; [self deselectAll:self]; [window flushWindow]; return self; } #define stopTimer(timer) if (timer) { \ NXEndTimer(timer); \ timer = NULL; \ } #define startTimer(timer) if (!timer) timer = NXBeginTimer(NULL, 0.1, 0.1); #define MOVE_MASK NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK - (BOOL)move:(NXEvent *)event /* * Moves the selection by cacheing the selected graphics into the * selection cache, then compositing them repeatedly as the user * moves the mouse. The tracking loop uses TIMER events to autoscroll * at regular intervals. TIMER events do not have valid mouse coordinates, * so the last coordinates are saved and restore when there is a TIMER event. */ { NXEvent peek; NXCoord dx, dy; NXPoint p, last; BOOL tracking = YES,command; NXPoint mine; command = (event->flags & NX_COMMANDMASK) ? YES : NO; if (!command) command = (event->flags & NX_CONTROLMASK) ? YES : NO; if (command == NO) return [super move:event]; /* change cursor */ if (!rotateCursor) rotateCursor = [[NXCursor alloc] initFromImage: [NXImage findImageNamed:"rotCursor"]]; [rotateCursor push]; last = event->location; event = [NXApp getNextEvent:MOVE_MASK]; if (event->type == NX_MOUSEUP) return NO; [self convertPoint:&last fromView:nil]; [self lockFocus]; while (tracking) { p = event->location; [self convertPoint:&p fromView:nil]; dx = p.x - last.x; dy = p.y - last.y; mine.x= dx; mine.y = dy; /***** if (dx || dy) { *****/ /***** Even though we are doing an extra draw for the case MOUSEUP, where * dx and dy are zero, we need to pass-on the mouseup to 3D drawing. The * threeD drawing sets a 'speedy flag' during mouse dragging, and we * need the mouseup to turn the speedy flag off and resume full drawing. *****/ [self graphicsPerform:@selector(mouseMoved:withKey:) with:(id)&mine with:(id)&(event->flags) andDraw:YES]; [window flushWindow]; last = p; /***** } *****/ tracking = (event->type != NX_MOUSEUP); if (tracking) { p = event->location; if (![NXApp peekNextEvent:MOVE_MASK into:&peek]) { event = [NXApp getNextEvent:MOVE_MASK|NX_TIMERMASK]; } else { event = [NXApp getNextEvent:MOVE_MASK]; } if (event->type == NX_TIMER) { event->location = p; } } } [rotateCursor pop]; [window flushWindow]; [self unlockFocus]; return YES; } - graphicsPerformNOP: g { NXRect affectedBounds; [g getExtendedBounds:&affectedBounds]; [self cache:&affectedBounds]; return self; } - graphicsPerform:(SEL)aSelector with:(void *)argument andDraw:(BOOL)flag inList:aList { id savesList; savesList = slist; slist = aList; [self graphicsPerform:aSelector with:argument andDraw:flag]; slist = savesList; [self dirty]; return self; } - graphicsPerform:(SEL)aSelector with:(void *)argument1 with:(void *)argument2 andDraw:(BOOL)flag { id g; int i, count; NXRect eb, affectedBounds; if (flag) { count = [slist count]; if (count) { [[slist objectAt:0] getExtendedBounds:&affectedBounds]; for (i = 1; i < count; i++) { g = [slist objectAt:i]; NXUnionRect([g getExtendedBounds:&eb], &affectedBounds); } for (i = 0; i < count; i++) { g = [slist objectAt:i]; [g perform:aSelector with:argument1 with:argument2]; NXUnionRect([g getExtendedBounds:&eb], &affectedBounds); } [self cache:&affectedBounds]; } } else { [self graphicsPerform:aSelector with:argument1 with:argument2]; } [self dirty]; return self; } - graphicsPerform:(SEL)aSelector with:arg1 with:arg2 { id g; unsigned i, count; count = [slist count]; for ( i = 0; i < count; i++ ) { g = [slist objectAt:i]; [g perform:aSelector with:arg1 with:arg2]; } [self dirty]; return self; } - copyPSToPasteboard:pboard { char *data; NXStream *stream; const char *types[1]; int length, maxlen; if ([slist count]) { types[0] = NXPostScriptPboardType; stream = NXOpenMemory(NULL, 0, NX_WRITEONLY); [ self copySelectionAsPS:stream]; NXGetMemoryBuffer(stream, &data, &length, &maxlen); [pboard declareTypes:types num:1 owner:[self class]]; [pboard writeType:NXPostScriptPboardType data:data length:length]; NXCloseMemory(stream, NX_FREEBUFFER); return self; } else { return nil; } } - writePSToStream:(NXStream *)stream /* over-ride GraphicView method to add one line */ { NXRect bbox; if (stream) { [self getBBox:&bbox of:glist]; [self bindDisplaysInList:glist]; /* Added line */ [self copyPSCodeInside:&bbox to:stream]; } return self; } - bindDisplays { [ self bindDisplaysInList:glist]; return self; } - bindDisplaysInList:list { [list makeObjectsPerform:@selector(setGraphicView:) with:self]; [list makeObjectsPerform:@selector(bindReference)]; [list makeObjectsPerform:@selector(bindCuts)]; [list makeObjectsPerform:@selector(replaceDispFuncs)]; return self; } - replace:oldTuple with:newTuple { id g; unsigned int i; i = [glist count]; while ( i-- ) { g = [glist objectAt:i]; [g replace:oldTuple with:newTuple]; } return self; } - closeTupleFile:(const char *) filename { List *plotList; InspectTuple *inspectTuple; HTuple *htuple; Plot *plot; int i, j, pcount; plotList = [self plotList]; pcount = [plotList count]; if ( !pcount ) { return self; } inspectTuple = [hippoDraw inspectTuple]; tupleList = [inspectTuple tupleListForFile:filename]; if ( ![tupleList count] ) { return self; } for ( i = 0; i < pcount; i++) { plot = [plotList objectAt:i]; htuple = [plot hTuple]; j = [tupleList indexOf:htuple]; if ( j != NX_NOT_IN_LIST ) { [ plot closeTuple ]; } } return self; } - openTuple:pasteBoard userData:(const char *)args error:(char **)errorMsg { id inspectTuple; id retval; int graphtype; inspectTuple = [hippoDraw inspectTuple]; retval = [inspectTuple openTuple:pasteBoard userData:args error:errorMsg]; if ( retval == nil ) { return self; } sscanf(args, "%i", &graphtype ); [self addPlotOfType:graphtype]; return self; } - calcDefaultPlotSize:(NXRect *) bbox { NXRect frameRect; const char *defaultValue; unsigned int cols, rows; float h, w; defaultValue = NXGetDefaultValue("HippoDraw", "NumPlotCols" ); sscanf( defaultValue, "%u", &cols ); if ( cols <= 0 ) { sscanf( DEFAULTCOLS, "%u", &cols ); } defaultValue = NXGetDefaultValue("HippoDraw", "NumPlotRows" ); sscanf( defaultValue, "%u", &rows ); if ( rows <= 0 ) { sscanf( DEFAULTROWS, "%u", &rows ); } [[[self window] delegate] getPageFrame:&frameRect]; if ( frameRect.size.height > frameRect.size.width ) { w = (frameRect.size.width - 10.0*(cols-1)) / cols; h = (frameRect.size.height - 10.0*(rows-1)) / rows; } else { w = (frameRect.size.width - 10.0*(rows-1)) / rows; h = (frameRect.size.height - 10.0*(cols-1)) / cols; } /* truncate to the factor of 10 */ w = 10.0 * (int)(w/10.0); h = 10.0 * (int)(h/10.0); NXSetRect( bbox, 0, 0, w, h ); return self; } - startArchivingTo:(const char *)directory { HTuple *hTuple; id inspector; int i; tupleList = [self tupleList]; i = [tupleList count]; while( i-- ) { hTuple = [tupleList objectAt:i]; [hTuple startArchivingTo:directory]; } if ( [self hasPFunctions] ) { inspector = [hippoDraw inspectPFunc]; [inspector load:self]; [inspector startArchivingTo:directory]; } return self; } - (BOOL) hasPFunctions { List *funcList; List *classList; List *plotList; Plot *plot; int i; classList = [[List allocFromZone:[self zone]] initCount:0]; plotList = [self plotList]; i = [plotList count]; while (i--) { plot = [plotList objectAt:i]; funcList = [plot functionList]; if ( funcList && [funcList count] ) { return YES; } } return NO; } - (int) finishUnarchivingFrom:(const char *)directory { HTuple *hTuple; InspectTuple *inspector; int i, irc; i = [tupleList count]; while ( i-- ) { hTuple = [tupleList objectAt:i]; irc = [hTuple finishUnarchivingFrom:directory]; if ( irc != 0 ) return irc; } inspector = [hippoDraw inspectTuple]; [inspector updateColBrowser]; /* in case functions added columns */ /* Now can safely bind the displays to the n-tuples */ [self bindDisplays]; /* The following was in GraphicView awake method, but was taken * out so we can bind the displays first and we need the know the * directory before be can un-archive functions */ if (!InMsgPrint) { [self createCacheWindow]; [self cache:&bounds andUpdateLinks:NO]; } return 0; } - write:(NXTypedStream *)stream { id cut; unsigned int i, count; [super write:stream]; NXWriteObject( stream, tupleList ); if ( cutList ) { count = [cutList count]; } else { count = 0; } NXWriteType( stream, "i", &count ); for ( i = 0; i < count; i++ ) { cut = [cutList objectAt:i]; NXWriteObjectReference( stream, cut ); } return self; } - read:(NXTypedStream *)stream { id cut; unsigned int i, count; [super read:stream]; tupleList = NXReadObject( stream ); NXReadType( stream, "i", &count ); if ( count ) { cutList = [[List allocFromZone:[self zone]] initCount:0]; } for ( i = 0; i < count; i++ ) { cut = NXReadObject( stream ); if ( cut ) { [cutList addObject:cut]; } } return self; } - awake { id inspectTuple; hippoDraw = NXGetNamedObject("HDrawInstance", NXApp); if ( tupleList && [tupleList count] ) { [ hippoDraw orderFrontTupleInsp:self]; inspectTuple = [hippoDraw inspectTuple]; if ([inspectTuple addTuplesIfAbsent:tupleList] != HD_OK) { NX_RAISE(NX_APPBASE,NULL,NULL); } } return [super awake]; } /* Following methods makes up for used method not implemented * in the NS 3.0 version of GraphicView. */ - graphicsPerformSingle:(SEL)aSelector with:(void *)argument on:(id) g { NXRect affectedBounds; [g getExtendedBounds:&affectedBounds]; [g perform:aSelector with:argument]; [self cache:&affectedBounds]; return self; } - loadImageFromStream:(NXStream *)stream at:(const NXPoint *)location allowAlpha:(BOOL)alphaOk /* * Creates a new Image object using the PostScript or TIFF found in the * given stream and inserts it as the only item in the selection (i.e. * it deslects everything else). The new Graphic is centered at the * given point p, and the GraphicView is scrolled to make the Graphic * visible. */ { // return [self placeGraphic:[[Image allocFromZone:[self zone]] initFromStream:stream allowAlpha:alphaOk] at:location]; return [self placeGraphic:[[Image allocFromZone:[self zone]] initFromStream:stream] at:location]; } - insertGraphicNoSelect:graphic /* * Inserts the specified graphic into the glist and draws it. */ { NXRect eb; if (graphic) { [graphic deselect]; [glist insertObject:graphic at:0]; [self cache:[graphic getExtendedBounds:&eb]]; [window flushWindow]; // DIRTY(YES); } return self; } - copySelectionAsPS:(NXStream *)stream { id savedglist; if (stream && [slist count]) { savedglist = glist; glist = slist; [self writePSToStream:stream]; glist = savedglist; } else { return nil; } return self; } - pasteFromPasteboard:(Pasteboard *)pboard andLink:(LinkType)doLink at:(const NXPoint *)center { List *pblist = nil; Plot *graphic; NXRect visibleRect; NXRect graphicRect; NXRect pageRect; NXCoord delta; int i, ndely; pblist = [super pasteFromPasteboard:pboard andLink:doLink at:center]; if ( pblist ) { i = [pblist count]; while (i--) { graphic = [pblist objectAt:i]; if ( [graphic isKindOf:[Plot class]] ) { [graphic setGraphicView:self]; } if ( [self getVisibleRect:&visibleRect] ) { [graphic getBounds:&graphicRect]; if ( !NXContainsRect(&frame, &graphicRect) ) { delta = frame.origin.y - graphicRect.origin.y; [[[self window] delegate] getPageFrame:&pageRect]; ndely = delta/pageRect.size.height; graphicRect.origin.y += ndely * pageRect.size.height; [graphic setBounds:&graphicRect]; } if ( !NXContainsRect(&frame, &graphicRect) ) { delta = frame.origin.x - graphicRect.origin.x; [[[self window] delegate] getPageFrame:&pageRect]; ndely = delta/pageRect.size.width; graphicRect.origin.x += ndely * pageRect.size.width; [graphic setBounds:&graphicRect]; } } } [self bindDisplaysInList:pblist]; /* Hippo added */ } return pblist; } - (BOOL) isAllowed { id g; int i; i = [slist count]; while (i-- ) { g = [slist objectAt:i]; if ( [g isKindOf:[Plot class]] ) { if ( [g isCutPlot] ) { if ( [g dependCount] ) { NXRunAlertPanel("Can not delete", "Selected graphic include plots that display" " a cut. Remove cut from target plot(s) first.", "OK", NULL, NULL); return NO; } } } } return YES; } - calcPlacement: (const NXSize *)theSize result:(NXPoint *)location { NXRect curRect; NXRect frameRect, box; NXRect sliceRect, filledRect; float pageHeight; id g, myglist; int below=1, i; [ self getFrame: &frameRect ]; myglist = [[List allocFromZone:[self zone]] init]; for (i=[glist count]-1; i>=0; i--) { g = [glist objectAt:i]; if (![g isKindOf:[PageMarker class]]) [myglist addObject:g]; } [ self getBBox:&curRect of:myglist ]; /* * when there is nothing in the document, bounding box comes back with * all 0's. Reset to region at top of page. */ if ( NXEmptyRect(&curRect) ) { curRect.origin.x = 0.0; curRect.origin.y = frameRect.size.height; } else if (curRect.size.height >= theSize->height) { /* * see if there is room on right at bottom of bounding box. */ NXDivideRect( &curRect, &sliceRect, theSize->height, 1 ); NXSetRect( &filledRect, 0.0, 0.0, 0.0, 0.0 ); i = [myglist count]; while ( i-- ) { g = [myglist objectAt:i]; [g getBounds:&box]; NXIntersectionRect( &sliceRect, &box ); NXUnionRect( &box, &filledRect ); } location->x = filledRect.origin.x + filledRect.size.width + 10.0; location->y = filledRect.origin.y; below = (location->x + theSize->width) > frameRect.size.width; NXUnionRect( &sliceRect, &curRect ); } [[[self window] delegate] getPageFrame:&box]; pageHeight = box.size.height; if (below) { location->x = 0.0; location->y = curRect.origin.y - theSize->height; if ((curRect.origin.y-frameRect.origin.y) < theSize->height) { int npages = (int)((frameRect.origin.y - location->y) / pageHeight) + 1; [ self addPages: npages]; /* * everything was moved up by npages pages, so change * the current bounding box. */ location->y += npages * pageHeight; } } /* * if size is shorter than a page, make sure stuff * does not cross page boundary. */ if (theSize->height < pageHeight && (int)(location->y/pageHeight) != (int)((location->y + theSize->height)/pageHeight) ) { location->y = pageHeight * (int)(location->y/pageHeight + 1) - theSize->height; } location->x = 10.0 * (int)(location->x / 10.0); /* round to nearest 10 */ location->y = 10.0 * (int)(location->y / 10.0); [myglist free]; return self; } @end /* Private methods, i.e. only called by self */ @implementation HGraphicView(PrivateMethods) - placeGraphic:graphic at:(const NXPoint *)location /* * Places the graphic centered at the given location on the page. * If the graphic is too big, the user is asked whether the graphic * should be scaled. */ { int scale; NXPoint offset; float sx, sy, factor; NXRect gbounds, myBounds; if (graphic) { [graphic getExtendedBounds:&gbounds]; if (gbounds.size.width > bounds.size.width || gbounds.size.height > bounds.size.height) { scale = NXRunAlertPanel("Load Image", "The image is too large to fit on the page. Scale it to fit?", "Scale", "Don't Scale", "Cancel"); if (scale < 0) { [graphic free]; return self; } else if (scale > 0) { sx = (bounds.size.width / gbounds.size.width) * 0.95; sy = (bounds.size.height / gbounds.size.height) * 0.95; factor = MIN(sx, sy); gbounds.size.width *= factor; gbounds.size.height *= factor; [graphic sizeTo:&gbounds.size]; } } if (location) [graphic centerAt:location]; [graphic getExtendedBounds:&gbounds]; myBounds = bounds; NXContainRect(&myBounds, &gbounds); offset.x = bounds.origin.x - myBounds.origin.x; offset.y = bounds.origin.y - myBounds.origin.y; if (offset.x || offset.y) [graphic moveBy:&offset]; [self deselectAll:self]; [self insertGraphic:graphic]; [self scrollGraphicToVisible:graphic]; } return graphic; } - tupleList { if ( !tupleList ) { tupleList = [[List allocFromZone:[self zone]] initCount:0]; } else { [tupleList empty]; } [glist makeObjectsPerform:@selector(addHTupleToList:) with:tupleList]; return tupleList; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.