Annotation of Examples/AppKit/Draw/Polygon.m, revision 1.1

1.1     ! root        1: #import "draw.h"
        !             2: 
        !             3: /*
        !             4:  * This line is just a stub to get genstrings to generate
        !             5:  * a .strings file entry for the name of this type of Graphic.
        !             6:  * The name is used in the Undo New <Whatever> menu item.
        !             7:  *
        !             8:  * NXLocalString("Polygon", NULL, "Name of the tool that draws polygons, i.e., the %s of the New %s operation.")
        !             9:  */
        !            10: 
        !            11: @implementation Polygon
        !            12: 
        !            13: + initialize
        !            14: /*
        !            15:  * This bumps the class version so that we can compatibly read
        !            16:  * old Graphic objects out of an archive.
        !            17:  */
        !            18: {
        !            19:     [Polygon setVersion:1];
        !            20:     return self;
        !            21: }
        !            22: 
        !            23: + cursor
        !            24: /*
        !            25:  * The cursor inherited from Scribble is a pencil.
        !            26:  * That's not very appropriate, so CrossCursor is used instead.
        !            27:  */
        !            28: {
        !            29:     return CrossCursor;
        !            30: }
        !            31: 
        !            32: static void getRectFromBBox(NXRect *r, float x1, float y1, float x2, float y2)
        !            33: /*
        !            34:  * Takes two points (x1, y1) and (x2, y2) and updates the r rect to
        !            35:  * equal that bounding box.
        !            36:  */
        !            37: {
        !            38:     r->size.width = x1 - x2;
        !            39:     r->size.height = y1 - y2;
        !            40:     if (r->size.width < 0.0) {
        !            41:        r->origin.x = x2 + r->size.width;
        !            42:        r->size.width = 0.0 - r->size.width;
        !            43:     } else r->origin.x = x2;
        !            44:     if (r->size.height < 0.0) {
        !            45:        r->origin.y = y2 + r->size.height;
        !            46:        r->size.height = 0.0 - r->size.height;
        !            47:     } else r->origin.y = y2;
        !            48: }
        !            49: 
        !            50: /*
        !            51:  * This class probably is probably not implemented in the optimal way,
        !            52:  * but it shows how an existing implementation (i.e. Scribble) can be
        !            53:  * used to implement some other object.
        !            54:  *
        !            55:  * This method creates a polygon.  The user must drag out each segment of
        !            56:  * the polygon clicking to make a corner, finally ending with a double click.
        !            57:  *
        !            58:  * Start by getting the starting point of the polygon from the mouse down
        !            59:  * event passed in the event parameter (if the ALT key is not down, then we
        !            60:  * will close the path even if the user does not explicitly do so).
        !            61:  *
        !            62:  * Next, we initialize a chunk of space for the points to be stored in
        !            63:  * and initialize point[0] and point[1] to be the starting point (since the
        !            64:  * first thing in the userpath is a moveto).  We also initialize our bounding
        !            65:  * box to contain only that point.
        !            66:  *
        !            67:  * p represents the last point the user moved the mouse to.  We initialize it
        !            68:  * to start before entering the tracking loop.
        !            69:  *
        !            70:  * Inside the loop, last represents the last point the user confirmed (by
        !            71:  * clicking) as opposed to p, the last point the user moved to.  We update
        !            72:  * last every time we start the segment tracking loop (the inner,
        !            73:  * while (event->type != NX_MOUSEUP) loop).
        !            74:  *
        !            75:  * In the segment tracking loop, r represents the rectangle which must be
        !            76:  * redrawn to get rid of the last time we drew the segment we are currently
        !            77:  * tracking.  After we [view drawSelf:&r :1] to clear out the last segment,
        !            78:  * we recalculate the value of r for the next time around the loop.  Finally,
        !            79:  * we draw ourselves (i.e. all the other segments besides the one we are
        !            80:  * currently tracking) and then draw the segment we are currently tracking.
        !            81:  *
        !            82:  * After tracking the segment, we check to see if we are done.
        !            83:  * We are finished if any of the following are true:
        !            84:  *    1. The last segment the user created was smaller than a gridSpacing.
        !            85:  *    2. The user clicked on the starting point (thereby closing the path).
        !            86:  *    3. The mouse down is outside the view's bounds.
        !            87:  *    4. A kit defined or system defined event comes through.
        !            88:  *
        !            89:  * If we are not done (or we need to close the path), then we store the
        !            90:  * new point pair into points (reallocating our points
        !            91:  * and userPathOps arrays if we are out of room).  We then update our bounding
        !            92:  * box to reflect the new point and update our bounds to equal our bounding
        !            93:  * box.  If we aren't done, we look for the next mouse down to begin the
        !            94:  * tracking of another segment.
        !            95:  *
        !            96:  * After we are finished with all segments, we check to be sure that we have
        !            97:  * at least two segments (one segment is a line, not a polygon).  If the
        !            98:  * path is closed, then we need at least three segments.  If we have the
        !            99:  * requisite number of segments, then we reallocate our arrays to fit exactly
        !           100:  * our number of points and return YES.  Otherwise, we free the storage of
        !           101:  * those arrays and clean up any drawing we did and return NO.
        !           102:  */
        !           103: 
        !           104: #define POLYGON_MASK (NX_MOUSEDRAGGEDMASK|NX_MOUSEUPMASK)
        !           105: #define END_POLYGON_MASK (NX_KITDEFINEDMASK|NX_MOUSEDOWNMASK|NX_SYSDEFINEDMASK)
        !           106: 
        !           107: - (BOOL)create:(NXEvent *)event in:view
        !           108: {
        !           109:     float *pptr;
        !           110:     NXRect r, viewBounds;
        !           111:     NXPoint start, last, p;
        !           112:     Window *window = [view window];
        !           113:     BOOL closepath, done = NO, resend = NO;
        !           114:     float grid = (float)[view gridSpacing];
        !           115:     int windowNum = event->window, arrow = 0;
        !           116: 
        !           117:     if (![view gridIsEnabled])
        !           118:         grid = 1.0;
        !           119: 
        !           120:     gFlags.initialized = YES;
        !           121:     if (gFlags.arrow && gFlags.arrow != ARROW_AT_START) {
        !           122:        arrow = gFlags.arrow;
        !           123:        gFlags.arrow = (gFlags.arrow == ARROW_AT_END) ? 0 : ARROW_AT_START;
        !           124:     }
        !           125: 
        !           126:     start = event->location;
        !           127:     [view convertPoint:&start fromView:nil];
        !           128:     [view grid:&start];
        !           129: 
        !           130:     [view getVisibleRect:&viewBounds];
        !           131: 
        !           132:     closepath = (event->flags & NX_ALTERNATEMASK) ? NO : YES;
        !           133: 
        !           134:     length = 0;
        !           135:     [self allocateChunk];
        !           136:     pptr = points;
        !           137:     *pptr++ = bbox[0] = bbox[2] = start.x;
        !           138:     *pptr++ = bbox[1] = bbox[3] = start.y;
        !           139:     userPathOps[0] = dps_moveto;
        !           140: 
        !           141:     [view lockFocus];
        !           142: 
        !           143:     [self setLineColor];
        !           144:     PSsetlinewidth(linewidth);
        !           145: 
        !           146:     p = start;
        !           147:     event = [NXApp getNextEvent:POLYGON_MASK];
        !           148:     while (!done) {
        !           149:        last = p;
        !           150:        if (event->type == NX_MOUSEDOWN) {
        !           151:            if (event->data.mouse.click > 1) {
        !           152:                done = YES;
        !           153:                [NXApp getNextEvent:NX_MOUSEUPMASK];
        !           154:            } else if (event->window != windowNum) {
        !           155:                done = YES;
        !           156:                resend = YES;
        !           157:            } else {
        !           158:                p = event->location;
        !           159:                [view convertPoint:&p fromView:nil];
        !           160:                done = !NXMouseInRect(&p, &viewBounds, NO);
        !           161:                resend = YES;
        !           162:            }
        !           163:        } else if (event->type == NX_KITDEFINED ||
        !           164:                   event->type == NX_SYSDEFINED) {
        !           165:            done = YES;
        !           166:            resend = YES;
        !           167:        }
        !           168:        if (!done) {
        !           169:            while (event->type != NX_MOUSEUP) {
        !           170:                p = event->location;
        !           171:                [view convertPoint:&p fromView:nil];
        !           172:                [view grid:&p];
        !           173:                [view drawSelf:&r :1];
        !           174:                getRectFromBBox(&r, p.x, p.y, last.x, last.y);
        !           175:                [view scrollPointToVisible:&p];
        !           176:                NXInsetRect(&r, -2.0, -2.0);
        !           177:                [self draw];
        !           178:                PSmoveto(last.x, last.y);
        !           179:                PSlineto(p.x, p.y);
        !           180:                PSstroke();
        !           181:                [window flushWindow];
        !           182:                event = [NXApp getNextEvent:POLYGON_MASK];
        !           183:            }
        !           184:            if (fabs(p.x-start.x) <= grid && fabs(p.y-start.y) <= grid) {
        !           185:                done = YES;
        !           186:                closepath = YES;
        !           187:            }
        !           188:        }
        !           189:        if (!done || (closepath && length > 1)) {
        !           190:            if (done) p = start;
        !           191:            length++;
        !           192:            if (!(length % CHUNK_SIZE)) [self allocateChunk];
        !           193:            *pptr++ = p.x - last.x;
        !           194:            *pptr++ = p.y - last.y;
        !           195:            if (p.x < bbox[0]) bbox[0] = p.x;
        !           196:            if (p.x > bbox[2]) bbox[2] = p.x;
        !           197:            if (p.y < bbox[1]) bbox[1] = p.y;
        !           198:            if (p.y > bbox[3]) bbox[3] = p.y;
        !           199:            getRectFromBBox(&bounds, bbox[0], bbox[1], bbox[2], bbox[3]);
        !           200:            if (!done) event = [NXApp getNextEvent:END_POLYGON_MASK];
        !           201:        }
        !           202:     }
        !           203: 
        !           204:     [view unlockFocus];
        !           205: 
        !           206:     if (resend) DPSPostEvent(event, 1);
        !           207:     if (arrow) gFlags.arrow = arrow;
        !           208: 
        !           209:     if (length > (closepath ? 2 : 1)) {
        !           210:        points = NX_ZONEREALLOC([self zone], points, float, (length+1) << 1);
        !           211:        userPathOps = NX_ZONEREALLOC([self zone], userPathOps, char, length+1);
        !           212:        return YES;
        !           213:     } else {
        !           214:        NX_FREE(points); points = NULL;
        !           215:        NX_FREE(userPathOps); userPathOps = NULL;
        !           216:        [view drawSelf:[self getExtendedBounds:&r] :1];
        !           217:        return NO;
        !           218:     }
        !           219: }
        !           220: 
        !           221: - (Graphic *)colorAcceptorAt:(const NXPoint *)point
        !           222: {
        !           223:     if ([self hit:point]) return self;
        !           224:     return nil;
        !           225: }
        !           226: 
        !           227: @end
        !           228: 

unix.superglobalmegacorp.com

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