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

  1. /* BigView.m
  2.  * Purpose: Demonstrates custom pagination.
  3.  * a BigView is a "matrix" of 3x4 rectangles, each of which is 8" x 10"
  4.  * A bigView therefore has very logical page breaks, although the Appkit by
  5.  * default won't break up the bigView on those boundaries.  This class demonstrates
  6.  * how to do this.  This class also demonstrates somewhat optimized scrolling by only
  7.  * drawing affected pages (because a page is the smallest divisible unit in this class.)
  8.  *
  9.  * You may freely copy, distribute, and reuse the code in this example.
  10.  * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  11.  * fitness for any particular use.
  12.  *
  13.  * Written by: Samuel Streeper
  14.  * Created: (04/April/91)
  15.  */
  16.  
  17. #import "BigView.h"
  18. #import "drawRect.h"
  19. #import "MyPrintInfo.h"
  20. #import <dpsclient/wraps.h>
  21. #import <appkit/graphics.h> 
  22. #import <appkit/Application.h>
  23. #import <appkit/PrintInfo.h>
  24. #import <math.h>
  25.  
  26. #define INCHES * 72.0
  27.  
  28. #define PAGEWIDTH (8 INCHES)
  29. #define PAGEHEIGHT (10 INCHES)
  30. #define GRIDWIDTH (1. INCHES)
  31. #define GRIDHEIGHT (1. INCHES)
  32.  
  33. #define MAXCOLUMN 3
  34. #define MAXROW 4
  35. #define PAGES (MAXCOLUMN * MAXROW)
  36.  
  37. #define min(X, Y)  ((X) < (Y) ? (X) : (Y))
  38.  
  39. @implementation BigView
  40.  
  41. static char *string[PAGES] = {
  42.     "one","two","three","four",
  43.     "five","six","seven","eight",
  44.     "nine","ten","and","more!"
  45.     };
  46.  
  47. // I could just printf these.  Nah...
  48. static char *numbers[PAGES] = {
  49.     "1","2","3","4","5","6",
  50.     "7","8","9","A","B","C"
  51.     };
  52.     
  53. - initFrame:(const NXRect *)frameRect
  54. {
  55.     // normally you would always initialize to the frame you are passed, like this:
  56.     //    [super initFrame:frameRect];
  57.     // however, I want to force all BigView intances to be the 'correct' size.
  58.     // (you usually shouldn't do this...)
  59.  
  60.     NXRect r = {0,0,(MAXCOLUMN*PAGEWIDTH),(MAXROW*PAGEHEIGHT)};
  61.     [super initFrame:&r];
  62.  
  63.     [self allocateGState];        // for faster focusing and scrolling
  64.     loadPSProcedures();            // initialize the drawing context
  65.     return self;
  66. }
  67.  
  68. // DrawSelf if used to construct the View for printing or when a portion
  69. // gets scrolled onto the screen.  It should only draw the areas that
  70. // intersect with rects.
  71. - drawSelf:(const NXRect *)rects :(int)rectCount
  72. {
  73.     int darkFlag;
  74.     int minColumn, maxColumn, minRow, maxRow;
  75.     int row, col, offset;
  76.     
  77.     if (!rectCount) return self;
  78.     minColumn = rects->origin.x / PAGEWIDTH;
  79.     maxColumn = (rects->origin.x + rects->size.width) / PAGEWIDTH;
  80.  
  81.     minRow = rects->origin.y / PAGEHEIGHT;
  82.     maxRow = (rects->origin.y + rects->size.height) / PAGEHEIGHT;
  83.     
  84.     if (maxColumn > MAXCOLUMN-1) maxColumn = MAXCOLUMN-1;
  85.     if (maxRow > MAXROW-1) maxRow = MAXROW-1;
  86.  
  87.     // Drawing is optimized to draw only the affected pages.  In this app,
  88.     // it's possible for one page to somewhat overlap another page.
  89.     // Without clipping, drawing optimization could allow a page in back to
  90.     // draw, while not telling the page in front to draw.  Clipping to rects
  91.     // insures that either the background will not draw over the foreground,
  92.     // or if it does, the foreground page will also draw
  93.     
  94.     NXRectClip(rects);
  95.     
  96.     for (col = minColumn; col <= maxColumn; col++)
  97.     {
  98.         for (row = minRow; row <= maxRow; row++)
  99.         {
  100.             offset = ((MAXROW-1)-row)*MAXCOLUMN + col;
  101.             darkFlag = ((row + col) & 1);
  102.             drawRect(col*PAGEWIDTH,row*PAGEHEIGHT,string[offset], numbers[offset], darkFlag);
  103.         }
  104.     }
  105.     return self;
  106. }
  107.  
  108. // If the extended printInfo has been set to application controlled
  109. // pagination, tell the kit we know where our pages lie.
  110. - (BOOL)knowsPagesFirst:(int *)firstPageNum last:(int *)lastPageNum
  111. {
  112.     if ([pi paginationMode] != APPCONTROLLED) return NO;
  113.     
  114.     *lastPageNum = PAGES;
  115.     return YES;
  116. }
  117.  
  118. // If we know where our pages lie, the kit will ask us for the rect
  119. // for each page.
  120. - (BOOL)getRect:(NXRect *)theRect forPage:(int)page
  121. {
  122.     int row, col;
  123.  
  124.     if (page < 1 || page > PAGES) return NO;
  125.     page--;
  126.     row = (MAXROW-1) - (page / MAXCOLUMN);
  127.     col = page % MAXCOLUMN;
  128.  
  129.     theRect->origin.x = col * PAGEWIDTH;
  130.     theRect->origin.y = row * PAGEHEIGHT;
  131.     theRect->size.width = PAGEWIDTH;
  132.     theRect->size.height = PAGEHEIGHT;
  133.     return YES;
  134. }
  135.  
  136.  
  137. // There are at least 3 good reasons to override this method:
  138. // 1) The printing rect does not appear where you desire on the paper
  139. //        so you set your own value for location
  140. // 2) The rect in aRect is not the one that you want placed, due to
  141. //        scaling by your own pagination algorithm (which is applied _after_
  142. //        this method gets invoked), or you will change
  143. //        the size with adjustPageHeight and andjustPageWidth.  I override
  144. //        this method for reason #2
  145. // 3) The kit version of this method will not horizontally center
  146. //         a rect if the View has more than 1 column, and it will not
  147. //         vertically center a rect if the View has more than 1 row.
  148. //        If you need this, it is trivial to rewrite this method to
  149. //        center the rect within the paperRect.
  150.  
  151. - placePrintRect:(const NXRect *)aRect offset:(NXPoint *)location
  152. {
  153.     NXRect myRect;
  154.     float vertScale, horScale;
  155.     NXCoord l,r,t,b;
  156.     const NXRect *paperRect;
  157.     
  158.     if ([pi paginationMode] != APPCONTROLLED)
  159.     {
  160.         [super placePrintRect:aRect offset:location];
  161.     }
  162.     else
  163.     {    
  164.         myRect = *aRect;
  165.         paperRect = [pi paperRect];
  166.         [pi getMarginLeft:&l right:&r top:&t bottom:&b];
  167.  
  168.         // calculate scaling factor so that rect will fit within margins
  169.         horScale = (paperRect->size.width - r - l)/PAGEWIDTH;
  170.         if (horScale <= 0) horScale = 1;
  171.         vertScale = (paperRect->size.height - t - b)/PAGEHEIGHT;
  172.         if (vertScale <= 0) vertScale = 1;
  173.  
  174.         realScale = min(horScale, vertScale);
  175.         myRect.size.width *= realScale;
  176.         myRect.size.height *= realScale;
  177.         
  178.         // now place the scaled rect (scaling actually happens later,
  179.         // in addToPageSetup...)
  180.  
  181.         [super placePrintRect:&myRect offset:location];
  182.     }
  183.  
  184.     return self;    
  185. }
  186.  
  187. // Note: add to page setup is called after placePrintRect.  Thus placePrintRect attempts
  188. // to place an unscaled rect.  Thus any scaling you will add here should be figured
  189. // into the placement of the print rectangle.
  190. - addToPageSetup
  191. {
  192.     [super addToPageSetup];
  193.  
  194.     if ([pi paginationMode] == APPCONTROLLED)
  195.     {
  196.         PSscale(realScale, realScale);
  197.     }
  198.  
  199.     return self;
  200. }
  201.  
  202.  
  203. // A helpful hint:  You won't be able to adjust the height if vertical pagination
  204. // is set to clip...
  205.  
  206. - adjustPageHeightNew:(float *)newBottom
  207.     top:(float)oldTop
  208.     bottom:(float)oldBottom
  209.     limit:(float)bottomLimit
  210. {
  211.     if ([pi paginationMode] == AUTOWITHHELP)
  212.     {
  213.         // caution! with normal coordinates, you need to round the height up...
  214.         * newBottom = (ceil(oldBottom/GRIDHEIGHT)) * GRIDHEIGHT;
  215.         if (*newBottom < oldBottom || *newBottom > bottomLimit)
  216.             *newBottom = oldBottom;
  217.     }
  218.     else
  219.     {
  220.         [super adjustPageHeightNew:newBottom top:oldTop bottom:oldBottom
  221.             limit:bottomLimit];
  222.     }
  223.     return self;
  224. }
  225.  
  226. // A helpful hint:  You won't be able to adjust the width if horizontal pagination
  227. // is set to clip...
  228.  
  229. - adjustPageWidthNew:(float *)newRight
  230.     left:(float)oldLeft
  231.     right:(float)oldRight
  232.     limit:(float)rightLimit
  233. {
  234.     if ([pi paginationMode] == AUTOWITHHELP)
  235.     {
  236.         * newRight = (floor(oldRight/GRIDWIDTH)) * GRIDWIDTH;
  237.         if (*newRight > oldRight || *newRight < rightLimit)
  238.             *newRight = oldRight;
  239.     }
  240.     else
  241.     {
  242.         [super adjustPageWidthNew:newRight left:oldLeft right:oldRight
  243.             limit:rightLimit];
  244.     }
  245.     return self;
  246. }
  247.  
  248. // Remember that when you print, you are outputting to a different context
  249. // than when you were drawing.  Therefore, you need to define the
  250. // procedures you will use for the printing context.
  251.  
  252. - endPrologue
  253. {
  254.     loadPSProcedures();
  255.     return [super endPrologue];
  256. }
  257.  
  258. // I do this just so I don't have to keep calling [NXApp printInfo]
  259. - setPrintInfo:newPi
  260. {
  261.     pi = newPi;
  262.     return self;
  263. }
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272. @end
  273.