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.