Annotation of Examples/AppKit/CompositeLab/CompositeView.m, revision 1.1.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.