This is BigView.m in view mode; [Download] [Up]
/* BigView.m * Purpose: Demonstrates custom pagination. * a BigView is a "matrix" of 3x4 rectangles, each of which is 8" x 10" * A bigView therefore has very logical page breaks, although the Appkit by * default won't break up the bigView on those boundaries. This class demonstrates * how to do this. This class also demonstrates somewhat optimized scrolling by only * drawing affected pages (because a page is the smallest divisible unit in this class.) * * You may freely copy, distribute, and reuse the code in this example. * NeXT disclaims any warranty of any kind, expressed or implied, as to its * fitness for any particular use. * * Written by: Samuel Streeper * Created: (04/April/91) */ #import "BigView.h" #import "drawRect.h" #import "MyPrintInfo.h" #import <dpsclient/wraps.h> #import <appkit/graphics.h> #import <appkit/Application.h> #import <appkit/PrintInfo.h> #import <math.h> #define INCHES * 72.0 #define PAGEWIDTH (8 INCHES) #define PAGEHEIGHT (10 INCHES) #define GRIDWIDTH (1. INCHES) #define GRIDHEIGHT (1. INCHES) #define MAXCOLUMN 3 #define MAXROW 4 #define PAGES (MAXCOLUMN * MAXROW) #define min(X, Y) ((X) < (Y) ? (X) : (Y)) @implementation BigView static char *string[PAGES] = { "one","two","three","four", "five","six","seven","eight", "nine","ten","and","more!" }; // I could just printf these. Nah... static char *numbers[PAGES] = { "1","2","3","4","5","6", "7","8","9","A","B","C" }; - initFrame:(const NXRect *)frameRect { // normally you would always initialize to the frame you are passed, like this: // [super initFrame:frameRect]; // however, I want to force all BigView intances to be the 'correct' size. // (you usually shouldn't do this...) NXRect r = {0,0,(MAXCOLUMN*PAGEWIDTH),(MAXROW*PAGEHEIGHT)}; [super initFrame:&r]; [self allocateGState]; // for faster focusing and scrolling loadPSProcedures(); // initialize the drawing context return self; } // DrawSelf if used to construct the View for printing or when a portion // gets scrolled onto the screen. It should only draw the areas that // intersect with rects. - drawSelf:(const NXRect *)rects :(int)rectCount { int darkFlag; int minColumn, maxColumn, minRow, maxRow; int row, col, offset; if (!rectCount) return self; minColumn = rects->origin.x / PAGEWIDTH; maxColumn = (rects->origin.x + rects->size.width) / PAGEWIDTH; minRow = rects->origin.y / PAGEHEIGHT; maxRow = (rects->origin.y + rects->size.height) / PAGEHEIGHT; if (maxColumn > MAXCOLUMN-1) maxColumn = MAXCOLUMN-1; if (maxRow > MAXROW-1) maxRow = MAXROW-1; // Drawing is optimized to draw only the affected pages. In this app, // it's possible for one page to somewhat overlap another page. // Without clipping, drawing optimization could allow a page in back to // draw, while not telling the page in front to draw. Clipping to rects // insures that either the background will not draw over the foreground, // or if it does, the foreground page will also draw NXRectClip(rects); for (col = minColumn; col <= maxColumn; col++) { for (row = minRow; row <= maxRow; row++) { offset = ((MAXROW-1)-row)*MAXCOLUMN + col; darkFlag = ((row + col) & 1); drawRect(col*PAGEWIDTH,row*PAGEHEIGHT,string[offset], numbers[offset], darkFlag); } } return self; } // If the extended printInfo has been set to application controlled // pagination, tell the kit we know where our pages lie. - (BOOL)knowsPagesFirst:(int *)firstPageNum last:(int *)lastPageNum { if ([pi paginationMode] != APPCONTROLLED) return NO; *lastPageNum = PAGES; return YES; } // If we know where our pages lie, the kit will ask us for the rect // for each page. - (BOOL)getRect:(NXRect *)theRect forPage:(int)page { int row, col; if (page < 1 || page > PAGES) return NO; page--; row = (MAXROW-1) - (page / MAXCOLUMN); col = page % MAXCOLUMN; theRect->origin.x = col * PAGEWIDTH; theRect->origin.y = row * PAGEHEIGHT; theRect->size.width = PAGEWIDTH; theRect->size.height = PAGEHEIGHT; return YES; } // There are at least 3 good reasons to override this method: // 1) The printing rect does not appear where you desire on the paper // so you set your own value for location // 2) The rect in aRect is not the one that you want placed, due to // scaling by your own pagination algorithm (which is applied _after_ // this method gets invoked), or you will change // the size with adjustPageHeight and andjustPageWidth. I override // this method for reason #2 // 3) The kit version of this method will not horizontally center // a rect if the View has more than 1 column, and it will not // vertically center a rect if the View has more than 1 row. // If you need this, it is trivial to rewrite this method to // center the rect within the paperRect. - placePrintRect:(const NXRect *)aRect offset:(NXPoint *)location { NXRect myRect; float vertScale, horScale; NXCoord l,r,t,b; const NXRect *paperRect; if ([pi paginationMode] != APPCONTROLLED) { [super placePrintRect:aRect offset:location]; } else { myRect = *aRect; paperRect = [pi paperRect]; [pi getMarginLeft:&l right:&r top:&t bottom:&b]; // calculate scaling factor so that rect will fit within margins horScale = (paperRect->size.width - r - l)/PAGEWIDTH; if (horScale <= 0) horScale = 1; vertScale = (paperRect->size.height - t - b)/PAGEHEIGHT; if (vertScale <= 0) vertScale = 1; realScale = min(horScale, vertScale); myRect.size.width *= realScale; myRect.size.height *= realScale; // now place the scaled rect (scaling actually happens later, // in addToPageSetup...) [super placePrintRect:&myRect offset:location]; } return self; } // Note: add to page setup is called after placePrintRect. Thus placePrintRect attempts // to place an unscaled rect. Thus any scaling you will add here should be figured // into the placement of the print rectangle. - addToPageSetup { [super addToPageSetup]; if ([pi paginationMode] == APPCONTROLLED) { PSscale(realScale, realScale); } return self; } // A helpful hint: You won't be able to adjust the height if vertical pagination // is set to clip... - adjustPageHeightNew:(float *)newBottom top:(float)oldTop bottom:(float)oldBottom limit:(float)bottomLimit { if ([pi paginationMode] == AUTOWITHHELP) { // caution! with normal coordinates, you need to round the height up... * newBottom = (ceil(oldBottom/GRIDHEIGHT)) * GRIDHEIGHT; if (*newBottom < oldBottom || *newBottom > bottomLimit) *newBottom = oldBottom; } else { [super adjustPageHeightNew:newBottom top:oldTop bottom:oldBottom limit:bottomLimit]; } return self; } // A helpful hint: You won't be able to adjust the width if horizontal pagination // is set to clip... - adjustPageWidthNew:(float *)newRight left:(float)oldLeft right:(float)oldRight limit:(float)rightLimit { if ([pi paginationMode] == AUTOWITHHELP) { * newRight = (floor(oldRight/GRIDWIDTH)) * GRIDWIDTH; if (*newRight > oldRight || *newRight < rightLimit) *newRight = oldRight; } else { [super adjustPageWidthNew:newRight left:oldLeft right:oldRight limit:rightLimit]; } return self; } // Remember that when you print, you are outputting to a different context // than when you were drawing. Therefore, you need to define the // procedures you will use for the printing context. - endPrologue { loadPSProcedures(); return [super endPrologue]; } // I do this just so I don't have to keep calling [NXApp printInfo] - setPrintInfo:newPi { pi = newPi; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.