home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula
/
nebula.bin
/
SourceCode
/
MiniExamples
/
PaginationLab
/
BigView.m
< prev
next >
Wrap
Text File
|
1991-05-18
|
8KB
|
273 lines
/* 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