home *** CD-ROM | disk | FTP | other *** search
- // PatchView.m by Mara Helmuth
-
- #import <math.h>
- #import <appkit/Application.h>
- #import <appkit/NXImage.h>
- #import <appkit/graphics.h>
- #import <appkit/Form.h>
- #import <appkit/Panel.h>
- #import <dpsclient/psops.h>
- #import <dpsclient/wraps.h>
-
- #import "PatchWindow.h"
- #import "PatchView.h"
- #import "draw.h"
- #import "Oscil.h"
- #import "Arith.h"
- #import "Rand.h"
- #import "Out.h"
- #import "Evp.h"
- #import "Converter.h"
- #import "Buzz.h"
- #import "Reson.h"
- #import "Comb.h"
- #import "Pluck.h"
- #import "Allpass.h"
- //#import "Delay.h"
- //#import "Reverb.h"
- //#import "WS.h"
- #import "Instrum.h"
- #import "Param.h"
-
-
- @implementation PatchView
-
- - initFrame:(const NXRect *)frameRect
- {
- [super initFrame:frameRect];
-
- /* off-screen buffer */
- screenImage = [[NXImage alloc] initSize:&bounds.size];
-
- return self;
- }
-
-
- - setImages // erase the patchview and make ugen images
- {
-
- [self erase:0];
-
- connecting = NO;
- moving = NO;
- setting = NO;
-
- PSInit(); // initialize postscript drawing defs
-
- return self;
- }
-
- /* instance methods */
-
- - windowChanged:newWindow
- {
- NXRect rect;
-
- [super windowChanged:newWindow];
-
- /* if our new window's an PatchWindow, we'll "register" ourself with it */
- if ([newWindow respondsTo:@selector(registerRect:forView:)]) {
- /* give the window our window-based coordinates */
- rect = bounds;
- [self convertRect:&rect toView:nil];
- [newWindow registerRect:&rect forView:self];
- }
-
- return self;
- }
-
- - setUgen:(int)uType
- {
- ugenType = uType;
- return self;
- }
-
-
- - setDelegate:anObject
- {
- delegate = anObject;
- return self;
- }
-
- - (BOOL)windowEntered:dragSource
- {
- /* let our window know we've done some drawing */
- return YES;
- }
-
- - (BOOL)windowExited:dragSource
- {
- /* let our window know we've done some drawing */
- return YES;
- }
-
- - (BOOL)windowDropped:dragSource:(NXPoint *)currentLocation
- {
- /* the user dropped a window into us */
- [window flushWindow];
- if ([delegate respondsTo:@selector(acceptedWindow:fromSource:)]) {
- [delegate acceptedWindow:self fromSource:dragSource];
- }
-
- // put the new ugen into the UnitGen ugenList
- switch(ugenType) {
- case 5: {
- currentUgen = [[Arith alloc] init];
- [currentUgen setAtype:'+'];
- break;
- }
- case 6: {
- currentUgen = [[Arith alloc] init];
- [currentUgen setAtype:'-'];
- break;
- }
- case 7: {
- currentUgen = [[Arith alloc] init];
- [currentUgen setAtype:'*'];
- break;
- }
- case 8: {
- currentUgen = [[Arith alloc] init];
- [currentUgen setAtype:'/'];
- break;
- }
- /*
- case 9: {
- currentUgen = [[WS alloc] init];
- break;
- }
- */
- case 10: {
- currentUgen = [[Comb alloc] init];
- break;
- }
- case 11: {
- currentUgen = [[Pluck alloc] init];
- break;
- }
- /* case 12: {
- currentUgen = [[Allpass alloc] init];
- break;
- }
- */ case 13: {
- currentUgen = [[Allpass alloc] init]; // delay actually?
- break;
- }
- /* case 14: {
- currentUgen = [[Reverb alloc] init];
- break;
- }
- */
- case 15: {
- currentUgen = [[Oscil alloc] init];
- break;
- }
- case 16: {
- currentUgen = [[Buzz alloc] init];
- break;
- }
- case 17: {
- currentUgen = [[Rand alloc] init];
- break;
- }
- case 18: {
- currentUgen = [[Evp alloc] init];
- break;
- }
- case 19: {
- currentUgen = [[Reson alloc] init];
- break;
- }
- case 20:
- case 21:
- case 22:
- case 23:
- case 24:
- case 25: {
- currentUgen = [[Converter alloc] init];
- [currentUgen setCtype:ugenType];
- break;
- }
- default: {
- NXRunAlertPanel("patchmix","Sorry, this unit generator is not yet working","OK",NULL,NULL);
- return NO;
- }
- }
- currentUgenCenter.x = currentUgenCenter.y = 40;
- /* we accept it */
- [self convertPoint:currentLocation fromView:nil];
-
- // center on the cursor
- currentLocation->x -= [currentUgen getCenter]->x;
- currentLocation->y -= [currentUgen getCenter]->y;
-
- [currentUgen move:currentLocation];
- currentLocation = [currentUgen getLocation];
-
- currentImage = [currentUgen getImage];
- // draw the current ugen into the view
- [self lockFocus];
- [currentImage composite:NX_SOVER toPoint:currentLocation];
- [self unlockFocus];
- [window flushWindow];
-
- // draw the current ugen into the off-screen buffer
- if ([screenImage lockFocus]) {
- [currentImage composite:NX_SOVER toPoint:currentLocation];
- [screenImage unlockFocus];
- }
-
-
- [window disableFlushWindow];
- [self display];
- [window reenableFlushWindow];
-
- return YES;
- }
-
- - drawSelf:(NXRect *)rects :(int)count
- {
- /* load the appropriate portion of the off-screen buffer
- * into the visible portion of the view
- */
- [screenImage composite:NX_COPY fromRect:rects toPoint:&(rects->origin)];
- return self;
- }
-
-
- - erase:sender
- // erase the view and free up all the unit generators
- {
-
- NXSize imageSize;
- NXPoint outLocation;
-
- setting = connecting = moving = NO;
-
- if ([screenImage lockFocus]) {
- NXEraseRect(&bounds);
- [screenImage unlockFocus];
- }
-
- [Inst freeUgens]; // free up ugens in list
-
- currentUgen = [[Out alloc] init];
-
- // draw the out ugen into the view
- currentImage = [currentUgen getImage];
- [currentImage getSize:&imageSize];
- outLocation.x = floor((NX_WIDTH(&bounds) - imageSize.width) / 2.0);
- outLocation.y = floor((NX_HEIGHT(&bounds) - imageSize.height) / 5.0);
- [currentUgen move:&outLocation];
- [self lockFocus];
- [currentImage composite:NX_SOVER toPoint:&outLocation];
- [self unlockFocus];
- [window flushWindow];
-
- // draw the out ugen into the off-screen buffer
- if ([screenImage lockFocus]) {
- [currentImage composite:NX_SOVER toPoint:&outLocation];
- [screenImage unlockFocus];
- }
- [self display];
-
-
- return self;
- }
-
- - mouseDown:(NXEvent *)e
- /* logic for mouse down events:
- convert the point location
- if a unit generator found at the mouse down point
- if a parameter found at the mouse down point
- if we are setting a parameter
- set the parameter to whatever use input into Param form field
- unhighlight the parameter
- else if the event is a double click
- we are setting a parameter so highlight it
- diplay the parameter name and value in the Param form field
- else
- we are connecting unit generators so save the location
- else (a unit generator found, but no parameter)
- if event is a double-click
- delete unit generator if user confirms and it is not an out ugen
- else single-click
- if setting, user error - display panel
- else we are moving a unit generator - erase and redraw at location
- and erase all its connections
- else no unit generator found
- if setting - user error - display panel
- while event is not a mouseUp,
- call mouseDraggedAction (for moving unit generator)
- */
- {
- id pList;
- NXPoint startPoint = e->location, nextPoint;
- int looping = YES, i;
- int oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK];
-
- /* do first mouse down action */
- [self convertPoint:&startPoint fromView:nil];
- //printf("mouseDown\n");
-
- if(currentUgen = [Inst findUgenAtPoint:&startPoint]) {
- currentImage = [currentUgen getImage];
- if(currentParam = [currentUgen findParamAtPoint:&startPoint]) {
- if(setting) { // mouse click after set param val
- [currentParam setValue:[paramVal stringValueAt:0]];
- setting = NO;
- hrect = [currentParam getRect];
- // unhighlight param
- [self lockFocus];
- NXHighlightRect(hrect);
- [self unlockFocus];
- [window flushWindow];
- }
- else if(e->data.mouse.click == 2) { // double click,
- // begin to set param...
- connecting = moving = NO;
- setting = YES;
- hrect = [currentParam getRect]; // highlight the param
- [self lockFocus];
- NXHighlightRect(hrect);
- [self unlockFocus];
- [window flushWindow];
- [paramVal setStringValue:[currentParam getValue] at:0];
- [paramVal setTitle:[currentParam getTitle] at:0];
- [paramVal selectTextAt:0];
- }
- else { // no double click
- connecting = YES;
- moving = setting = NO;
- connPoint1 = [currentParam getDrawPoint];
- connUgen1 = currentUgen;
- connParam1 = currentParam;
- }
- }
- else { // no param found, but a ugen selected
- if(e->data.mouse.click == 2) { // double click, delete ugen?
- ugenselected = YES;
- hrect = [currentUgen getRect]; // highlight the ugen
- [self lockFocus];
- NXHighlightRect(hrect);
- [self unlockFocus];
- [window flushWindow];
- choice = NXRunAlertPanel("Cut Alert", "Delete this unit generator?", "Blow it away","No, Save it!",NULL);
- hrect = [currentUgen getRect];
- // unhighlight ugen
- [self lockFocus];
- NXHighlightRect(hrect);
- [self unlockFocus];
- [window flushWindow];
- if(choice == NX_ALERTDEFAULT) {
- if(!strcmp("Out",[currentUgen getType]))
- NXRunAlertPanel("Cut Alert", "Can't delete Output Unit Generator!", "OK", NULL, NULL);
- else {
- if(![currentUgen remove]) {
- NXRunAlertPanel("Cut Alert", "Can't delete a connected unit generator! Please delete connectors first.", "OK", NULL, NULL);
- }
- else {
- //THIS ERASES A UGEN
- // draw the current ugen into the view
- [self lockFocus];
- [[currentUgen getImage] composite:NX_XOR toPoint:[currentUgen getLocation]];
- [self unlockFocus];
- [window flushWindow];
- // draw the current ugen into the off-screen buffer
- if ([screenImage lockFocus]) {
- [[currentUgen getImage] composite:NX_XOR toPoint:[currentUgen getLocation]];
- [screenImage unlockFocus];
- }
- }
- }
- }
- [self display];
- }
- else { // not a double-click, ugen selected
- if(setting) { // unhighlight param and stop setting - user error
- [self lockFocus];
- NXHighlightRect(hrect);
- [self unlockFocus];
- [window flushWindow];
- NXRunAlertPanel("Param Alert", "I hope you know you have to click on the param again to save the value...", "Oh, alright!", NULL, NULL);
- setting = NO;
- }
- else { // unit gen selected no param, not double click, not setting
- moving = YES;
- connecting = setting = NO;
- // erase the original so you can move image around
- [self lockFocus];
- [[currentUgen getImage] composite:NX_XOR toPoint:[currentUgen getLocation]];
- [self unlockFocus];
- [window flushWindow];
- // draw the current ugen into the off-screen buffer
- if ([screenImage lockFocus]) {
- [[currentUgen getImage] composite:NX_XOR toPoint:[currentUgen getLocation]];
- [screenImage unlockFocus];
- }
- // erase the connectors too, for now
- pList = [currentUgen getParamList];
- for(i = 0; i < [pList count]; i++) {
- currentParam = [pList objectAt:i];
- if(eraseParam = [currentParam getConnectedParam]) { // if connected
- ePoint1 = [currentParam getDrawPoint];
- ePoint2 = [eraseParam getDrawPoint];
- [self lockFocus];
- PSsetgray(NX_WHITE);
- PSLine(ePoint1->x,ePoint1->y, ePoint2->x-ePoint1->x, ePoint2->y-ePoint1->y);
- [self unlockFocus];
- if ([screenImage lockFocus]) {
- PSsetgray(NX_WHITE);
- PSLine(ePoint1->x,ePoint1->y, ePoint2->x-ePoint1->x, ePoint2->y-ePoint1->y);
- [screenImage unlockFocus];
- }
- }
- }
- // draw ugen where mouse down is and store points
- nextPoint.x = startPoint.x - currentUgenCenter.x;
- nextPoint.y = startPoint.y - currentUgenCenter.y;
- // draw the current ugen into the view
- [self lockFocus];
- [currentImage composite:NX_SOVER toPoint:&nextPoint];
- [self unlockFocus];
- [window flushWindow];
- if ([screenImage lockFocus]) {
- [currentImage composite:NX_SOVER toPoint:&nextPoint];
- [screenImage unlockFocus];
- }
- erasePoint1.x = nextPoint.x;
- erasePoint1.y = nextPoint.y;
- }
- }
- }
- }
- // no ugen found
- else {
- if(setting) { // unhighlight param and stop setting - user error
- [self lockFocus];
- NXHighlightRect(hrect);
- [self unlockFocus];
- [window flushWindow];
- NXRunAlertPanel("Param Alert", "I hope you know you have to click on the param again to save the value...", "Oh, alright!", NULL, NULL);
- setting = NO;
- }
- }
-
- while (looping) {
- e = [NXApp getNextEvent:NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK];
- nextPoint = e->location;
- [self convertPoint:&nextPoint fromView:nil];
- if(e->type == NX_MOUSEDRAGGED) {
- [superview autoscroll:e];
- /* TO DRAG AN IMAGE: */
- if(moving) { // erase the old
- [self lockFocus];
- [currentImage composite:NX_XOR toPoint:&erasePoint1];
- [self unlockFocus];
- [window flushWindow];
- // erase off-screen buffer, not needed if not drawing there
- if ([screenImage lockFocus]) {
- [currentImage composite:NX_XOR toPoint:&erasePoint1];
- [screenImage unlockFocus];
- }
- // do continuing mouse dragged action
- [self mouseDraggedAction:&nextPoint];
- }
- }
- else { // mouse up - drag is done
- looping = NO;
- /* do mouse up action */
- [self mouseUpAction:&nextPoint];
- [window setEventMask:oldMask];
- }
-
- }
- return self;
- }
-
- - mouseDraggedAction:(NXPoint *)currentLocation
- {
- // THIS DRAGS A UGEN: draws ugen on new points */
- if (moving) {
- currentLocation->x -= currentUgenCenter.x;
- currentLocation->y -= currentUgenCenter.y;
- // draw the current ugen into the view
- [self lockFocus];
- [currentImage composite:NX_SOVER toPoint:currentLocation];
- [self unlockFocus];
- [window flushWindow];
- // draw the current ugen into the off-screen buffer
- if ([screenImage lockFocus]) {
- [currentImage composite:NX_SOVER toPoint:currentLocation];
- [screenImage unlockFocus];
- }
- erasePoint1.x = currentLocation->x;
- erasePoint1.y = currentLocation->y;
- }
- return self;
- }
-
- - mouseUpAction:(NXPoint *)currentLocation
- /* if moving
- redraw the connections to other unit generators
- else if connecting
- for each parameter:
- erase previous connections
- draw the new connection
- store the new connections
- */
- {
- id pList;
- BOOL draw = YES;
- int i;
-
- if(moving) {
- // for each param, redraw if connected
- // save new location for Ugen
- currentLocation->x -= currentUgenCenter.x;
- currentLocation->y -= currentUgenCenter.y;
- [currentUgen move:currentLocation];
- // if ugen connected, redraw connectors
- // for each param, check if connected, redraw line
- pList = [currentUgen getParamList];
- for(i = 0; i < [pList count]; i++) {
- currentParam = [pList objectAt:i];
- if(connParam1 = [currentParam getConnectedParam]) { // if connected
- connPoint1 = [currentParam getDrawPoint];
- connPoint2 = [connParam1 getDrawPoint];
- [self lockFocus];
- PSLine(connPoint1->x,connPoint1->y, connPoint2->x-connPoint1->x, connPoint2->y-connPoint1->y);
- [self unlockFocus];
- if ([screenImage lockFocus]) {
- PSLine(connPoint1->x,connPoint1->y, connPoint2->x-connPoint1->x, connPoint2->y-connPoint1->y);
- [screenImage unlockFocus];
- }
- }
- }
- [self display];
- moving = NO;
- }
- // if connecting draw final line
- else if(connecting) {
- if((currentUgen = [Inst findUgenAtPoint:currentLocation]) != connUgen1) {
- // test if these connectors are already connected
- // if so, erase the line
- // erase any previous connections for either connector
- if(currentParam = [currentUgen findParamAtPoint:currentLocation]) {
- connPoint2 = [currentParam getDrawPoint];
- if([connParam1 getConnectedParam] == currentParam) {
- // they are already connected, ERASE
- // and disconnect
- //printf("already conn, erasing\n");
- [connParam1 setConnectedParam:nil];
- [currentParam setConnectedParam:nil];
- [self lockFocus];
- PSsetgray(NX_WHITE);
- PSLine(connPoint1->x,connPoint1->y, connPoint2->x-connPoint1->x, connPoint2->y-connPoint1->y);
- [self unlockFocus];
- if ([screenImage lockFocus]) {
- PSsetgray(NX_WHITE);
- PSLine(connPoint1->x,connPoint1->y, connPoint2->x-connPoint1->x, connPoint2->y-connPoint1->y);
- [screenImage unlockFocus];
- }
- draw = NO;
- } // conn1 was connected, erase
- else {
- if(eraseParam = [connParam1 getConnectedParam]) {
- ePoint2 = [eraseParam getDrawPoint];
- [connParam1 setConnectedParam:nil];
- [eraseParam setConnectedParam:nil];
- [self lockFocus];
- PSsetgray(NX_WHITE);
- PSLine(connPoint1->x,connPoint1->y, ePoint2->x-connPoint1->x, ePoint2->y-connPoint1->y);
- [self unlockFocus];
- if ([screenImage lockFocus]) {
- PSsetgray(NX_WHITE);
- PSLine(connPoint1->x,connPoint1->y, ePoint2->x-connPoint1->x, ePoint2->y-connPoint1->y);
- [screenImage unlockFocus];
- }
- } // conn2 was connected, erase
- if(eraseParam = [currentParam getConnectedParam]) {
- ePoint1 = [eraseParam getDrawPoint];
- [currentParam setConnectedParam:nil];
- [eraseParam setConnectedParam:nil];
- [self lockFocus];
- PSsetgray(NX_WHITE);
- PSLine(ePoint1->x,ePoint1->y, connPoint2->x-ePoint1->x, connPoint2->y-ePoint1->y);
- [self unlockFocus];
- if ([screenImage lockFocus]) {
- PSsetgray(NX_WHITE);
- PSLine(ePoint1->x,ePoint1->y, connPoint2->x-ePoint1->x, connPoint2->y-ePoint1->y);
- [screenImage unlockFocus];
- }
- }
- }
- if(draw) { // draw the connnector
- [connParam1 setConnectedParam:currentParam];
- [currentParam setConnectedParam:connParam1];
- [self lockFocus];
- PSLine(connPoint1->x,connPoint1->y, connPoint2->x-connPoint1->x, connPoint2->y-connPoint1->y);
- [self unlockFocus];
- if ([screenImage lockFocus]) {
- PSLine(connPoint1->x,connPoint1->y, connPoint2->x-connPoint1->x, connPoint2->y-connPoint1->y);
- [screenImage unlockFocus];
- }
- }
- }
- [self display];
- connecting = NO;
- }
- }
- return self;
- }
-
- /* delegation methods */
- - acceptedWindow:acceptView fromSource:source
- {
- /*
- * if delegate implements this method, it'll get called whenever the user
- * drops a window into the view
- */
- return self;
- }
-
- @end
-