home *** CD-ROM | disk | FTP | other *** search
/ NOVA - For the NeXT Workstation / NOVA - For the NeXT Workstation.iso / SourceCode / AdobeExamples / NX_HitDetect / DocView.m < prev    next >
Encoding:
Text File  |  1992-12-19  |  11.6 KB  |  460 lines

  1.  
  2. /*
  3.  * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
  4.  *
  5.  * (b)  If this Sample Code is distributed as part of the Display PostScript
  6.  *    System Software Development Kit from Adobe Systems Incorporated,
  7.  *    then this copy is designated as Development Software and its use is
  8.  *    subject to the terms of the License Agreement attached to such Kit.
  9.  *
  10.  * (c)  If this Sample Code is distributed independently, then the following
  11.  *    terms apply:
  12.  *
  13.  * (d)  This file may be freely copied and redistributed as long as:
  14.  *    1) Parts (a), (d), (e) and (f) continue to be included in the file,
  15.  *    2) If the file has been modified in any way, a notice of such
  16.  *      modification is conspicuously indicated.
  17.  *
  18.  * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
  19.  *    Adobe Systems Incorporated.
  20.  * 
  21.  * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
  22.  *    CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
  23.  *    AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
  24.  *    ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
  25.  *    OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
  26.  *    WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
  27.  *    WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
  28.  *    DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
  29.  *    FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
  30.  *    OF THIRD PARTY RIGHTS.
  31.  */
  32.  
  33. /*
  34.  *    DocView.m
  35.  *
  36.  *    This class handles the scaling of the drawing view. It repositions
  37.  *    the drawing view within itself if the drawing view is smaller than the
  38.  *    size of the clip view. The size of the doc view is:
  39.  *    MAX(clip view frame, drawing view frame).
  40.  *
  41.  *    Version:    2.0
  42.  *    Author:    Ken Fromm
  43.  *    History:
  44.  *            03-07-91        Added this comment.
  45.  */
  46.  
  47. #import "DetectApp.h"
  48. #import "DocView.h"
  49. #import "DrawingView.h"
  50. #import "DrawingViewWraps.h"
  51.  
  52. #import <appkit/NXCursor.h>
  53. #import <appkit/NXImage.h>
  54. #import <appkit/Matrix.h>
  55. #import <appkit/ScrollView.h>
  56. #import <dpsclient/wraps.h>
  57. #import <appkit/nextstd.h>
  58.  
  59. @implementation DocView
  60.  
  61. /*
  62. *    Since there is only one subview its easier to keep track of it as an
  63. *    instance variable rather than in the subview list.  Returns the 
  64. *    previous drawing view.
  65. */
  66. - addDrawView:subView
  67. {
  68.     id        oldView;
  69.  
  70.     oldView = drawviewId;
  71.     [oldView  removeFromSuperview];
  72.  
  73.     [self  addSubview:subView];
  74.     drawviewId = subView;
  75.     
  76.     return oldView;
  77. }
  78.  
  79. /*
  80. *    Change the menu title and toggle the trace boolean
  81. */
  82. - traceZoom:sender
  83. {
  84.     if (!tracezoom)
  85.         [[sender selectedCell] setTitle:"Zooming On"];
  86.     else
  87.         [[sender selectedCell] setTitle:"Zooming Off"];
  88.  
  89.     tracezoom = !tracezoom;
  90.     
  91.     return self;
  92. }
  93.  
  94. /*     Returns whether tracing should be turned on when zooming. */
  95. - (BOOL) isTraceZooming
  96. {
  97.     return tracezoom;
  98. }
  99.  
  100. /*    Sets and returns the scale for the drawing view. */
  101. - setScale:(float)value
  102. {
  103.     scale = value;
  104.     
  105.     return self;
  106. }
  107.  
  108. - (float) scale
  109. {
  110.     return  scale;
  111. }
  112.  
  113. /*
  114. *    Returns the size of the control point scaled to reflect the
  115. *    current scale. If the scaling were not done, a control point
  116. *    would look like the USS Enterprise at 400%. (The aircraft
  117. *    carrier.) 
  118. *    
  119. */
  120. - (float) controlPointSize
  121. {
  122.     return  FONTSIZE * (1.0/scale);
  123. }
  124.  
  125. /*
  126. *    Returns a scaled the hit setting. Using an unscaled hit setting would be
  127. *    like using a boxing glove at 400% scale.
  128. */
  129. - (float) hitSetting
  130. {    
  131.     return [NXApp  hitSetting] * (1.0/scale);
  132. }
  133.  
  134.  
  135. - (BOOL) isZooming
  136. {
  137.     return zooming;
  138. }
  139.  
  140. /*
  141. *    Check whether the frame of the drawingview is in the rectangle passed in.
  142. *    If drop is true, then include the linewidth and the drop shadow as part of the
  143. *    drawingview frame.
  144. */
  145. - getDrawViewInRect:(const NXRect *) aRect  withDrop:(BOOL) drop
  146. {
  147.     id        aView = NULL;
  148.  
  149.     NXRect    viewRect, dropRect;
  150.     
  151.     [drawviewId  getFrame:&viewRect];
  152.     if (drop)
  153.     {    
  154.         dropRect = viewRect;
  155.         NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
  156.         NXOffsetRect(&viewRect, rint(LINEWIDTH/2 * scale), rint(LINEWIDTH/2 * scale));
  157.         NXUnionRect(&dropRect, &viewRect);
  158.     }
  159.     if (NXIntersectsRect(aRect, &viewRect))
  160.         aView = drawviewId;
  161.  
  162.     return  aView;
  163. }
  164.  
  165. /*
  166. *    This method is overridden from the View class. When the
  167. *    user is zooming the cursor rect for the zoom cursor is set
  168. *    the the frame of the drawing view.
  169. */
  170. - resetCursorRects
  171. {
  172.     id            imageId, visView;
  173.  
  174.     NXPoint        hotspot;
  175.  
  176.     NXRect        cursorRect, visRect;
  177.  
  178.     if (zooming)
  179.     {
  180.         if (!zoomCursor)
  181.         {
  182.             hotspot.x = hotspot.y = 8.0;
  183.             imageId = [NXImage  newFromSection:"zoom.tiff"];
  184.             zoomCursor = [NXCursor  newFromImage:imageId];
  185.             [zoomCursor setHotSpot:&hotspot];
  186.         }
  187.  
  188.         [self getVisibleRect:&visRect];
  189.         visView = [self getDrawViewInRect:&visRect  withDrop:NO];
  190.         if (visView)
  191.         {
  192.             [visView getFrame:&cursorRect];
  193.             NXIntersectionRect(&visRect, &cursorRect);
  194.             [self addCursorRect:&cursorRect  cursor:zoomCursor];
  195.         }        
  196.         else
  197.             zooming = NO;
  198.     }
  199.  
  200.     return self;
  201. }
  202.  
  203. /*
  204. *    Messaged from the zoom matrix. Starts the zoom loop. At the next
  205. *    mouse down in the drawing view, the scaleDrawView:toPoint: method
  206. *    will be called.
  207. */
  208. - zoom:sender
  209. {
  210.     zooming = YES;
  211.     zoomControl = sender;
  212.     [self  resetCursorRects];
  213.  
  214.     [window makeKeyAndOrderFront:self];
  215.  
  216.     return self;
  217. }
  218.  
  219. /*
  220. *    Sizes the drawing view from the old scale to the new scale.
  221. *    The frame of the view is used because it provides the size
  222. *     of the view in default coordinates. The bounds of the view
  223. *    provides the size in scaled coordinates. As a result, the
  224. *    bounds will always be the same regardless of the scale.
  225. */
  226. - sizeView:viewId withScale:(float) newscale
  227. {
  228.     float            scalefactor, sizewidth, sizeheight;
  229.  
  230.     NXRect        viewFrame;
  231.     
  232.     [viewId  getFrame:&viewFrame];
  233.     scalefactor = newscale/scale;
  234.     sizewidth = viewFrame.size.width*scalefactor;
  235.     sizeheight = viewFrame.size.height*scalefactor;
  236.     [viewId sizeTo:rint(sizewidth) :rint(sizeheight)];
  237.  
  238.     return self;
  239. }
  240.  
  241. /* 
  242. *    Scales the drawing view from the old scale to the new scale.
  243. *    The scale method is relative so we use the ratio
  244. *    of the old scale to the new scale to obtain the scaling factor.
  245. */
  246. - scaleView:viewId  withScale:(float) newscale
  247. {
  248.     float     scalefactor;
  249.  
  250.     scalefactor = newscale/scale;
  251.     [viewId scale:scalefactor  :scalefactor];
  252.  
  253.     return self;
  254. }
  255.  
  256. /*
  257. *    Place the view passed in in the center of the doc view
  258. *    if it is smaller than the size of the ClipView. Scroll bars
  259. *    are added or deleted depending on whether or not they
  260. *    are needed. (They can always appear but we've chosen
  261. *    to show them conditionally in this example.
  262. *
  263. *    Two passes are made through the loop because adding
  264. *    or removing a horizontal or vertical scrollbar will 
  265. *    affect the size of the remaining dimension .
  266. */
  267. - placeView:viewId
  268. {
  269.     BOOL        vert = NO, horiz = NO, done = NO;
  270.  
  271.     int            passes = 0, border_type;
  272.  
  273.     float            margin;
  274.     
  275.     NXSize        contSize, newSize, insetSize, delta;
  276.  
  277.     NXRect         viewFrame, scrollFrame;
  278.  
  279.     margin = 4 * OFFSET * scale;
  280.  
  281.     [viewId  getFrame:&viewFrame];
  282.     [[superview superview]  getFrame:&scrollFrame];
  283.     border_type = [[superview superview]  borderType];
  284.  
  285.     while (!done && ++passes <= 2)
  286.     {
  287.         [ScrollView getContentSize:&contSize forFrameSize:&scrollFrame.size
  288.             horizScroller:horiz  vertScroller:vert borderType:border_type];
  289.  
  290.         newSize.width = MAX(viewFrame.size.width, contSize.width);
  291.         newSize.height = MAX(viewFrame.size.height, contSize.height);
  292.  
  293.         delta.width = newSize.width - viewFrame.size.width;
  294.         delta.height = newSize.height - viewFrame.size.height;
  295.         if (delta.width != 0.0 || delta.height != 0.0)
  296.         {
  297.             if (delta.width < margin)
  298.                 newSize.width += margin - delta.width;
  299.             if (delta.height < margin)
  300.                 newSize.height += margin - delta.height;
  301.         }
  302.  
  303.         horiz = (newSize.width != contSize.width);
  304.         vert = (newSize.height != contSize.height);
  305.         if ((horiz && vert) || (!horiz && !vert))
  306.             done = YES;
  307.         else
  308.             done = NO;
  309.     }
  310.     
  311.     [self  sizeTo:newSize.width  :newSize.height];
  312.  
  313.     insetSize.width = floor((newSize.width - viewFrame.size.width)/2);
  314.     insetSize.height =  floor((newSize.height - viewFrame.size.height)/2);
  315.     [viewId  moveTo:insetSize.width  :insetSize.height];
  316.     if (insetSize.width != 0 || insetSize.height != 0)
  317.         [viewId  setClipping:YES];
  318.     else
  319.         [viewId setClipping:NO];
  320.  
  321.     if (horiz)
  322.         [[superview superview] setHorizScrollerRequired:YES];
  323.     else
  324.         [[superview superview] setHorizScrollerRequired:NO];
  325.     
  326.     if (vert)
  327.         [[superview superview] setVertScrollerRequired:YES];
  328.     else
  329.         [[superview superview] setVertScrollerRequired:NO];
  330.  
  331.     return self;
  332. }
  333.  
  334. /*
  335. *    Scales the view to the tag of the selected matrix cell and then
  336. *    scrolls to the point. The point is in window coordinates so
  337. *    it must be converted to the drawing view  coordinates in order
  338. *    to position it in the same relative place in the view.
  339. */
  340. - scaleDrawView:hitView  toPoint:(NXPoint *) p;
  341. {
  342.     float            newscale;
  343.  
  344.     NXPoint        viewPt;
  345.  
  346.     [window invalidateCursorRectsForView:self];
  347.     newscale = [zoomControl  selectedTag] * 0.01;
  348.     if (hitView && newscale != scale)
  349.     {
  350.         /* Convert the point to the hitView's coordinates. */
  351.         viewPt = *p;
  352.         [hitView  convertPoint:&viewPt  fromView:nil];
  353.         [window disableDisplay];
  354.             /*
  355.             *    Size and then scale the drawing view. The frame of the
  356.             *    drawing view must reflect the changed size. Scaling
  357.             *    alone will not change the frame.
  358.             */
  359.             [self  sizeView:hitView  withScale:newscale];
  360.             [self  scaleView:hitView  withScale:newscale];
  361.             [self  setScale:newscale];
  362.     
  363.             [self  placeView:hitView];
  364.             [self  scrollPoint:&viewPt  inView:hitView  to:p];
  365.         [window reenableDisplay];
  366.  
  367.         /* Trace the zoom if the menu option is set. */
  368.         if (tracezoom)
  369.             DPSTraceContext(DPSGetCurrentContext(), YES);
  370.  
  371.         [[window contentView]  display];
  372.  
  373.         if (tracezoom)
  374.             DPSTraceContext(DPSGetCurrentContext(), NO);
  375.     }
  376.     zooming = NO;
  377.  
  378.     return self;
  379. }
  380.  
  381.  
  382. /*
  383.  *    Use the point location relative to the window versus the point relative
  384.  *    to the drawing view (before the scale) to determine where to scroll
  385.  *    the drawing view. We want the same location in the drawing view to
  386.  *    appear where the mouse downed occurred.  The window coordinates
  387.  *    are used and then adjusted by the position of the scrolling frame
  388.  *    because the presence or absence of scrollbars throws the use
  389.  *    of the doc views coordinates awry.
  390.  */    
  391. - scrollPoint:(const NXPoint *) aPt  inView:hitView  to:(const NXPoint *) windowPt
  392. {
  393.     NXPoint        viewPt;
  394.  
  395.     NXSize        contSize;
  396.  
  397.     NXRect         viewFrame, visRect, scrollFrame;
  398.  
  399.     [[superview superview]  getContentSize:&contSize];
  400.     [hitView  getFrame:&viewFrame];
  401.  
  402.     if (viewFrame.size.width > contSize.width || viewFrame.size.height > contSize.height)
  403.     {
  404.         viewPt = *aPt;
  405.         [self  convertPoint:&viewPt  fromView:hitView];        
  406.         [self getVisibleRect:&visRect];
  407.         [[superview superview] getFrame:&scrollFrame];
  408.  
  409.         if (viewFrame.size.width > contSize.width)
  410.             viewPt.x  -= windowPt->x - (scrollFrame.origin.x +scrollFrame.size.width -
  411.                             visRect.size.width);
  412.  
  413.         if (viewFrame.size.height > contSize.height)
  414.             viewPt.y  -= windowPt->y - (scrollFrame.origin.y + scrollFrame.size.height -
  415.                             visRect.size.height);
  416.  
  417.         [self  scrollPoint:&viewPt];        
  418.     }
  419.  
  420.     return self;
  421. }
  422.  
  423. /*
  424.  * This drawSelf method draws a border around the drawing view as well as a
  425.  * drop shadow.  This is only done if it will be visible however. We tell if it is visible
  426.  * if the rectangle passed in is not contained entirely within the drawingView.
  427. */
  428. - drawSelf:(NXRect *)r :(int) count
  429. {
  430.     id            visView;
  431.  
  432.     NXRect        drawRect, dropRect;
  433.  
  434.     visView = [self getDrawViewInRect:r  withDrop:YES];
  435.     if (visView)
  436.     {
  437.         [visView  getFrame:&drawRect];
  438.         if (!NXContainsRect(&drawRect, r))
  439.         {
  440.             dropRect = drawRect;
  441.             NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
  442.             
  443.             PSgsave();
  444.             PSsetgray(NX_BLACK);
  445.             PSsetlinewidth(LINEWIDTH * scale);
  446.             PSrectclip(r->origin.x, r->origin.y, r->size.width, r->size.height);
  447.             PSrectfill(dropRect.origin.x, dropRect.origin.y,
  448.                 dropRect.size.width, dropRect.size.height);
  449.             PSrectstroke(drawRect.origin.x, drawRect.origin.y,
  450.                 drawRect.size.width, drawRect.size.height);
  451.             PSgrestore();
  452.         }
  453.     }
  454.  
  455.     return self;            
  456. }
  457.  
  458. @end
  459.  
  460.