This is CompositeView.m in view mode; [Download] [Up]
// CompositeView implements a view with three horizontal, equal-sized areas. // The left-most area is the "source," the middle area is the "destination," // and the right-most area is the "result." CompositeView assures that the // contents of the result area is always generated by compositing the other // two areas using the compositing mode set in the setOperator: method. // It is also possible to change the contents, color, and alpha of the // source and destination areas; see the methods setSourceGray:, // setSourceAlpha:, etc. // CompositeView written by Bruce Blumberg and Ali Ozer, NeXT Developer Support #import "CompositeView.h" #import <appkit/Bitmap.h> #import <appkit/Control.h> #import <appkit/Matrix.h> #import <appkit/Window.h> #import <dpsclient/wraps.h> @implementation CompositeView // The possible draw modes for the source. #define TRIANGLE 0 #define CIRCLE 1 #define DIAMOND 2 #define HEART 3 #define FLOWER 4 // newFrame creates the view, initializes the rectangles that define the // three areas described above, and creates the bitmaps used for rendering the // source and destination bitmaps. +newFrame:(const NXRect *)tF { // Create the view self = [super newFrame:tF]; // Make rectangles for source, destination and result sRect = bounds; sRect.size.width /= 3.0; dRect = sRect; dRect.origin.x = sRect.size.width; rRect = dRect; rRect.origin.x = dRect.origin.x + dRect.size.width; // Create bitmap for source image. Bitmaps are flipped by default; // make sure we make ours not-flipped. source = [Bitmap newSize:sRect.size.width :sRect.size.height type:NX_UNIQUEBITMAP]; [source setFlip:NO]; // Now do the same for the destination... destination = [Bitmap newSize:dRect.size.width :dRect.size.height type:NX_UNIQUEBITMAP]; [destination setFlip:NO]; // Set the default operator and source picture. Also set default // gray and alpha values. You will of course have to make sure // the sliders in your Interface Builder window have the same values. // (This is a problem; can you see a way to fix it?) operator = NX_COPY; sourcePicture = TRIANGLE; sourceGray = 0.333; // dark gray destGray = 0.666; // light gray sourceAlpha = 1.0; // opaque destAlpha = 1.0; // opaque // Create the bitmap images using the initial values set above [self drawSource]; [self drawDestination]; return self; } // drawSource creates the source image in the source bitmap. Note that // drawSource does not render in the view; it renders in the bitmap only. -drawSource { [source lockFocus]; PScompositerect (0.0, 0.0, sRect.size.width, sRect.size.height, NX_CLEAR); PSsetgray(sourceGray); PSsetalpha(sourceAlpha); PSnewpath(); switch (sourcePicture) { case TRIANGLE: PSmoveto (0.0, 0.0); PSlineto (0.0, sRect.size.height); PSlineto (sRect.size.width, sRect.size.height); break; case CIRCLE: PSscale (sRect.size.width, sRect.size.height); PSarc (0.5, 0.5, 0.4, 0.0, 360.0); // diameter is 80% of area break; case DIAMOND: PSmoveto (0.0, sRect.size.height / 2.0); PSlineto (sRect.size.width / 2.0, 0.0); PSlineto (sRect.size.width, sRect.size.height / 2.0); PSlineto (sRect.size.width / 2.0, sRect.size.height); break; case HEART: PSscale (sRect.size.width, sRect.size.height); PSmoveto (0.5, 0.5); PScurveto (0.3, 1.0, 0.0, 0.5, 0.5, 0.1); PSmoveto (0.5, 0.5); PScurveto (0.7, 1.0, 1.0, 0.5, 0.5, 0.1); break; case FLOWER: PSscale (sRect.size.width, sRect.size.height); PStranslate (0.5, 0.5); PSmoveto (0.0, 0.0); {int cnt; for (cnt = 0; cnt < 6; cnt++) { PSrotate (60.0); PScurveto (0.4, 0.5, -0.4, 0.5, 0.0, 0.0); } } break; default: break; } PSclosepath(); PSfill(); [source unlockFocus]; return self; } // drawDestination creates the destination image in the destination bitmap. // Like drawSource, drawDestination only draws in the bitmap, not the view. -drawDestination { [destination lockFocus]; PScompositerect (0.0, 0.0, dRect.size.width, dRect.size.height, NX_CLEAR); PSsetgray(destGray); PSsetalpha(destAlpha); PSnewpath(); PSmoveto(dRect.size.width, 0.0); PSlineto(dRect.size.width, dRect.size.height); PSlineto(0.0, dRect.size.height); PSclosepath(); PSfill(); [destination unlockFocus]; return self; } // setSourcePicture allows setting the picture to be drawn in the source // bitmap. Buttons connected to this method should have tags that are // set to the various possible pictures (see the "#define"s, above). // // After setting the sourcePicture instance variable, setSourcePicture redraws // the bitmap and updates the view to reflect the new configuration. -setSourcePicture:(id)ctl { sourcePicture = [ctl selectedTag]; [self drawSource]; [self display]; return self; } // The following four methods set the color or alpha parameters and update // the source or destination bitmaps and the view to reflect the change. -setSourceGray:(id)ctl { sourceGray = [ctl floatValue]; [self drawSource]; [self display]; return self; } -setDestGray:(id)ctl { destGray = [ctl floatValue]; [self drawDestination]; [self display]; return self; } -setSourceAlpha:(id)ctl { sourceAlpha = [ctl floatValue]; [self drawSource]; [self display]; return self; } -setDestAlpha:(id)ctl { destAlpha = [ctl floatValue]; [self drawDestination]; [self display]; return self; } // The operator method returns the operator currently in use. -(int)operator {return operator;} // setOperator sets the operator to be used in the compositing operations // and updates the view to reflect the change. Note that setOperator needs // to be connected to a row of buttons. -setOperator:(id)sender { char *modeName; switch ([sender selectedRow]) { case 0: operator = NX_COPY; break; case 1: operator = NX_CLEAR; break; case 2: operator = NX_SOVER; break; case 3: operator = NX_DOVER; break; case 4: operator = NX_SIN; break; case 5: operator = NX_DIN; break; case 6: operator = NX_SOUT; break; case 7: operator = NX_DOUT; break; case 8: operator = NX_SATOP; break; case 9: operator = NX_DATOP; break; case 10: operator = NX_XOR; break; case 11: operator = NX_PLUSD; break; case 12: operator = NX_PLUSL; break; default: break; } [self speedyDraw]; return self; } // drawSelf:: simply redisplays the contents of the view. The source and // destination rectangles are updated from the bitmaps while the result // rectangle is created by compositing the two bitmaps. -drawSelf:(NXRect *)r :(int) count { // Erase the whole view NXEraseRect(&bounds); // Draw the source bitmap and then frame it with black [source composite:NX_COPY toPoint:&sRect.origin]; PSsetgray(NX_BLACK); NXFrameRect(&sRect); // Draw the destination bitmap and frame it with black [destination composite:NX_COPY toPoint:&dRect.origin]; PSsetgray(NX_BLACK); NXFrameRect(&dRect); // And now create the destination image and frame it with black as well [destination composite:NX_COPY toPoint:&rRect.origin]; [source composite:operator toPoint:&rRect.origin]; PSsetgray(NX_BLACK); NXFrameRect(&rRect); return self; } // speedyDraw provides some efficiency in redisplaying the view by assuming // that the source and the destination rectangles are already in place. -speedyDraw { [self lockFocus]; NXEraseRect(&rRect); [destination composite:NX_COPY toPoint:&rRect.origin]; [source composite:operator toPoint:&rRect.origin]; NXFrameRect(&rRect); [self unlockFocus]; [[self window] flushWindow]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.