This is PatchView.m in view mode; [Download] [Up]
// 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
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.