home *** CD-ROM | disk | FTP | other *** search
- /* 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 <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 is 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
-