ftp.nice.ch/pub/next/developer/objc/appkit/Lab1234.s.tar.gz#/Lab2/CompositeView.m

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.
// In this version, only TRIANGLE is implemented.

#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];

    // EXERCISE: Make rectangles for source, destination and result.
    // You'll need to initialize the three rectangles (sRect, dRect, rRect)
    // so that they define the three areas in the view where the source,
    // destination, and result images will appear...

    // 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];
    
    // EXERCISE: Now create bitmap for the destination image...

    // 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;
	//
	// EXERCISE: Add code to draw the other images (defined above).
        // You might want to use the demo programs Draw and/or Yap if the idea
        // of hacking PostScript doesn't appeal to you.
	//
	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
{
   // EXERCISE: drawDestination needs to be written; it draws the destination
   // image in the destination bitmap. This method is very similar to 
   // drawSource, except it needs to draw a triangle oriented differently.
   // drawDestination also does not need to draw the other images (just
   // a triangle is enough).

   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.

// EXERCISE: Make setSourcePicture do what the comment above says it should do.
// Of course, the harder problem is actually creating the different pictures.

-setSourcePicture:(id)ctl
{
    return self;
}

// The following four methods set the color parameters and update
// the source or destination bitmaps and the view to reflect the change.
//
// EXERCISE: You will need to fill in the methods to set the alpha 
// values for the source and the destination. (They'll probably look very
// similar to the following two...)

-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
{
    return self;
}

- setDestAlpha:(id)ctl
{
    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
{	
    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 display];

    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;
}

@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.