home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * (a) (C) 1990 by Adobe Systems Incorporated. All rights reserved.
- *
- * (b) If this Sample Code is distributed as part of the Display PostScript
- * System Software Development Kit from Adobe Systems Incorporated,
- * then this copy is designated as Development Software and its use is
- * subject to the terms of the License Agreement attached to such Kit.
- *
- * (c) If this Sample Code is distributed independently, then the following
- * terms apply:
- *
- * (d) This file may be freely copied and redistributed as long as:
- * 1) Parts (a), (d), (e) and (f) continue to be included in the file,
- * 2) If the file has been modified in any way, a notice of such
- * modification is conspicuously indicated.
- *
- * (e) PostScript, Display PostScript, and Adobe are registered trademarks of
- * Adobe Systems Incorporated.
- *
- * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
- * CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
- * AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
- * ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
- * OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
- * WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
- * WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
- * DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
- * OF THIRD PARTY RIGHTS.
- */
-
- /*
- * DrawView.m
- *
- * The purpose of the application is to show different methods for drawing paths and
- * the times obtained for each method. Lines are used in the construction of the paths
- * but curves and arcs could be used as well.
- *
- * This file contains the methods for the DrawView class, a subclass of view.
- * The important methods to note are the methods to draw the lines.
- *
- * Version: 2.0
- * Author: Ken Anderson, Ken Fromm
- * History:
- * 03-07-91 Added this comment.
- */
-
- #import "DrawView.h"
- #import "DrawViewWraps.h"
- #import <appkit/Button.h>
- #import <appkit/Control.h>
- #import <appkit/Matrix.h>
- #import <appkit/TextField.h>
- #import <dpsclient/wraps.h>
-
- @implementation DrawView
-
- /*
- * A gstate is allocated for this view and the clippling is set to NO. The gstate is used
- * because the view is considered important enough to have one. The clipping is set to NO
- * because it can be expensive. In addition, the lines are constructed to fall entirely within the view.
- * The initialization is done here because the "initailize" method is too late for instance
- * variables that are involved in the display of the view.
- */
- -initFrame:(const NXRect *) frameRect
- {
- [super initFrame:frameRect];
-
- [self allocateGState];
- [self setClipping:NO];
-
- srand(1);
- TotalLines = 0;
-
- PSTrace = Random = NO;
-
- PSWDefs();
-
- return self;
- }
-
- /* Since we allocate a gstate, why not free it. In all likelihood, the gstate is freed anyways.
- * A freeGState method is available, however, so conservative programming dictates that it be used.
- */
- - free
- {
- [self freeGState];
-
- return [super free];
- }
-
- /*
- * This method is used to obtain the ids of the text fields to display the times.
- */
- -setMatrixDisplayTimes:anObject;
- {
- matrixDisplayTimes = anObject;
- return self;
- }
-
- /*
- * These two methods are used to obtain the ids of the line color and line width sliders.
- */
-
- -setSliderColor:anObject
- {
- sliderColor = anObject;
- LineColor = [sliderColor floatValue];
-
- return self;
- }
-
- -setSliderWidth:anObject
- {
- sliderWidth = anObject;
- LineWidth = [sliderWidth floatValue];
-
- return self;
- }
-
- /* Id of total lines text field. */
- -setFieldTotalLines:anObject
- {
- fieldTotalLines = anObject;
-
- return self;
- }
-
- /* Messaged from the button to select the line color and width. The sender is a matrix
- * of buttons (a one cell matrix). The state of the button is used to key the enabling or
- * disabling of the slider controls. At the end, the value of Random is flipped to make it
- * sematically correct. Otherwise, YES would be no and NO would be yes.
- */
- -selectColorWidth:sender
- {
- Random = [[sender selectedCell] state];
- [sliderColor setEnabled:Random];
- [sliderWidth setEnabled:Random];
- Random = !Random;
-
- return self;
- }
-
- /* The sliders message these methods. */
- -changeLineColor:sender
- {
- LineColor = [sender floatValue];
-
- return self;
- }
-
- -changeLineWidth:sender
- {
- LineWidth = [sender floatValue];
-
- return self;
- }
-
- /* This method changes the title of the menu cell according to the
- * value of the PSTrace variable.
- */
- -psTrace:sender
- {
- if (PSTrace == NO)
- [[sender selectedCell] setTitle:"Trace On"];
- else
- [[sender selectedCell] setTitle:"Trace Off"];
- PSTrace = !PSTrace;
-
- return self;
- }
-
- /* Erases the times. Messaged when new lines are made or the lines are cleared. */
- -eraseTimes:sender
- {
- int i;
-
- for (i = 0; i < [matrixDisplayTimes cellCount]; i++)
- [[matrixDisplayTimes cellAt:i :0] setStringValue:""];
-
- return self;
- }
-
- /* This method is messaged by the row of buttons to make lines. The sender is a matrix
- * so the tag of the selected cell is used to obtain the number of lines to make. If the total
- * number of lines exceeds the size of the line arrays, then system beep; otherwise,
- * randomly create the lines and populate the arrays. If Random is set, the line color and
- * width are randomly selected with each line. This is the worst case displaying lines,
- * especially with the OptimizedStroke. If Random is not set then the current values
- * of LineColor and LineWidth are used.
- */
- -makeLines:sender
- {
- int Numsetlines, j;
-
- [self eraseTimes:self];
-
- Numsetlines = [sender selectedTag];
-
- if (TotalLines >= MAXARRAY)
- NXBeep();
- else
- {
- if (TotalLines + Numsetlines > MAXARRAY)
- Numsetlines = MAXARRAY - TotalLines;
-
- for (j = TotalLines; j < TotalLines + Numsetlines; j++)
- {
- X[j] = rand () % ((int)bounds.size.width -4) +2;
- Y[j] = rand () % ((int)bounds.size.height -4) +2;
- X1[j] = rand () % ((int)bounds.size.width -4) +2;
- Y1[j] = rand () % ((int)bounds.size.height -4) +2;
- if (Random)
- {
- C[j] = (rand() % 1000) * 0.001;
- W[j] = (rand() % (MAXWIDTH * 10)) * 0.1;
- }
- else
- {
- C[j] = LineColor;
- W[j] = LineWidth;
- }
- }
-
- TotalLines += Numsetlines;
- [fieldTotalLines setIntValue:TotalLines];
- }
-
- return self;
- }
-
- -clearLines:sender
- {
- TotalLines = 0;
- [fieldTotalLines setIntValue:TotalLines];
-
- [self eraseTimes:self];
-
- return self;
- }
-
- /*
- * Messaged by the method drawing matrix of buttons.
- * Messages display which in turn will message drawSelf::.
- */
- -drawViewOne:sender
- {
- int i, row;
-
- row = [sender selectedRow];
- drawFlags.field = 0x80 >> row;
-
- [self display];
-
- return self;
- }
-
- /* Messaged by "Draw All" button. Messages display which in turn will message drawSelf::. */
- -drawViewAll:sender
- {
- drawFlags.field = DRAWALL;
-
- [self display];
-
- return self;
- }
-
- /*
- * Below are five methods. Each uses a different approach to drawing lines.
- * In some cases, the approaches are similar. Each is annotated.
- */
-
- /* This approach uses the single operator function calls which are quite easy to use because
- * no wraps are necessary. The drawback is that each call is a separate message to
- * the interpreter whereas a wrap is just one message. This approach is fine for simple
- * drawing but wraps should be used for anything over a few lines and repetitions.
- */
- -drawSingleOps:(int) cell
- {
- int ElapsedTime,counter;
-
- [[matrixDisplayTimes cellAt:cell :0] setStringValue:""];
-
- PSWMarkTime(); NXPing ();
- if (PSTrace)
- DPSTraceContext(DPSGetCurrentContext(), YES);
-
- PSsetgray (BGCOLOR);
- PSrectfill (0.0, 0.0, bounds.size.width, bounds.size.height);
- PSsetgray (BGSTRCOLOR);
- PSsetlinewidth (BGSTRWIDTH);
- PSrectstroke (0.0, 0.0, bounds.size.width, bounds.size.height);
-
- for (counter = 0; counter < TotalLines; counter++)
- {
- PSsetlinewidth(W[counter]);
- PSsetgray (C[counter]);
- PSmoveto (X[counter], Y[counter]);
- PSlineto (X1[counter], Y1[counter]);
- PSstroke ();
- }
-
- if (PSTrace)
- DPSTraceContext(DPSGetCurrentContext(), NO);
- PSWReturnTime (&ElapsedTime);
-
- [[matrixDisplayTimes cellAt:cell:0] setIntValue:ElapsedTime];
-
- return self;
- }
-
- /* This approach creates wraps to erase the view and draw the lines. The appropriate
- * arguments are passed to each wrap. Compare this method with the one that follows.
- * The time difference between the two is slight. As in the singler operator approach,
- * this method is fine for drawings that are displayed infrequently. For drawings that
- * are repeated, binding is suggested. See the comments in DrawViewWraps.psw
- * for more information on binding.
- */
- -drawWraps:(int) cell
- {
- int ElapsedTime, counter;
- float ViewRect[4];
-
- [[matrixDisplayTimes cellAt:cell :0] setStringValue:""];
-
- PSWMarkTime (); NXPing ();
- if (PSTrace)
- DPSTraceContext(DPSGetCurrentContext(), YES);
-
- ViewRect[0] = ViewRect[1] = 0.0;
- ViewRect[2] = bounds.size.width;
- ViewRect[3] = bounds.size.height;
- PSWEraseView (BGCOLOR, BGSTRCOLOR, BGSTRWIDTH, ViewRect);
-
- for (counter = 0; counter < TotalLines; counter++)
- {
- PSWDrawLine (W[counter], C[counter], X[counter], Y[counter],
- X1[counter], Y1[counter]);
- }
-
- if (PSTrace)
- DPSTraceContext(DPSGetCurrentContext(), NO);
- PSWReturnTime (&ElapsedTime);
-
- [[matrixDisplayTimes cellAt:cell:0] setIntValue:ElapsedTime];
-
- return self;
- }
-
- /* The wrap calls used in this approach make use of definitions contained in PSWDefs().
- * The definitions bind their operators which simply means that the name lookup occurs
- * at definition time only once rather than with each interpretation of the definition (which
- * can occur many times). This approach is recommended for more than the simplest
- * drawing. Drawings with lines that are of uniform line color and width might benefit
- * from the opitimized stroke method. Random line colors and widths show this to be
- * the fastest.
- */
- -drawWrapsBind:(int) cell
- {
- int ElapsedTime, counter;
- float ViewRect[4];
-
- [[matrixDisplayTimes cellAt:cell :0] setStringValue:""];
-
- PSWMarkTime (); NXPing ();
- if (PSTrace)
- DPSTraceContext(DPSGetCurrentContext(), YES);
-
- ViewRect[0] = ViewRect[1] = 0.0;
- ViewRect[2] = bounds.size.width;
- ViewRect[3] = bounds.size.height;
- PSWEraseViewBind (BGCOLOR, BGSTRCOLOR, BGSTRWIDTH, ViewRect);
-
- for (counter = 0; counter < TotalLines; counter++)
- {
- PSWDrawLineBind (W[counter], C[counter], X[counter], Y[counter],
- X1[counter], Y1[counter]);
- }
-
- if (PSTrace)
- DPSTraceContext(DPSGetCurrentContext(), NO);
- PSWReturnTime (&ElapsedTime);
-
- [[matrixDisplayTimes cellAt:cell:0] setIntValue:ElapsedTime];
-
- return self;
- }
-
-
- /* This approach is uses the interpreter to loop through the array and draw the
- * lines. As a result, a good deal of stack manipulation must be performed in the wrap.
- * The timing results show this to be a poor approach. Not recommended at this time.
- */
- -drawWrapsRepeat:(int) cell
- {
- int ElapsedTime;
- float ViewRect[4];
-
- [[matrixDisplayTimes cellAt:cell :0] setStringValue:""];
-
- PSWMarkTime (); NXPing ();
- if (PSTrace)
- DPSTraceContext(DPSGetCurrentContext(), YES);
-
- ViewRect[0] = ViewRect[1] = 0.0;
- ViewRect[2] = bounds.size.width;
- ViewRect[3] = bounds.size.height;
- PSWEraseViewBind (BGCOLOR, BGSTRCOLOR, BGSTRWIDTH, ViewRect);
- PSWDrawLineRepeatBind (W, C, X, Y, X1, Y1, TotalLines);
-
- if (PSTrace)
- DPSTraceContext(DPSGetCurrentContext(), NO);
- PSWReturnTime (&ElapsedTime);
-
- [[matrixDisplayTimes cellAt:cell:0] setIntValue:ElapsedTime];
-
- return self;
- }
-
- /* This approach builds the path with successive moveto's and lineto's until the end of the
- * array or a change in line color or width occurs. At this point, the path is stroked. The
- * timing studies show this to be an efficient approach when the line color and width appear
- * in non-random order. As a result, this approach might be used to display a grid or other
- * similar uniform drawing. NOTE: as of this writing the path stack contains a 1500 point limit.
- * Therefore, a check should be included to stroke if the limit has been reached. Otherwise
- * a limiterror may occur.
- */
- -drawOptimizedStroke:(int) cell
- {
- int ElapsedTime,counter;
- float ViewRect[4];
-
- [[matrixDisplayTimes cellAt:cell :0] setStringValue:""];
-
- PSWMarkTime (); NXPing ();
- if (PSTrace)
- DPSTraceContext(DPSGetCurrentContext(), YES);
-
- ViewRect[0] = ViewRect[1] = 0.0;
- ViewRect[2] = bounds.size.width;
- ViewRect[3] = bounds.size.height;
- PSWEraseViewBind (BGCOLOR, BGSTRCOLOR, BGSTRWIDTH, ViewRect);
-
- for (counter = 0; counter < TotalLines; counter++)
- {
- PSWMakeLineBind (X[counter], Y[counter], X1[counter], Y1[counter]);
-
- if (counter >= TotalLines -1 ||
- C[counter] != C[counter + 1] ||
- W[counter] != W[counter+1])
- {
- PSWStrokeLineBind (W[counter], C[counter]);
- }
- }
-
- if (PSTrace)
- DPSTraceContext(DPSGetCurrentContext(), NO);
- PSWReturnTime (&ElapsedTime);
-
- [[matrixDisplayTimes cellAt:cell:0] setIntValue:ElapsedTime];
-
- return self;
- }
-
- /* Messaged by the "display" method. This method should not be called directly. */
- -drawSelf:(NXRect *)r :(int) count
- {
- float ViewRect[4];
-
- ViewRect[0] = ViewRect[1] = 0.0;
- ViewRect[2] = bounds.size.width;
- ViewRect[3] = bounds.size.height;
- PSWEraseViewBind (BGCOLOR, BGSTRCOLOR, BGSTRWIDTH, ViewRect);
-
- if (drawFlags.flags.singleops)
- [self drawSingleOps:0];
- if (drawFlags.flags.wraps)
- [self drawWraps:1];
- if (drawFlags.flags.bind)
- [self drawWrapsBind:2];
- if (drawFlags.flags.repeat)
- [self drawWrapsRepeat:3];
- if (drawFlags.flags.optimized)
- [self drawOptimizedStroke:4];
-
- return self;
- }
-
- @end
-