Annotation of Examples/AppKit/CompositeLab/CompositeView.m, revision 1.1

1.1     ! root        1: /*
        !             2: 
        !             3:  You may freely copy, distribute and reuse the code in this example.
        !             4:  NeXT disclaims any warranty of any kind, expressed or implied,
        !             5:  as to its fitness for any particular use.
        !             6: 
        !             7:  CompositeView implements a view with three horizontal, equal-sized areas.
        !             8:  The left-most area is the "source," the middle area is the "destination,"
        !             9:  and the right-most area is the "result." CompositeView assures that the
        !            10:  contents of the result area is always generated by compositing the other
        !            11:  two areas using the compositing mode set in the setOperator: method.
        !            12:  It is also possible to change the contents, color, and alpha of the
        !            13:  source and destination areas; see the methods setSourceColor:, 
        !            14:  setSourceAlpha:, etc.
        !            15: 
        !            16:  CompositeView also demonstrates some of the drag & drop features of
        !            17:  NeXTSTEP 3.0 by acting as a destination for colors & images.
        !            18: 
        !            19:  CompositeView written by Bruce Blumberg and Ali Ozer.
        !            20: 
        !            21:  Color support, NXColorPanel, NXColorWells, and NXImage added during 1990 by Ali.
        !            22:  Color dragging support added Feb 9, 1992, by Ali.
        !            23:  Image dragging support added May 27, 1992, by Ali.
        !            24:  Image dragging problem fixed Sep 29, 1992 (for 3.1), by Ali. See QAP appkit.878.
        !            25: 
        !            26: */
        !            27: 
        !            28: #import <appkit/appkit.h>
        !            29: #import "CompositeView.h"
        !            30: 
        !            31: 
        !            32: @implementation CompositeView
        !            33: 
        !            34: // The possible draw modes for the source.
        !            35: 
        !            36: #define TRIANGLE 0
        !            37: #define CIRCLE   1
        !            38: #define DIAMOND  2
        !            39: #define HEART    3
        !            40: #define FLOWER   4
        !            41: #define CUSTOM   5
        !            42: 
        !            43: // initFrame: creates the view, initializes the rectangles that define the
        !            44: // three areas described above, and creates the bitmaps used for rendering the
        !            45: // source and destination bitmaps. newFrame: is a convenience method.
        !            46: 
        !            47: - initFrame:(const NXRect *)tF
        !            48: {
        !            49:     // Initialize the view
        !            50:     [super initFrame:tF];
        !            51: 
        !            52:     // Make rectangles for source, destination and result
        !            53:     sRect = bounds;
        !            54:     sRect.size.width /= 3.0;
        !            55:     dRect = sRect;
        !            56:     dRect.origin.x = sRect.size.width;
        !            57:     rRect = dRect;
        !            58:     rRect.origin.x = dRect.origin.x + dRect.size.width;
        !            59: 
        !            60:     // Create source, destination, and result images.
        !            61: 
        !            62:     [(source = [[NXImage allocFromZone:[self zone]] initSize:&sRect.size])
        !            63:        useDrawMethod:@selector(drawSource:) inObject:self];
        !            64:     [source setBackgroundColor:NX_COLORCLEAR];
        !            65:     
        !            66:     [(destination = [[NXImage allocFromZone:[self zone]] initSize:&dRect.size])
        !            67:        useDrawMethod:@selector(drawDestination:) inObject:self];
        !            68:     [destination setBackgroundColor:NX_COLORCLEAR];
        !            69: 
        !            70:     [(result = [[NXImage allocFromZone:[self zone]] initSize:&dRect.size])
        !            71:        useDrawMethod:@selector(drawResult:) inObject:self];
        !            72:     [result setBackgroundColor:NX_COLORCLEAR];
        !            73: 
        !            74:     // Set the default operator and source picture. No need to set the default
        !            75:     // colors; these are read from the .nib file when the outlets to the wells
        !            76:     // are estanblished.
        !            77: 
        !            78:     operator = NX_COPY;
        !            79:     sourcePicture = TRIANGLE;
        !            80: 
        !            81:     // Tell the application that alpha should be allowed in the color panel
        !            82:     // and dragged colors. Most apps do not want to bother with this.
        !            83: 
        !            84:     [NXApp setImportAlpha:YES];
        !            85: 
        !            86:     // Finally, register for dragging colors and files. 
        !            87: 
        !            88:     [self registerForDraggedTypes:&NXColorPboardType count:1];
        !            89:     [self registerForDraggedTypes:&NXFilenamePboardType count:1];
        !            90: 
        !            91:     return self;
        !            92: }
        !            93: 
        !            94: // Get handles to the wells and read their initial colors.
        !            95: 
        !            96: - setSourceColorWell:anObject
        !            97: {
        !            98:     sourceColorWell = anObject;
        !            99:     sourceColor = [anObject color];
        !           100:     return self;
        !           101: }
        !           102: 
        !           103: - setDestColorWell:anObject
        !           104: {
        !           105:     destColorWell = anObject;
        !           106:     destColor = [anObject color];
        !           107:     return self;
        !           108: }
        !           109: 
        !           110: - setBackColorWell:anObject
        !           111: {
        !           112:     backColorWell = anObject;
        !           113:     backgroundColor = [anObject color];
        !           114:     return self;
        !           115: }
        !           116: 
        !           117: // drawSource creates the source image in the source bitmap. Note that
        !           118: // drawSource does not render in the view; it renders in the bitmap only.
        !           119: 
        !           120: - drawSource:image
        !           121: {      
        !           122:     NXPoint zeroPoint = {0.0, 0.0};
        !           123: 
        !           124:     NXSetColor(sourceColor);
        !           125:     PSnewpath();
        !           126:     switch (sourcePicture) {
        !           127: 
        !           128:        case TRIANGLE: 
        !           129:            PSmoveto (0.0, 0.0);
        !           130:            PSlineto (0.0, sRect.size.height);
        !           131:            PSlineto (sRect.size.width, sRect.size.height);
        !           132:            break;
        !           133: 
        !           134:        case CIRCLE:
        !           135:            PSscale (sRect.size.width, sRect.size.height);
        !           136:            PSarc (0.5, 0.5, 0.4, 0.0, 360.0);  // diameter is 80% of area
        !           137:            break;
        !           138: 
        !           139:        case DIAMOND:
        !           140:            PSmoveto (0.0, sRect.size.height / 2.0);
        !           141:            PSlineto (sRect.size.width / 2.0, 0.0);
        !           142:            PSlineto (sRect.size.width, sRect.size.height / 2.0);
        !           143:            PSlineto (sRect.size.width / 2.0, sRect.size.height);
        !           144:            break;
        !           145: 
        !           146:        case HEART:
        !           147:            PSscale (sRect.size.width, sRect.size.height);
        !           148:            PSmoveto (0.5, 0.5);
        !           149:            PScurveto (0.3, 1.0, 0.0, 0.5, 0.5, 0.1);
        !           150:            PSmoveto (0.5, 0.5);                        
        !           151:            PScurveto (0.7, 1.0, 1.0, 0.5, 0.5, 0.1);  
        !           152:            break;
        !           153: 
        !           154:        case FLOWER:
        !           155:            PSscale (sRect.size.width, sRect.size.height);
        !           156:            PStranslate (0.5, 0.5);
        !           157:            PSmoveto (0.0, 0.0); 
        !           158:             {int cnt;
        !           159:             for (cnt = 0; cnt < 6; cnt++) {
        !           160:                PSrotate (60.0);
        !           161:                PScurveto (0.4, 0.5, -0.4, 0.5, 0.0, 0.0);
        !           162:             }
        !           163:            }
        !           164:            break;
        !           165: 
        !           166:         case CUSTOM:
        !           167:            if (!customImage) {
        !           168:                customImage = [[NXImage allocFromZone:[self zone]] 
        !           169:                                initSize:&rRect.size];
        !           170:                [customImage setScalable:YES];
        !           171:                [customImage useFromSection:"DefaultCustomImage.eps"];
        !           172:            }
        !           173:            [customImage composite:NX_SOVER toPoint:&zeroPoint];
        !           174:            break;
        !           175:  
        !           176:        default:
        !           177:            break;
        !           178:     }
        !           179:     PSclosepath();
        !           180:     PSfill();
        !           181: 
        !           182:     return self;
        !           183: }
        !           184: 
        !           185: // drawDestination creates the destination image in the destination bitmap. 
        !           186: // Like drawSource, drawDestination only draws in the bitmap, not the view.
        !           187: 
        !           188: - drawDestination:image
        !           189: {
        !           190:     NXSetColor(destColor);
        !           191:     PSnewpath();
        !           192:     PSmoveto(dRect.size.width, 0.0);
        !           193:     PSlineto(dRect.size.width, dRect.size.height);
        !           194:     PSlineto(0.0, dRect.size.height);
        !           195:     PSclosepath();
        !           196:     PSfill();
        !           197:     return self;
        !           198: }
        !           199: 
        !           200: // drawResults creates the resulting image, formed by compositing the
        !           201: // source image after the destination image with the specified operator. 
        !           202: 
        !           203: - drawResult:image
        !           204: {
        !           205:     NXPoint zeroPoint = {0.0, 0.0};
        !           206: 
        !           207:     [destination composite:NX_COPY toPoint:&zeroPoint];
        !           208:     [source composite:operator toPoint:&zeroPoint];
        !           209:     return self;
        !           210: }
        !           211:     
        !           212: // setSourcePicture allows setting the picture to be drawn in the source
        !           213: // bitmap. Buttons connected to this method should have tags that are 
        !           214: // set to the various possible pictures (see the "#define"s, above).
        !           215: //
        !           216: // After setting the sourcePicture instance variable, setSourcePicture redraws
        !           217: // the bitmap and updates the view to reflect the new configuration.
        !           218: 
        !           219: - setSourcePicture:sender
        !           220: {
        !           221:     sourcePicture = [sender selectedTag];
        !           222:     [source recache];
        !           223:     [result recache];
        !           224:     [self display];
        !           225:     return self;
        !           226: }
        !           227: 
        !           228: - (BOOL)changeCustomImageTo:newImage
        !           229: {
        !           230:     if (newImage) {
        !           231:        [newImage setSize:&rRect.size];
        !           232:        [newImage setScalable:YES];
        !           233:        if ([newImage lockFocus]) {     // Is this a good image indeed?
        !           234:            [newImage unlockFocus];
        !           235:            [customImage free];
        !           236:            customImage = newImage;
        !           237:            if (sourcePicture != CUSTOM) {
        !           238:                sourcePicture = CUSTOM;
        !           239:                [sourcePictureMatrix selectCellWithTag:CUSTOM];
        !           240:            }
        !           241:            [source recache];
        !           242:            [result recache];
        !           243:            [self display];
        !           244:            return YES;
        !           245:        }
        !           246:     }
        !           247:     return NO;
        !           248: }
        !           249: 
        !           250: - changeCustomImage:sender
        !           251: {
        !           252:     if ([[OpenPanel new] runModalForTypes:[NXImage imageFileTypes]]) {
        !           253:        const char *fileName = [[OpenPanel new] filename];
        !           254:        (void)[self changeCustomImageTo:[[NXImage allocFromZone:[self zone]] initFromFile:fileName]];
        !           255:     }
        !           256: 
        !           257:     return self;
        !           258: }
        !           259: 
        !           260: // The following methods change the colors and update
        !           261: // the source or destination bitmaps and the view to reflect the change.
        !           262: // They should typically be called by a control capable of returning
        !           263: // a color (for instance, an NXColorWell).
        !           264: 
        !           265: - changeSourceColor:sender
        !           266: {
        !           267:     [self changeSourceColorTo:[sender color] andDisplay:YES];
        !           268:     return self;
        !           269: }
        !           270: 
        !           271: - changeDestColor:sender
        !           272: {
        !           273:     [self changeDestColorTo:[sender color] andDisplay:YES];
        !           274:     return self;
        !           275: }
        !           276: 
        !           277: - changeBackgroundColor:sender
        !           278: {
        !           279:     [self changeBackgroundColorTo:[sender color] andDisplay:YES];
        !           280:     return self;
        !           281: }
        !           282: 
        !           283: - (void)changeSourceColorTo:(NXColor)color andDisplay:(BOOL)flag
        !           284: {
        !           285:     if (!NXEqualColor(sourceColor, color)) {
        !           286:        sourceColor = color;
        !           287:        [source recache];
        !           288:        [result recache];
        !           289:        if (flag) [self display];
        !           290:     }
        !           291: }
        !           292: 
        !           293: - (void)changeDestColorTo:(NXColor)color andDisplay:(BOOL)flag
        !           294: {
        !           295:     if (!NXEqualColor(destColor, color)) {
        !           296:        destColor = color;
        !           297:        [destination recache];
        !           298:        [result recache];
        !           299:        if (flag) [self display];
        !           300:     }
        !           301: }
        !           302: 
        !           303: - (void)changeBackgroundColorTo:(NXColor)color andDisplay:(BOOL)flag
        !           304: {
        !           305:     if (!NXEqualColor(backgroundColor, color)) {
        !           306:        backgroundColor = color;
        !           307:        if (flag) [self display];
        !           308:     }
        !           309: }
        !           310: 
        !           311: // The operator method returns the operator currently in use.
        !           312: 
        !           313: - (int)operator {return operator;}
        !           314: 
        !           315: 
        !           316: // setOperator sets the operator to be used in the compositing operations
        !           317: // and updates the view to reflect the change. Note that setOperator needs
        !           318: // to be connected to a row of buttons.
        !           319: 
        !           320: - setOperator:sender
        !           321: {      
        !           322:     switch ([sender selectedRow]) {
        !           323:        case 0: operator = NX_COPY;             break;
        !           324:        case 1: operator = NX_CLEAR;            break;
        !           325:        case 2: operator = NX_SOVER;            break;
        !           326:        case 3: operator = NX_DOVER;            break;
        !           327:        case 4: operator = NX_SIN;              break;
        !           328:        case 5: operator = NX_DIN;              break;
        !           329:        case 6: operator = NX_SOUT;             break;
        !           330:        case 7: operator = NX_DOUT;             break;
        !           331:        case 8: operator = NX_SATOP;            break; 
        !           332:        case 9: operator = NX_DATOP;            break;
        !           333:        case 10: operator = NX_XOR;             break;
        !           334:        case 11: operator = NX_PLUSD;           break;
        !           335:        case 12: operator = NX_PLUSL;           break;
        !           336:        default: break;
        !           337:     }
        !           338:     [result recache];
        !           339:     [self speedyDraw];
        !           340: 
        !           341:     return self;
        !           342: }
        !           343: 
        !           344:                
        !           345: // drawSelf:: simply redisplays the contents of the view. The source and
        !           346: // destination rectangles are updated from the bitmaps while the result
        !           347: // rectangle is created by compositing the two bitmaps.
        !           348: 
        !           349: - drawSelf:(NXRect *)r :(int) count
        !           350: {
        !           351:     // Erase the whole view
        !           352:     NXSetColor (backgroundColor);
        !           353:     NXRectFill (&bounds);
        !           354: 
        !           355:     // Color for the frame of the three sections...
        !           356:     NXSetColor (NXChangeAlphaComponent (NX_COLORBLACK, 1.0));
        !           357: 
        !           358:     // Draw the source bitmap and then frame it with black
        !           359:     [source composite:NX_SOVER toPoint:&sRect.origin];
        !           360:     NXFrameRect(&sRect);
        !           361: 
        !           362:     // Draw the destination bitmap and frame it with black 
        !           363:     [destination composite:NX_SOVER toPoint:&dRect.origin];
        !           364:     NXFrameRect(&dRect);
        !           365: 
        !           366:     // And now for the result image. Frame it with black as well
        !           367:     [result composite:NX_SOVER toPoint:&rRect.origin];
        !           368:     NXFrameRect(&rRect);
        !           369: 
        !           370:     return self;
        !           371: }
        !           372: 
        !           373: // speedyDraw provides some efficiency in redisplaying the view by assuming
        !           374: // that the source and the destination rectangles are already in place.
        !           375: 
        !           376: - speedyDraw
        !           377: {
        !           378:     [self lockFocus];
        !           379:     NXSetColor (backgroundColor);
        !           380:     NXRectFill (&rRect);
        !           381:     [result composite:NX_SOVER toPoint:&rRect.origin];
        !           382:     NXSetColor (NXChangeAlphaComponent (NX_COLORBLACK, 1.0));
        !           383:     NXFrameRect(&rRect);
        !           384:     [[self window] flushWindow];
        !           385:     [self unlockFocus];
        !           386: 
        !           387:     return self;
        !           388: }
        !           389: 
        !           390: // free method to free all the images along with the view.
        !           391: 
        !           392: - free
        !           393: {
        !           394:     [source free];
        !           395:     [destination free];
        !           396:     [result free];
        !           397:     [customImage free];
        !           398:     return [super free];
        !           399: }
        !           400: 
        !           401: 
        !           402: // Code to support dragging...
        !           403: // This is mostly complicated by the fact that the code wants to demonstrate
        !           404: // how to dynamically give feedback to the user as the colors are
        !           405: // dragged (but not dropped). We don't dynamically give feedback when images
        !           406: // are dragged (as it might take a long time).
        !           407: 
        !           408: // includesType() returns YES if type is included within types.
        !           409: 
        !           410: static BOOL includesType (const NXAtom *types, NXAtom type)
        !           411: {
        !           412:     if (types) while (*types) if (*types++ == type) return YES;
        !           413:     return NO;
        !           414: }
        !           415: 
        !           416: - (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
        !           417: {
        !           418:     return [self draggingUpdated:sender];
        !           419: }
        !           420: 
        !           421: - (NXDragOperation)draggingUpdated:(id <NXDraggingInfo>)sender
        !           422: {
        !           423:     if ([sender draggingSourceOperationMask] & NX_DragOperationGeneric) {
        !           424:        Pasteboard *pboard = [sender draggingPasteboard];
        !           425:         if (includesType([pboard types], NXColorPboardType)) { // Color
        !           426:            NXColor sourceColorSave = sourceColor;
        !           427:            NXColor destColorSave = destColor;
        !           428:            NXColor backgroundColorSave = backgroundColor;
        !           429:            [self doColorDrag:sender];
        !           430:            [self changeSourceColorTo:sourceColorSave andDisplay:NO];
        !           431:            [self changeDestColorTo:destColorSave andDisplay:NO];
        !           432:            [self changeBackgroundColorTo:backgroundColorSave andDisplay:NO];
        !           433:            return NX_DragOperationGeneric;
        !           434:        } else if ([NXImage canInitFromPasteboard:pboard]) {    // Image?
        !           435:            return NX_DragOperationGeneric;
        !           436:        }
        !           437:     }
        !           438:     return NX_DragOperationNone;           
        !           439: }
        !           440: 
        !           441: - draggingExited:sender
        !           442: {
        !           443:     if (includesType([[sender draggingPasteboard] types], NXColorPboardType)) {        // We need to fix the view up
        !           444:        [self display];
        !           445:     }
        !           446:     return self;
        !           447: }
        !           448: 
        !           449: - (BOOL)performDragOperation:(id <NXDraggingInfo>)sender
        !           450: {
        !           451:     return ([self draggingUpdated:sender] == NX_DragOperationNone) ? NO : YES;
        !           452: }
        !           453: 
        !           454: - concludeDragOperation:(id <NXDraggingInfo>)sender
        !           455: {
        !           456:     Pasteboard *pboard = [sender draggingPasteboard];
        !           457: 
        !           458:     if (includesType([pboard types], NXColorPboardType)) {
        !           459:        [self doColorDrag:sender];
        !           460:        [sourceColorWell setColor:sourceColor];
        !           461:        [destColorWell setColor:destColor];
        !           462:        [backColorWell setColor:backgroundColor];
        !           463:     } else {
        !           464:         (void)[self changeCustomImageTo:[[NXImage allocFromZone:[self zone]] initFromPasteboard:pboard]];
        !           465:     }
        !           466:     return self;
        !           467: }
        !           468: 
        !           469: - (void)doColorDrag:(id <NXDraggingInfo>)sender
        !           470: {
        !           471:     NXPoint p = [sender draggingLocation];
        !           472:     NXColor c = NXReadColorFromPasteboard([sender draggingPasteboard]);
        !           473: 
        !           474:     [self convertPoint:&p fromView:nil];
        !           475: 
        !           476:     switch ((int)(3 * p.x / NX_WIDTH(&bounds))) {
        !           477:        case 0:
        !           478:            [self changeSourceColorTo:c andDisplay:YES];
        !           479:            break;
        !           480:        case 1:
        !           481:            [self changeDestColorTo:c andDisplay:YES];
        !           482:            break;
        !           483:        case 2:
        !           484:            [self changeBackgroundColorTo:c andDisplay:YES];
        !           485:            break;
        !           486:        default:
        !           487:            break;      // Shouldn't really happen...
        !           488:     }
        !           489: }
        !           490: 
        !           491: 
        !           492: @end

unix.superglobalmegacorp.com

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