Annotation of Examples/AppKit/Lines/LinesView.m, revision 1.1

1.1     ! root        1: /*
        !             2:  * LinesView.m, a small sample view for showing timed entries & userpaths.
        !             3:  * Author: Ali T. Ozer, NeXT Computer, Inc.
        !             4:  * Written March 19, 1989.
        !             5:  * Updated for 2.0 Oct 16, 1990 by Jayson Adams to use UserPath.[hm].
        !             6:  * Updated for 3.0 March 24, 1992 by Ali Ozer
        !             7:  *
        !             8:  * You may freely copy, distribute and reuse the code in this example.
        !             9:  * NeXT disclaims any warranty of any kind, expressed or implied, as to its
        !            10:  * fitness for any particular use.
        !            11:  *
        !            12:  * LinesView draws a number of connected lines whose endpoints bounce around
        !            13:  * randomly within the bounds of the view. The endpoints are stored in
        !            14:  * an data array which is passed to PostScript as a user path. The
        !            15:  * animation is performed by calling the "animate" method as often as
        !            16:  * possible through a timed entry.
        !            17:  */
        !            18: 
        !            19: #import <appkit/appkit.h>
        !            20: #import <libc.h>                // For random(), etc...
        !            21: #import <dpsclient/wraps.h>    // For PS and DPS function prototypes
        !            22: #import "LinesView.h"
        !            23: 
        !            24: #define RANDINT(n) (random() % (n+1))          // Return random integer 0..n
        !            25: 
        !            26: #define XVEL corners[count].xVel  // Some slimy shortcuts, asuuming we're
        !            27: #define YVEL corners[count].yVel  // using "count" as corner counter.
        !            28: #define XLOC corners[count].xLoc
        !            29: #define YLOC corners[count].yLoc
        !            30: 
        !            31: #define MAXVEL 12              // Maximum velocity of corners
        !            32: 
        !            33: 
        !            34: @implementation LinesView
        !            35: 
        !            36: - initFrame:(NXRect *)rect
        !            37: {
        !            38:     [super initFrame:rect];
        !            39: 
        !            40:   /* create a user path */
        !            41:     userPath = newUserPath();
        !            42:     
        !            43:     running = NO;
        !            44: 
        !            45:     return self;
        !            46: }
        !            47: 
        !            48: - free
        !            49: {
        !            50:   /* be sure to stop the timed entry */
        !            51:     if (running) {
        !            52:        DPSRemoveTimedEntry(linesTimedEntry);
        !            53:     }
        !            54:     freeUserPath(userPath);
        !            55:     
        !            56:     return [super free];
        !            57: }
        !            58: 
        !            59: void DrawIt(DPSTimedEntry te, double timeNow, void *data)
        !            60: {
        !            61:   /* we set data to self so we can call this method from the timed entry */
        !            62:     [(id)data animate];
        !            63: }
        !            64: 
        !            65: - toggleRun:sender
        !            66: {
        !            67:   /* start or stop the timed entry (we're called by a two-state button) */
        !            68:     if (running) {
        !            69:        DPSRemoveTimedEntry(linesTimedEntry);
        !            70:        running = NO;
        !            71:     } else {
        !            72:       /* Call the DrawIt() function as often as possible... */
        !            73:        linesTimedEntry = DPSAddTimedEntry(0.0, &DrawIt, self,
        !            74:                                           NX_BASETHRESHOLD);
        !            75:        running = YES;
        !            76:     }
        !            77: 
        !            78:     return self;
        !            79: }
        !            80: 
        !            81: /*
        !            82:  * This method should be connected to a UI object capable of generating
        !            83:  * int numbers. Note that to successfully detect the initial value of this
        !            84:  * slider as set through IB, we also declare an outlet named "numberOfCorners,"
        !            85:  * and connect it to this UI object. Thus this method (setNumberOfCorners:)
        !            86:  * gets called when the .nib is being loaded, and we can detect the
        !            87:  * initial value of the slider.  Because at initialization time the window
        !            88:  * isn't up yet, we won't really update the display at that time, even though
        !            89:  * display is called below.
        !            90:  */
        !            91: - setNumberOfCorners:sender
        !            92: {
        !            93:     int           count;
        !            94:     int    oldNumCorners = numCorners;
        !            95: 
        !            96:   /* set the number of corners based on the "corners" slider */
        !            97:     numCorners = MIN(MAXNUMCORNERS, MAX([sender intValue], MINNUMCORNERS));
        !            98: 
        !            99:   /* set the new corner starting positions & velocities */
        !           100:     for (count = oldNumCorners; count < numCorners; count++) {
        !           101:       XLOC = (int)(bounds.size.width) / 2;      
        !           102:       YLOC = (int)(bounds.size.height) / 2;      
        !           103:       XVEL = (RANDINT(4) ? 1 : -1) * (1 + RANDINT(MAXVEL/2));
        !           104:       YVEL = (RANDINT(4) ? 1 : -1) * (1 + RANDINT(MAXVEL/2));
        !           105:     }
        !           106:     [self display];
        !           107: 
        !           108:     return self;
        !           109: }
        !           110: 
        !           111: - drawSelf:(const NXRect *)rects :(int)rectCount
        !           112: {
        !           113:     int          count;
        !           114:     
        !           115:   /* fill with the background color */
        !           116:     NXEraseRect(&bounds);
        !           117:     
        !           118:     PSsetgray(NX_BLACK);
        !           119:     PSsetlinewidth(0.0);
        !           120: 
        !           121:   /* "plot" the points */
        !           122:     beginUserPath(userPath, NO);
        !           123:     for (count = 0; count < numCorners; count++) {
        !           124:        if (count) {
        !           125:            UPlineto(userPath, XLOC, YLOC);
        !           126:        } else {
        !           127:            UPmoveto(userPath, XLOC, YLOC);
        !           128:        }
        !           129:     }
        !           130:     closePath(userPath);
        !           131:     
        !           132:   /* draw it */
        !           133:     endUserPath(userPath, dps_ustroke);
        !           134:     sendUserPath(userPath);
        !           135:     
        !           136:     return self;
        !           137: }
        !           138: 
        !           139: - animate
        !           140: /*
        !           141:  * Lines is an unusual animation program in that it runs untimed; that is,
        !           142:  * it runs as fast as the CPU will allow, and it doesn't care that on faster
        !           143:  * CPUs the animation will run faster. An animation or game application
        !           144:  * will usually want to limit to frame rate to a value (for instance, 30
        !           145:  * frames a second), and on hardware not capable of that rate, end up doing
        !           146:  * the best it can. Such an application would also look at the time
        !           147:  * that actually passed between frames and increment the animation or game play
        !           148:  * accordingly. (See the sources to the BreakApp example on how it does it
        !           149:  * animation timing. BreakApp also allocates a graphic state for its view so
        !           150:  * that the lock/unlockFocus is faster.)
        !           151:  *
        !           152:  * Lines accomplishes its goal of running as fast as possible by creating
        !           153:  * a timed entry with a 0.0 second period. This means that the timed entry
        !           154:  * will fire and this method (animate) will be called as soon as possible.
        !           155:  * To make things even faster, we stay in this method until some event comes
        !           156:  * along. Staying in this method has the advantage that we do not need to
        !           157:  * lock or unlockFocus every frame. Of course, this only works as desired
        !           158:  * if the timed entry was placed with a period of 0.0 seconds.
        !           159:  * 
        !           160:  * If an event comes along, we return from this method and process the event.
        !           161:  * Then, unless the user stopped the animation, the timed entry brings us
        !           162:  * right back in to continue with the animation.
        !           163:  *
        !           164:  * Lines uses a buffered output window as a means to fake double-buffered
        !           165:  * animation. The current frame is drawn directly into the window. However,
        !           166:  * because the window is buffered, the drawing goes to the backing store,
        !           167:  * and not the screen.  Only when the frame is complete does Lines flush the
        !           168:  * window contents to the screen; this process is fast and provides a
        !           169:  * flicker-free update.  The next frame is then drawn into the backing store,
        !           170:  * and the cycle continues.
        !           171:  */
        !           172: {
        !           173:     int count;  
        !           174:     NXEvent dummyEvent;  // For peeking at the event queue. 
        !           175:     
        !           176:     [self lockFocus];
        !           177:     
        !           178:     do {
        !           179:       /* move all the corners... */
        !           180:        for (count = 0; count < numCorners; count++) {
        !           181:            XLOC += XVEL;
        !           182:            YLOC += YVEL;
        !           183: 
        !           184:          /*
        !           185:           * Detect collision with sides; if we collide, bounce back in some
        !           186:           * random fashion.
        !           187:           */
        !           188:            if (XLOC >= bounds.size.width) {
        !           189:                XLOC = bounds.size.width-1;
        !           190:                XVEL = -1-RANDINT(MAXVEL);
        !           191:            } else if (XLOC < bounds.origin.x) {
        !           192:                XLOC = bounds.origin.x;
        !           193:                XVEL = 1+RANDINT(MAXVEL);
        !           194:            }
        !           195:            if (YLOC >= bounds.size.height) {
        !           196:                YLOC = bounds.size.height-1;
        !           197:                YVEL = -1-RANDINT(MAXVEL);
        !           198:            } else if (YLOC < bounds.origin.y) {
        !           199:                YLOC = bounds.origin.y;
        !           200:                YVEL = 1+RANDINT(MAXVEL);
        !           201:            }
        !           202:        }
        !           203: 
        !           204:       /* draw our path and flush to the screen */
        !           205:        [self drawSelf:&bounds :1];
        !           206:        [window flushWindow];
        !           207:        
        !           208:     } while ([NXApp peekNextEvent:NX_ALLEVENTS
        !           209:                    into:&dummyEvent 
        !           210:                    waitFor:0.0
        !           211:                    threshold:NX_BASETHRESHOLD] == NULL);
        !           212: 
        !           213:     [self unlockFocus];
        !           214: 
        !           215:     return self;
        !           216: }
        !           217: 
        !           218: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.