2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #import "iPhoneSCGraphView.h"
22 #import "iSCLangController.h"
23 #include "PyrInterpreter.h"
24 #include "PyrKernel.h"
25 #include "PyrMessage.h"
26 #include "VMGlobals.h"
28 #include "SC_BoundsMacros.h"
30 #import <UIKit/UIKit.h>
32 extern PyrSymbol *s_draw;
33 extern PyrSymbol *s_scview;
34 extern PyrSymbol *s_closed;
35 extern PyrSymbol *s_callDrawFunc;
36 extern PyrSymbol *s_toggleEditMode;
38 @implementation SCGraphView
40 - (void)setAcceptsClickThrough:(BOOL)boo
42 acceptsClickThrough = boo;
45 - (void)setAutoScrolls:(BOOL)boo;
50 - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
52 return acceptsClickThrough;
60 - (BOOL)mouseDownCanMoveWindow
65 //eat all key Events might add this
66 - (BOOL)performKeyEquivalent:(NSEvent *)event
68 // NSString *characters = [event characters];
69 unsigned int modifiers = [event modifierFlags];
70 //control tab/escape doesn't get passed here at all ?
71 if(modifiers & NSCommandKeyMask) // allow cmd-key only
72 [self keyDown: event];
73 return NO; //for now pass on the event
76 - (void)flagsChanged:(NSEvent *)event
78 unsigned int modifiers = [event modifierFlags];
79 // NSLog(@" modifiers %d %08X",modifiers, modifiers);
81 SCView *view = mTopView->focusView();
83 view->keyModifiersChanged(modifiers);
85 mTopView->keyModifiersChanged(modifiers);
89 - (void) keyDown: (NSEvent*) event
91 NSString *characters = [event characters];
92 unsigned int modifiers = [event modifierFlags];
93 unichar character = 0;
94 if([characters length] > 0) {
95 character = [characters characterAtIndex: 0];
97 //control tab/escape doesn't get passed here at all ?
98 // NSLog(@"unicode %d length:%d clength:%d mTopView %08X modifiers %d %08X",
99 // character,[characters length],[characters cStringLength], mTopView, modifiers, modifiers);
102 // for some reason modifiers becomes 256 on my machine with no keys pressed. So need to mask against known keys.
103 uint32 allKnownModifiers = NSAlphaShiftKeyMask | NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask
104 | NSAlternateKeyMask | NSHelpKeyMask | NSFunctionKeyMask | NSCommandKeyMask;
105 if(character == 9 && ((modifiers & allKnownModifiers) == 0)) {
106 mTopView->tabPrevFocus();
108 } else if (character == 25 && ((modifiers & allKnownModifiers) == NSShiftKeyMask)) {
109 mTopView->tabNextFocus();
111 } // other tab keys avail for user
112 SCView *view = mTopView->focusView();
114 view->keyDown(character, modifiers,[event keyCode]);
116 mTopView->keyDown(character,modifiers,[event keyCode]);
122 - (void) keyUp: (NSEvent*) event
124 NSString *characters = [event characters];
125 unsigned int modifiers = [event modifierFlags];
126 unichar character = 0;
127 if([characters length] > 0) {
128 character = [characters characterAtIndex: 0];
130 // NSLog(@"keyUp: unicode %d length:%d clength:%d mTopView %08X modifiers %d %08X",
131 // character,[characters length],[characters cStringLength], mTopView, modifiers, modifiers);
134 uint32 allKnownModifiers = NSAlphaShiftKeyMask | NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask
135 | NSAlternateKeyMask | NSHelpKeyMask | NSFunctionKeyMask;
136 if(character == 9 && ((modifiers & allKnownModifiers) == 0)) {
138 } else if (character == 25 && ((modifiers & allKnownModifiers) == NSShiftKeyMask)) {
140 } // other tab keys avail for user
142 SCView *view = mTopView->focusView();
144 view->keyUp(character, modifiers,[event keyCode]);
146 mTopView->keyUp(character,modifiers,[event keyCode]);
152 static CGRect SCtoCGRect(SCRect screct)
155 nsrect.origin.x = screct.x;
156 nsrect.origin.y = screct.y;
157 nsrect.size.width = screct.width;
158 nsrect.size.height = screct.height;
162 static NSString *sSCObjType = @"SuperCollider object address";
164 - (id)initWithFrame: (CGRect) frame
166 [super initWithFrame: frame];
167 //[self registerForDraggedTypes: [NSArray arrayWithObjects: sSCObjType, NSStringPboardType, nil]];
172 windowShouldClose = YES;
173 acceptsClickThrough = YES;
175 [self setBackgroundColor:[UIColor whiteColor]];
179 - (void) touch:(NSSet *)touches withEvent:(UIEvent *)event
181 for (UITouch *touch in touches)
184 if (!mTopView) return;
185 mouseLoc = [touch locationInView:self];
186 SCPoint scpoint = SCMakePoint(mouseLoc.x, mouseLoc.y);
187 SCView *view = mTopView->findView(scpoint);
192 view->makeFocus(true);
193 bool constructionmode = mTopView->ConstructionMode();
194 if(!constructionmode)
196 UITouchPhase phase = [touch phase];
197 if (phase==UITouchPhaseBegan)
199 view->touchDownAction(scpoint, touch);
200 view->touchBeginTrack(scpoint, touch);
202 else if (phase==UITouchPhaseMoved)
204 view->touchTrack(scpoint, touch);
205 view->touchMoveAction(scpoint, touch);
207 else if (phase==UITouchPhaseEnded)
209 view->touchUpAction(scpoint, touch);
210 view->touchEndTrack(scpoint, touch);
219 //else view->setConstructionModeFromPoint(scpoint);
221 //[self displayIfNeeded];
223 while (keepOn && !mDragStarted && !mMenuView) {
224 theEvent = [[self window] nextEventMatchingMask: NSLeftMouseUpMask |NSRightMouseUp | NSOtherMouseUp |
225 NSLeftMouseDraggedMask | NSRightMouseDragged | NSOtherMouseDragged
226 | NSKeyDownMask | NSKeyUpMask
228 mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
229 //isInside = [self mouse:mouseLoc inRect:[self bounds]];
230 scpoint = SCMakePoint(mouseLoc.x, mouseLoc.y);
231 int evtype = [theEvent type];
232 switch ([theEvent type]) {
233 case NSLeftMouseDown:
234 case NSRightMouseDown:
237 view->doConstructionMove(scpoint);
240 view->mouseDownAction(scpoint, modifiers,theEvent);
243 case NSLeftMouseDragged:
244 if(autoScrolls) [self autoscroll:theEvent];
245 case NSRightMouseDragged:
246 case NSOtherMouseDragged:
249 view->doConstructionMove(scpoint);
252 view->mouseTrack(scpoint, modifiers,theEvent);
253 view->mouseMoveAction(scpoint, modifiers,theEvent);
261 // view->doConstructionMove(scpoint);
265 // if(!view.GetSCObj()) break;
266 view->mouseUpAction(scpoint, modifiers,theEvent);
267 view->mouseEndTrack(scpoint, modifiers,theEvent);
272 post("evtype %d %4.4s\n", evtype, (char*)&evtype);
276 //[self displayIfNeeded];
284 - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
286 [self touch:touches withEvent:event];
289 - (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
291 [self touch:touches withEvent:event];
294 - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
296 [self touch:touches withEvent:event];
299 - (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
301 printf("touches cancelled\n");
307 - (NSMenu*) menuForEvent:(NSEvent*)theEvent;
310 mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
311 SCPoint scpoint = SCMakePoint(mouseLoc.x, mouseLoc.y);
312 if (!mTopView) return 0;
313 SCView *view = mTopView->findView(scpoint);
315 return view->contextMenu(scpoint);
318 -(void)rightMouseDown:(NSEvent*)theEvent { [self mouseDown:theEvent]; }
319 -(void)otherMouseDown:(NSEvent*)theEvent { [self mouseDown:theEvent]; }
320 - (void)mouseDown:(NSEvent *)theEvent
322 // NSLog(@"SCGraphView MOUSEDOWN");
324 //BOOL isInside = YES;
326 //NSLog(@"Click count: %i", [theEvent clickCount]);
327 //if([theEvent clickCount] == 2) return;
328 if (!mTopView) return;
329 unsigned int modifiers = [theEvent modifierFlags];
330 mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
331 SCPoint scpoint = SCMakePoint(mouseLoc.x, mouseLoc.y);
332 SCView *view = mTopView->findView(scpoint);
336 view->makeFocus(true);
337 bool constructionmode = mTopView->ConstructionMode();
338 if(!constructionmode)
340 view->mouseDownAction(scpoint, modifiers,theEvent);
341 view->mouseBeginTrack(scpoint, modifiers,theEvent);
343 view->setConstructionModeFromPoint(scpoint);
345 [self displayIfNeeded];
347 while (keepOn && !mDragStarted && !mMenuView) {
348 theEvent = [[self window] nextEventMatchingMask: NSLeftMouseUpMask |NSRightMouseUp | NSOtherMouseUp |
349 NSLeftMouseDraggedMask | NSRightMouseDragged | NSOtherMouseDragged
350 | NSKeyDownMask | NSKeyUpMask
352 mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
353 //isInside = [self mouse:mouseLoc inRect:[self bounds]];
354 scpoint = SCMakePoint(mouseLoc.x, mouseLoc.y);
355 int evtype = [theEvent type];
356 switch ([theEvent type]) {
357 case NSLeftMouseDown:
358 case NSRightMouseDown:
361 view->doConstructionMove(scpoint);
364 view->mouseDownAction(scpoint, modifiers,theEvent);
367 case NSLeftMouseDragged:
368 if(autoScrolls) [self autoscroll:theEvent];
369 case NSRightMouseDragged:
370 case NSOtherMouseDragged:
373 view->doConstructionMove(scpoint);
376 view->mouseTrack(scpoint, modifiers,theEvent);
377 view->mouseMoveAction(scpoint, modifiers,theEvent);
385 // view->doConstructionMove(scpoint);
389 // if(!view.GetSCObj()) break;
390 view->mouseUpAction(scpoint, modifiers,theEvent);
391 view->mouseEndTrack(scpoint, modifiers,theEvent);
396 if(!constructionmode)
398 [self keyDown:theEvent];
402 if(!constructionmode)
404 [self keyUp:theEvent];
408 post("evtype %d %4.4s\n", evtype, (char*)&evtype);
412 [self displayIfNeeded];
420 -(void)mouseMoved:(NSEvent*)theEvent
423 if (!mTopView) return;
424 unsigned int modifiers = [theEvent modifierFlags];
425 mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
426 SCPoint scpoint = SCMakePoint(mouseLoc.x, mouseLoc.y);
427 SCView *view = mTopView->findView(scpoint);
431 // view->makeFocus(true);
432 view->mouseOver(scpoint, modifiers, theEvent);
436 //scrollWheel:(NSEvent*)theEvent;
438 - (void)setSCObject: (struct PyrObject*)inObject;
440 mWindowObj = inObject;
443 - (struct PyrObject*)getSCObject
448 void damageFunc(SCRect inRect, void* inData)
450 SCGraphView *view = (SCGraphView*)inData;
452 [view setNeedsDisplayInRect: SCtoCGRect(inRect)];
455 void dragFunc(SCPoint where, PyrSlot *inSlot, NSString* inString, NSString* label, void* inData)
457 SCGraphView *view = (SCGraphView*)inData;
458 CGPoint point = CGPointMake(where.x, where.y);
459 [view beginDragFrom: point of: inSlot string: inString label: label];
464 - (unsigned int)draggingSourceOperationMaskForLocal: (BOOL)flag
466 return flag ? NSDragOperationEvery : NSDragOperationNone;
470 - (void)setSCTopView: (SCTopView*)inView
473 mTopView->setDamageCallback(damageFunc, (void*)self);
474 mTopView->setDragCallback(dragFunc);
475 mTopView->SetUIView(self);
480 //printf("dealloc %08X mTopView %08X\n", self, mTopView);
489 SCNSWindow *w = [self superview];
493 - (void)removeFromSuperview
495 [[iSCLangController sharedInstance] removeDeferredOperationsFor: self];
496 [[NSNotificationCenter defaultCenter] removeObserver:self];
497 [super removeFromSuperview];
502 [[iSCLangController sharedInstance] removeDeferredOperationsFor: self];
503 [[iSCLangController sharedInstance] removeDeferredOperationsFor: [self window]];
504 [[NSNotificationCenter defaultCenter] removeObserver:self];
506 pthread_mutex_lock (&gLangMutex);
508 SetPtr(mWindowObj->slots + 0, self);
509 VMGlobals *g = gMainVMGlobals;
511 ++g->sp; SetObject(g->sp, mWindowObj); // push window obj
512 runInterpreter(g, s_closed, 1);
513 g->canCallOS = false;
516 pthread_mutex_unlock (&gLangMutex);
522 /* from command-w, scvm is the delegate */
523 - (void)setWindowShouldClose:(BOOL)boo
525 windowShouldClose = boo;
528 - (BOOL)windowShouldClose
530 return windowShouldClose;
533 const int circDiam = 20;
535 //static int ivxGUIScreen_frameNumber = 11;
537 - (void)drawRect: (CGRect)drawBounds
543 CGRect bounds = [self bounds];
544 screct.x = bounds.origin.x;
545 screct.y = bounds.origin.y;
546 screct.width = bounds.size.width;
547 screct.height = bounds.size.height;
548 mTopView->setInternalBounds(screct);
550 screct.x = drawBounds.origin.x;
551 screct.y = drawBounds.origin.y;
552 screct.width = drawBounds.size.width;
553 screct.height = drawBounds.size.height;
556 Rect qdrect = {(int)screct.x, (int)screct.y,
557 (int)(screct.x + screct.width), (int)(screct.y + screct.height)};
560 if(mTopView->isSubViewScroller()) {
561 ((SCScrollView*)mTopView)->drawSubViewIfNecessary(screct);
563 mTopView->drawIfNecessary(screct);
566 pthread_mutex_lock (&gLangMutex);
567 if (mWindowObj && NotNil(mWindowObj->slots+6)) {
568 CGRect cgrect = *(CGRect*)&drawBounds;
569 CGContextRef cgc = (CGContextRef)UIGraphicsGetCurrentContext();
570 CGContextSaveGState(cgc);
571 CGContextClipToRect(cgc, cgrect);
573 VMGlobals *g = gMainVMGlobals;
575 ++g->sp; SetObject(g->sp, mWindowObj); // push window obj
576 runInterpreter(g, s_callDrawFunc, 1);
577 g->canCallOS = false;
579 CGContextRestoreGState(cgc);
581 pthread_mutex_unlock (&gLangMutex);
585 NSDictionary *makeFontAttrDict(char *cFontName, float fontSize, SCColor sccolor)
587 NSMutableDictionary *dict = [NSMutableDictionary dictionary];
589 NSString *fontName = [NSString stringWithCString: cFontName];
591 UIFont *font = [UIFont fontWithName: fontName size: fontSize];
595 UIColor *nscolor = [UIColor colorWithRed: sccolor.red
598 alpha: sccolor.alpha];
599 [dict setObject: font forKey: NSFontAttributeName ];
600 [dict setObject: nscolor forKey: NSForegroundColorAttributeName ];
605 int nsStringDrawInRect(NSString *nsstring, SCRect screct, char *cFontName, float fontSize, SCColor sccolor)
608 NSDictionary* dict = makeFontAttrDict(cFontName, fontSize, sccolor);
609 if (!dict) return errFailed;
611 [nsstring drawInRect: NSRectToCGRect(SCtoNSRect(screct)) withAttributes: dict];
613 int len = [nsstring length];
614 char *buf = (char *) malloc(len+1);
615 [nsstring getCString:buf maxLength:len+1 encoding:NSASCIIStringEncoding];
617 CGRect drawBounds = SCtoCGRect(screct);
619 CGRect cgrect = *(CGRect*)&screct;
620 CGContextRef cgc = (CGContextRef)UIGraphicsGetCurrentContext();
621 CGContextSaveGState(cgc);
622 CGContextClipToRect(cgc, cgrect);
624 CGContextSelectFont(cgc, cFontName, fontSize, kCGEncodingMacRoman);
625 CGContextSetTextDrawingMode(cgc, kCGTextFill);
626 CGContextSetRGBFillColor(cgc, sccolor.red, sccolor.green, sccolor.blue, sccolor.alpha);
627 CGContextSetTextMatrix(cgc, CGAffineTransformMakeScale(1, -1));
628 CGContextShowTextAtPoint(cgc, drawBounds.origin.x, drawBounds.origin.y+drawBounds.size.height, buf, len);
630 CGContextRestoreGState(cgc);
636 CGSize nsStringSize(NSString *nsstring, char *cFontName, float fontSize, SCColor sccolor)
639 NSDictionary* dict = makeFontAttrDict(cFontName, fontSize, sccolor);
640 return [nsstring sizeWithAttributes: dict];
642 return CGSizeMake(0,0);
645 int nsStringDrawInRectAlign(NSString *nsstring, SCRect screct, char *cFontName, float fontSize, SCColor sccolor,
646 int hAlign, int vAlign, CGSize *outSize)
648 return nsStringDrawInRect(nsstring, screct, cFontName, fontSize, sccolor);
650 NSDictionary* dict = makeFontAttrDict(cFontName, fontSize, sccolor);
651 if (!dict) return errFailed;
653 NSSize size = [nsstring sizeWithAttributes: dict];
654 if (outSize) *outSize = size;
657 UIFont *font = [UIFont fontWithName: fontName size: fontSize];
659 NSRect drawBounds = SCtoNSRect(screct);
661 float hdiff = drawBounds.size.width - size.width;
662 float vdiff = drawBounds.size.height - size.height;
665 drawBounds.origin.x += hdiff * .5;
666 } else if (hAlign > 0) {
667 drawBounds.origin.x += hdiff;
671 drawBounds.origin.y += vdiff * .5;
672 } else if (vAlign > 0) {
673 drawBounds.origin.y += vdiff;
676 CGRect cgrect = *(CGRect*)&screct;
677 CGContextRef cgc = (CGContextRef)UIGraphicsGetCurrentContext();
678 CGContextSaveGState(cgc);
679 CGContextClipToRect(cgc, cgrect);
681 //[nsstring drawInRect: drawBounds withAttributes: dict];
683 CGContextRestoreGState(cgc);
690 int stringDrawInRect(char *cString, SCRect screct, char *cFontName, float fontSize, SCColor sccolor)
692 NSString *nsstring = [NSString stringWithCString: cString];
693 return nsStringDrawInRect(nsstring, screct, cFontName, fontSize, sccolor);
696 int stringDrawCenteredInRect(char *cString, SCRect screct, char *cFontName, float fontSize, SCColor sccolor)
698 NSString *nsstring = [NSString stringWithCString: cString];
699 return nsStringDrawInRectAlign(nsstring, screct, cFontName, fontSize, sccolor, 0, 0, NULL);
702 int stringDrawLeftInRect(char *cString, SCRect screct, char *cFontName, float fontSize, SCColor sccolor)
704 NSString *nsstring = [NSString stringWithCString: cString];
705 return nsStringDrawInRectAlign(nsstring, screct, cFontName, fontSize, sccolor, -1, 0, NULL);
708 int stringDrawRightInRect(char *cString, SCRect screct, char *cFontName, float fontSize, SCColor sccolor)
710 NSString *nsstring = [NSString stringWithCString: cString];
711 return nsStringDrawInRectAlign(nsstring, screct, cFontName, fontSize, sccolor, 1, 0, NULL);
715 SCColor blendColor(float blend, SCColor a, SCColor b)
718 c.red = a.red + blend * (b.red - a.red);
719 c.green = a.green + blend * (b.green - a.green);
720 c.blue = a.blue + blend * (b.blue - a.blue);
721 c.alpha = a.alpha + blend * (b.alpha - a.alpha);
725 void vPaintGradient(CGContextRef cgc, CGRect bounds, SCColor startColor, SCColor endColor, int numSteps)
727 numSteps = (int)sc_min(numSteps, floor(bounds.size.height));
728 float rNumSteps1 = 1. / (numSteps - 1.);
731 rect.origin.x = bounds.origin.x;
732 rect.size.width = bounds.size.width;
733 float step = bounds.size.height / numSteps;
734 rect.size.height = ceil(step);
736 for (int i=0; i<numSteps; ++i) {
737 float blend = i * rNumSteps1;
738 SCColor color = blendColor(blend, startColor, endColor);
739 CGContextSetRGBFillColor(cgc, color.red, color.green, color.blue, color.alpha);
741 rect.origin.y = bounds.origin.y + floor(i * step);
742 rect.size.height = ceil(bounds.origin.y + (i + 1) * step) - rect.origin.y;
744 CGContextFillRect(cgc, rect);
748 void hPaintGradient(CGContextRef cgc, CGRect bounds, SCColor startColor, SCColor endColor, int numSteps)
750 numSteps = (int)sc_min(numSteps, floor(bounds.size.width));
751 float rNumSteps1 = 1. / (numSteps - 1.);
754 rect.origin.y = bounds.origin.y;
755 rect.size.height = bounds.size.height;
756 float step = bounds.size.width / numSteps;
757 rect.size.width = ceil(step);
759 for (int i=0; i<numSteps; ++i) {
760 float blend = i * rNumSteps1;
761 SCColor color = blendColor(blend, startColor, endColor);
762 CGContextSetRGBFillColor(cgc, color.red, color.green, color.blue, color.alpha);
764 rect.origin.x = bounds.origin.x + floor(i * step);
765 rect.size.width = ceil(bounds.origin.x + (i + 1) * step) - rect.origin.x;
767 CGContextFillRect(cgc, rect);
771 void QDDrawBevelRect(CGContextRef cgc, CGRect bounds, float width, bool inout)
774 CGContextSetRGBFillColor(cgc, 0, 0, 0, 0.5);
776 CGContextSetRGBFillColor(cgc, 1, 1, 1, 0.5);
778 CGContextMoveToPoint(cgc, bounds.origin.x, bounds.origin.y);
779 CGContextAddLineToPoint(cgc, bounds.origin.x + bounds.size.width, bounds.origin.y);
780 CGContextAddLineToPoint(cgc, bounds.origin.x + bounds.size.width - width, bounds.origin.y + width);
781 CGContextAddLineToPoint(cgc, bounds.origin.x + width, bounds.origin.y + width);
782 CGContextAddLineToPoint(cgc, bounds.origin.x + width, bounds.origin.y + bounds.size.height - width);
783 CGContextAddLineToPoint(cgc, bounds.origin.x, bounds.origin.y + bounds.size.height);
784 CGContextAddLineToPoint(cgc, bounds.origin.x, bounds.origin.y);
785 CGContextFillPath(cgc);
788 CGContextSetRGBFillColor(cgc, 1, 1, 1, 0.5);
790 CGContextSetRGBFillColor(cgc, 0, 0, 0, 0.5);
792 CGContextMoveToPoint(cgc, bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height);
793 CGContextAddLineToPoint(cgc, bounds.origin.x, bounds.origin.y + bounds.size.height);
794 CGContextAddLineToPoint(cgc, bounds.origin.x + width, bounds.origin.y + bounds.size.height - width);
795 CGContextAddLineToPoint(cgc,
796 bounds.origin.x + bounds.size.width - width, bounds.origin.y + bounds.size.height - width);
797 CGContextAddLineToPoint(cgc, bounds.origin.x + bounds.size.width - width, bounds.origin.y + width);
798 CGContextAddLineToPoint(cgc, bounds.origin.x + bounds.size.width, bounds.origin.y);
799 CGContextAddLineToPoint(cgc, bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height);
800 CGContextFillPath(cgc);
803 - (void)startMenuTracking: (SCView*) inView
808 - (IBAction) toggleUIEditMode: (id) sender;
810 // if (!mTopView) return;
811 // mTopView->SetConstructionMode(!mTopView->GetConstructionMode());
812 // [self setNeedsDisplay: YES];
814 VMGlobals *g = gMainVMGlobals;
816 ++g->sp; SetObject(g->sp, mWindowObj); // push window obj
817 runInterpreter(g, s_toggleEditMode, 1);
818 g->canCallOS = false;
821 - (void)scrollViewResized:(NSNotification *)notification
823 [self setFrameSizeToMinimum];
825 // this seems to be needed for correct resize behaivour
827 SCVirtualMachine* scvm = [SCVirtualMachine sharedInstance];
828 SEL sel = @selector(display);
829 NSMethodSignature *sig = [NSView instanceMethodSignatureForSelector: sel];
831 NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature: sig];
832 [anInvocation setTarget: [[self window] contentView]];
833 [anInvocation setSelector: sel];
834 [scvm defer: anInvocation];
838 extern PyrSymbol* s_doaction;
840 - (void)userScrolled:(NSNotification *)notification
842 // if this happens from a visibleOrigin method we can't use sendMessage, so the action gets called from the lang
843 // similarly, this blocks the action from being fired due to scrolling because of incidental resize (i.e. remove a child)
844 if(!((SCScrollTopView*)mTopView)->isInSetClipViewOrigin()) {
845 mTopView->sendMessage(s_doaction, 0, 0, 0); // this must be a scroll view
849 - (void)setFrameSizeToMinimum
852 if (sv = [self enclosingScrollView]){
854 NSSize visSize = [[sv contentView] documentVisibleRect].size;
856 NSSize candidate = SCtoNSRect(((SCScrollTopView*)mTopView)->checkMinimumSize()).size;
857 if((candidate.width > visSize.width) || (candidate.height > visSize.height)){
858 [self setFrameSize: candidate]; // set then check visible rect again to account for scroll bars that may have appeared or vanished
859 visSize = [[sv contentView] visibleRect].size;
860 [self setFrameSize: NSMakeSize(sc_max(candidate.width, visSize.width), sc_max(candidate.height, visSize.height))];
862 [self setFrameSize: visSize]; // always at least this big
865 [self setNeedsDisplay: YES];
866 [sv setNeedsDisplay: YES];