home *** CD-ROM | disk | FTP | other *** search
- // 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