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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #import "SCGraphView.h"
22 #import "SCVirtualMachine.h"
24 #include "PyrSymbol.h"
25 #include "PyrKernel.h"
26 #include "PyrMessage.h"
27 #include "VMGlobals.h"
29 #include "SC_BoundsMacros.h"
31 #include <Carbon/Carbon.h>
34 typedef long NSInteger
;
35 typedef unsigned long NSUInteger
;
37 typedef int NSInteger
;
38 typedef unsigned int NSUInteger
;
41 CGRect
SCtoCGRect(SCRect screct
);
43 extern PyrSymbol
*s_draw
;
44 extern PyrSymbol
*s_scview
;
45 extern PyrSymbol
*s_closed
;
46 extern PyrSymbol
*s_callDrawFunc
;
47 extern PyrSymbol
*s_toggleEditMode
;
49 @implementation SCGraphView
51 - (void)setAcceptsClickThrough
:(BOOL)boo
53 acceptsClickThrough
= boo
;
56 - (void)setAutoScrolls
:(BOOL)boo
;
61 - (BOOL)acceptsFirstMouse
:(NSEvent
*)theEvent
63 return acceptsClickThrough
;
71 - (BOOL)mouseDownCanMoveWindow
76 //eat all key Events might add this
77 - (BOOL)performKeyEquivalent
:(NSEvent
*)event
79 // NSString *characters = [event characters];
80 unsigned int modifiers
= [event modifierFlags
];
81 //control tab/escape doesn't get passed here at all ?
82 if((modifiers
& NSCommandKeyMask
) && !(modifiers
& NSFunctionKeyMask
)) // allow cmd-key only
83 [self keyDown
: event
];
84 return NO
; //for now pass on the event
87 - (void)flagsChanged
:(NSEvent
*)event
89 unsigned int modifiers
= [event modifierFlags
];
90 // NSLog(@" modifiers %d %08X",modifiers, modifiers);
92 SCView
*view
= mTopView
->focusView();
94 view
->keyModifiersChanged(modifiers
);
96 mTopView
->keyModifiersChanged(modifiers
);
100 - (void) keyDown
: (NSEvent
*) event
102 NSString
*characters
= [event characters
];
103 unsigned int modifiers
= [event modifierFlags
];
104 unichar character
= 0;
105 if([characters length
] > 0) {
106 character
= [characters characterAtIndex
: 0];
108 if ([event keyCode
] == 53){ //escape key breaks from modal or fullscreen windows
109 [[self window
] keyDown
:event
];
111 //control tab/escape doesn't get passed here at all ?
112 // NSLog(@"unicode %d length:%d clength:%d mTopView %08X modifiers %d %08X",
113 // character,[characters length],[characters cStringLength], mTopView, modifiers, modifiers);
116 // for some reason modifiers becomes 256 on my machine with no keys pressed. So need to mask against known keys.
117 uint32 allKnownModifiers
= NSAlphaShiftKeyMask | NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask
118 | NSAlternateKeyMask | NSHelpKeyMask | NSFunctionKeyMask | NSCommandKeyMask
;
119 if(character
== 9 && ((modifiers
& allKnownModifiers
) == 0)) {
120 mTopView
->tabPrevFocus();
122 } else if (character
== 25 && ((modifiers
& allKnownModifiers
) == NSShiftKeyMask
)) {
123 mTopView
->tabNextFocus();
125 } // other tab keys avail for user
126 SCView
*view
= mTopView
->focusView();
128 view
->keyDown(character
, modifiers
,[event keyCode
]);
130 mTopView
->keyDown(character
,modifiers
,[event keyCode
]);
134 if ([characters isEqual: @"w"] && (modifiers & NSCommandKeyMask)) {
135 [[SCVirtualMachine sharedInstance] endFullScreen: [self window]];
137 if ([characters isEqual: @"z"]) {
138 [[SCVirtualMachine sharedInstance] endFullScreen: [self window]];
144 - (void) keyUp
: (NSEvent
*) event
146 NSString
*characters
= [event characters
];
147 unsigned int modifiers
= [event modifierFlags
];
148 unichar character
= 0;
149 if([characters length
] > 0) {
150 character
= [characters characterAtIndex
: 0];
152 // NSLog(@"keyUp: unicode %d length:%d clength:%d mTopView %08X modifiers %d %08X",
153 // character,[characters length],[characters cStringLength], mTopView, modifiers, modifiers);
156 uint32 allKnownModifiers
= NSAlphaShiftKeyMask | NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask
157 | NSAlternateKeyMask | NSHelpKeyMask | NSFunctionKeyMask
;
158 if(character
== 9 && ((modifiers
& allKnownModifiers
) == 0)) {
160 } else if (character
== 25 && ((modifiers
& allKnownModifiers
) == NSShiftKeyMask
)) {
162 } // other tab keys avail for user
164 SCView
*view
= mTopView
->focusView();
166 view
->keyUp(character
, modifiers
,[event keyCode
]);
168 mTopView
->keyUp(character
,modifiers
,[event keyCode
]);
173 NSRect
SCtoNSRect(SCRect screct
)
176 nsrect.origin.x
= screct.x
;
177 nsrect.origin.y
= screct.y
;
178 nsrect.size.width
= screct.width
;
179 nsrect.size.height
= screct.height
;
183 static NSString
*sSCObjType
= @
"SuperCollider object address";
185 - (id)initWithFrame
: (NSRect
) frame
187 [super initWithFrame
: frame
];
188 [self registerForDraggedTypes
: [NSArray arrayWithObjects
: sSCObjType
, NSStringPboardType
, NSFilenamesPboardType
, nil]];
193 windowShouldClose
= YES
;
194 acceptsClickThrough
= YES
;
199 - (NSMenu
*) menuForEvent
:(NSEvent
*)theEvent
;
202 mouseLoc
= [self convertPoint
:[theEvent locationInWindow
] fromView
:nil];
203 SCPoint scpoint
= SCMakePoint(mouseLoc.x
, mouseLoc.y
);
204 if (!mTopView
) return 0;
205 SCView
*view
= mTopView
->findView(scpoint
);
207 return view
->contextMenu(scpoint
);
210 -(void)rightMouseDown
:(NSEvent
*)theEvent
{ [self mouseDown
:theEvent
]; }
211 -(void)otherMouseDown
:(NSEvent
*)theEvent
{ [self mouseDown
:theEvent
]; }
212 - (void)mouseDown
:(NSEvent
*)theEvent
214 //NSLog(@"SCGraphView MOUSEDOWN");
215 //[[self window] makeFirstResponder:self]; // there may be an active field editor
217 //BOOL isInside = YES;
219 //NSLog(@"Click count: %i", [theEvent clickCount]);
220 //if([theEvent clickCount] == 2) return;
221 if (!mTopView
) return;
222 unsigned int modifiers
= [theEvent modifierFlags
];
223 mouseLoc
= [self convertPoint
:[theEvent locationInWindow
] fromView
:nil];
224 SCPoint scpoint
= SCMakePoint(mouseLoc.x
, mouseLoc.y
);
225 SCView
*view
= mTopView
->findView(scpoint
);
227 [[self window
] makeFirstResponder
:self]; // there may be an active field editor
230 view
->makeFocus(true);
231 bool constructionmode
= mTopView
->ConstructionMode();
232 if(!constructionmode
)
234 view
->mouseDownAction(scpoint
, modifiers
,theEvent
);
235 view
->mouseBeginTrack(scpoint
, modifiers
,theEvent
);
237 view
->setConstructionModeFromPoint(scpoint
);
239 [self displayIfNeeded
];
241 while (keepOn
&& !mDragStarted
&& !mMenuView
) {
242 theEvent
= [[self window
] nextEventMatchingMask
: NSLeftMouseUpMask |NSRightMouseUp | NSOtherMouseUp |
243 NSLeftMouseDraggedMask | NSRightMouseDragged | NSOtherMouseDragged
244 | NSKeyDownMask | NSKeyUpMask
246 modifiers
= [theEvent modifierFlags
]; // added
247 mouseLoc
= [self convertPoint
:[theEvent locationInWindow
] fromView
:nil];
248 //isInside = [self mouse:mouseLoc inRect:[self bounds]];
249 scpoint
= SCMakePoint(mouseLoc.x
, mouseLoc.y
);
250 int evtype
= [theEvent type
];
251 switch ([theEvent type
]) {
252 case NSLeftMouseDown
:
253 case NSRightMouseDown
:
256 view
->doConstructionMove(scpoint
);
259 view
->mouseDownAction(scpoint
, modifiers
,theEvent
);
262 case NSLeftMouseDragged
:
263 if(autoScrolls
) [self autoscroll
:theEvent
];
264 case NSRightMouseDragged
:
265 case NSOtherMouseDragged
:
268 view
->doConstructionMove(scpoint
);
271 view
->mouseTrack(scpoint
, modifiers
,theEvent
);
272 view
->mouseMoveAction(scpoint
, modifiers
,theEvent
);
280 // view->doConstructionMove(scpoint);
284 // if(!view.GetSCObj()) break;
285 view
->mouseUpAction(scpoint
, modifiers
,theEvent
);
286 view
->mouseEndTrack(scpoint
, modifiers
,theEvent
);
291 if(!constructionmode
)
293 [self keyDown
:theEvent
];
297 if(!constructionmode
)
299 [self keyUp
:theEvent
];
303 post("evtype %d %4.4s\n", evtype
, (char*)&evtype
);
304 /* Ignore any other kind of event. */
308 [self displayIfNeeded
];
316 -(void)mouseMoved
:(NSEvent
*)theEvent
319 if (!mTopView
) return;
320 unsigned int modifiers
= [theEvent modifierFlags
];
321 mouseLoc
= [self convertPoint
:[theEvent locationInWindow
] fromView
:nil];
322 SCPoint scpoint
= SCMakePoint(mouseLoc.x
, mouseLoc.y
);
323 SCView
*view
= mTopView
->findView(scpoint
);
327 // view->makeFocus(true);
328 view
->mouseOver(scpoint
, modifiers
, theEvent
);
332 //scrollWheel:(NSEvent*)theEvent;
334 - (void)setSCObject
: (struct PyrObject
*)inObject
;
336 mWindowObj
= inObject
;
339 - (struct PyrObject
*)getSCObject
344 void damageFunc(SCRect inRect
, void* inData
)
346 SCGraphView
*view
= (SCGraphView
*)inData
;
348 [view setNeedsDisplayInRect
: SCtoNSRect(inRect
)];
351 void dragFunc(SCPoint where
, PyrSlot
*inSlot
, NSString
* inString
, NSString
* label
, void* inData
)
353 SCGraphView
*view
= (SCGraphView
*)inData
;
354 NSPoint point
= NSMakePoint(where.x
, where.y
);
355 [view beginDragFrom
: point of
: inSlot string
: inString label
: label
];
358 - (unsigned int)draggingSourceOperationMaskForLocal
: (BOOL)flag
360 return flag ? NSDragOperationEvery
: NSDragOperationNone
;
363 - (void)setSCTopView
: (SCTopView
*)inView
366 mTopView
->setDamageCallback(damageFunc
, (void*)self);
367 mTopView
->setDragCallback(dragFunc
);
368 mTopView
->SetNSView(self);
369 oldBounds
= NSMakeRect(0, 0, 0, 0);
374 //printf("dealloc %08X mTopView %08X\n", self, mTopView);
383 [[self window
] close
];
386 - (void)removeFromSuperview
388 [[SCVirtualMachine sharedInstance
] removeDeferredOperationsFor
: self];
389 [[NSNotificationCenter defaultCenter
] removeObserver
:self];
390 [super removeFromSuperview
];
395 [[SCVirtualMachine sharedInstance
] removeDeferredOperationsFor
: self];
396 [[SCVirtualMachine sharedInstance
] removeDeferredOperationsFor
: [self window
]];
397 [[NSNotificationCenter defaultCenter
] removeObserver
:self];
399 pthread_mutex_lock (&gLangMutex
);
401 SetPtr(mWindowObj
->slots
+ 0, self);
402 VMGlobals
*g
= gMainVMGlobals
;
404 ++g
->sp
; SetObject(g
->sp
, mWindowObj
); // push window obj
405 runInterpreter(g
, s_closed
, 1);
406 g
->canCallOS
= false;
409 pthread_mutex_unlock (&gLangMutex
);
414 extern PyrSymbol
* s_didBecomeKey
;
415 extern PyrSymbol
* s_didResignKey
;
416 - (void) didResignKey
{
418 if(NotNil(mWindowObj
->slots
+ 11)){ // check whether endFrontAction is nil
419 pthread_mutex_lock (&gLangMutex
);
420 SetPtr(mWindowObj
->slots
+ 0, self);
421 VMGlobals
*g
= gMainVMGlobals
;
424 ++g
->sp
; SetObject(g
->sp
, mWindowObj
); // push window obj
425 runInterpreter(g
, s_didResignKey
, 1);
426 g
->canCallOS
= false;
427 pthread_mutex_unlock (&gLangMutex
);
432 - (void) didBecomeKey
{
434 if(NotNil(mWindowObj
->slots
+ 10)){
436 pthread_mutex_lock (&gLangMutex
);
437 SetPtr(mWindowObj
->slots
+ 0, self);
438 VMGlobals
*g
= gMainVMGlobals
;
440 ++g
->sp
; SetObject(g
->sp
, mWindowObj
); // push window obj
441 runInterpreter(g
, s_didBecomeKey
, 1);
442 g
->canCallOS
= false;
443 pthread_mutex_unlock (&gLangMutex
);
447 /* from command-w, scvm is the delegate */
448 - (void)setWindowShouldClose
:(BOOL)boo
450 windowShouldClose
= boo
;
453 - (BOOL)windowShouldClose
455 return windowShouldClose
;
458 const int circDiam
= 20;
460 - (NSImage
*) makeDragImage
: (PyrSlot
*)slot label
: (NSString
*)label
469 PyrClass
*classobj
= classOfSlot(slot
);
470 nsstring
= [NSString stringWithCString
: slotRawSymbol(&classobj
->name
)->name
];
471 if (!nsstring
) return 0;
473 nsstring
= @
"No Data!";
476 NSMutableDictionary
*dict
= [NSMutableDictionary dictionary
];
477 NSFont
*font
= [NSFont fontWithName
: @
"Helvetica" size
: 12];
479 [dict setObject
: font forKey
: NSFontAttributeName
];
481 NSSize strSize
= [nsstring sizeWithAttributes
: dict
];
482 NSRect strRect
= NSMakeRect(circDiam
, 0, circDiam
+ strSize.width
, strSize.height
);
484 NSSize size
= NSMakeSize(circDiam
+strSize.width
, sc_max(circDiam
, strSize.height
));
486 NSImage
*image
= [[NSImage alloc
] initWithSize
: size
];
487 if (!image
) return 0;
492 NSColor
*colorClear
= [NSColor colorWithCalibratedRed
: 0
496 NSColor
*colorTransBlack
= [NSColor colorWithCalibratedRed
: 0
500 NSColor
*colorTransBlue
= [NSColor colorWithCalibratedRed
: 0
504 /*NSColor *colorTransLtBlue = [NSColor colorWithCalibratedRed: 0.8
508 NSColor
*colorTransWhite
= [NSColor colorWithCalibratedRed
: 1
512 NSColor
*colorCaptionBackgnd
= [NSColor colorWithCalibratedRed
: 0
516 NSColor
*colorWhite
= [NSColor colorWithCalibratedRed
: 1
521 [dict setObject
: colorWhite forKey
: NSForegroundColorAttributeName
];
525 [NSBezierPath fillRect
: NSMakeRect(0,0,size.width
,size.height
)];
526 NSBezierPath
*path
= [NSBezierPath bezierPathWithOvalInRect
: NSMakeRect(1,1,circDiam
-2,circDiam
-2)];
528 [path setLineWidth
: 1.5];
529 [colorTransBlue set
];
532 NSBezierPath
*hilite
= [NSBezierPath bezierPathWithOvalInRect
:
533 NSMakeRect(circDiam
*0.3, circDiam
*0.7, circDiam
*0.4, circDiam
*0.15)];
535 [colorTransWhite set
];
538 [colorTransBlack set
];
541 [colorCaptionBackgnd set
];
542 [NSBezierPath fillRect
: strRect
];
544 [nsstring drawInRect
: strRect withAttributes
: dict
];
552 - (void) beginDragFrom
: (NSPoint
)where of
: (PyrSlot
*)slot string
:(NSString
*) string label
:(NSString
*) label
554 NSImage
*image
= [self makeDragImage
: slot label
: label
];
556 NSPasteboard
*pboard
= [NSPasteboard pasteboardWithName
: NSDragPboard
];
557 [pboard declareTypes
: [NSArray arrayWithObjects
: sSCObjType
, NSStringPboardType
, nil] owner
: self];
560 NSData
*data
= [NSData dataWithBytes
: &fakeData length
: sizeof(int)];
562 [pboard setData
: data forType
: sSCObjType
];
563 [pboard setString
: string forType
: NSStringPboardType
];
565 NSSize imageSize
= [image size
];
566 where.x
-= circDiam
/ 2;
567 where.y
+= circDiam
/ 4;
569 NSSize dragOffset
= NSMakeSize(0.0, 0.0);
571 [self dragImage
: image at
: where offset
: dragOffset event
: [NSApp currentEvent
]
572 pasteboard
: pboard source
: self slideBack
: YES
];
575 - (unsigned int)draggingEntered
:(id)dragInfo
{
576 if (!mTopView
) return NSDragOperationNone
;
577 NSPasteboard
* pboard
= [dragInfo draggingPasteboard
];
578 if ([[pboard types
] containsObject
: sSCObjType
]) {
580 } else if ([[pboard types
] containsObject
: NSStringPboardType
]) {
581 NSString
*nsstring
= [pboard stringForType
: NSStringPboardType
];
582 if (!nsstring
) return NSDragOperationNone
;
583 pthread_mutex_lock (&gLangMutex
);
584 VMGlobals
*g
= gMainVMGlobals
;
585 PyrString
* pstrobj
= newPyrString(g
->gc
, [nsstring UTF8String
], 0, true);
586 int classVarIndex
= slotRawInt(&getsym("SCView")->u.classobj
->classVarIndex
);
587 SetObject(&g
->classvars
->slots
[classVarIndex
+0], pstrobj
); // currentDrag
588 g
->gc
->GCWrite(g
->classvars
, pstrobj
);
590 //PyrSymbol *method = getsym("importDrag");
591 //g->canCallOS = true;
592 ++g
->sp
; SetObject(g
->sp
, s_scview
->u.classobj
);
593 //runInterpreter(g, method, 1);
594 //g->canCallOS = false;
596 pthread_mutex_unlock (&gLangMutex
);
599 NSData
*data
= [NSData dataWithBytes
: &fakeData length
: sizeof(int)];
600 [pboard setData
: data forType
: sSCObjType
];
602 } else if ([[pboard types
] containsObject
: NSFilenamesPboardType
]) {
603 NSArray
*files
= [pboard propertyListForType
: NSFilenamesPboardType
];
604 if (!files
) return NSDragOperationNone
;
605 pthread_mutex_lock (&gLangMutex
);
606 VMGlobals
*g
= gMainVMGlobals
;
607 int size
= [files count
];
608 PyrObject
* array
= newPyrArray(g
->gc
, size
, 0, true);
610 for (int i
=0; i
<size
; ++i
) {
611 NSString
*path
= [files objectAtIndex
: i
];
612 PyrString
*string
= newPyrString(g
->gc
, [path UTF8String
], 0, true);
613 SetObject(array
->slots
+ array
->size
, string
);
615 g
->gc
->GCWrite(array
, string
);
618 int classVarIndex
= slotRawInt(&getsym("SCView")->u.classobj
->classVarIndex
);
619 SetObject(&g
->classvars
->slots
[classVarIndex
+0], array
);
620 g
->gc
->GCWrite(g
->classvars
, array
);
622 pthread_mutex_unlock (&gLangMutex
);
625 NSData
*data
= [NSData dataWithBytes
: &fakeData length
: sizeof(int)];
626 [pboard setData
: data forType
: sSCObjType
];
629 return NSDragOperationNone
;
632 NSPoint mouseLoc
= [self convertPoint
:[dragInfo draggingLocation
] fromView
:nil];
633 SCPoint scpoint
= SCMakePoint(mouseLoc.x
, mouseLoc.y
);
634 SCView
*view
= mTopView
->findView(scpoint
);
635 if(!view
&& mTopView
->ConstructionMode())
638 bool flag
= view
->canReceiveDrag();
639 view
->draggingEntered(scpoint
);
640 mTopView
->setDragView(flag ? view
: 0);
641 [self displayIfNeeded
];
642 return flag ? NSDragOperationEvery
: NSDragOperationNone
;
644 mTopView
->setDragView(0);
645 [self displayIfNeeded
];
646 return NSDragOperationNone
;
650 - (unsigned int)draggingUpdated
:(id)dragInfo
{
651 if (!mTopView
) return NSDragOperationNone
;
652 NSPoint mouseLoc
= [self convertPoint
:[dragInfo draggingLocation
] fromView
:nil];
654 SCPoint scpoint
= SCMakePoint(mouseLoc.x
, mouseLoc.y
);
655 SCView
*view
= mTopView
->findView(scpoint
);
656 if(!view
&& mTopView
->ConstructionMode())
659 bool flag
= view
->canReceiveDrag();
660 mTopView
->setDragView(flag ? view
: 0);
661 view
->draggingUpdated(scpoint
);
662 [self displayIfNeeded
];
663 return flag ? NSDragOperationEvery
: NSDragOperationNone
;
665 mTopView
->setDragView(0);
666 [self displayIfNeeded
];
667 return NSDragOperationNone
;
671 - (void)draggingExited
:(id)dragInfo
{
672 if (!mTopView
) return;
673 //NSPoint mouseLoc = [self convertPoint:[dragInfo draggingLocation] fromView:nil];
674 //SCPoint scpoint = SCMakePoint(mouseLoc.x, mouseLoc.y);
675 mTopView
->setDragView(0);
676 [self displayIfNeeded
];
679 - (BOOL)prepareForDragOperation
:(id)dragInfo
{
680 //post("prepareForDragOperation %08X\n", self);
681 if (!mTopView
) return FALSE;
682 NSPoint mouseLoc
= [self convertPoint
:[dragInfo draggingLocation
] fromView
:nil];
683 SCPoint scpoint
= SCMakePoint(mouseLoc.x
, mouseLoc.y
);
684 SCView
*view
= mTopView
->findView(scpoint
);
685 if(!view
&& mTopView
->ConstructionMode())
688 bool flag
= view
->canReceiveDrag();
689 mTopView
->setDragView(flag ? view
: 0);
690 [self displayIfNeeded
];
691 return flag ? YES
: NO
;
693 mTopView
->setDragView(0);
694 [self displayIfNeeded
];
699 - (BOOL)performDragOperation
:(id)dragInfo
{
700 if (!mTopView
) return NO
;
701 // post("performDragOperation %08X\n", self);
702 NSPoint mouseLoc
= [self convertPoint
:[dragInfo draggingLocation
] fromView
:nil];
703 SCPoint scpoint
= SCMakePoint(mouseLoc.x
, mouseLoc.y
);
704 SCView
*view
= mTopView
->findView(scpoint
);
705 if(!view
&& mTopView
->ConstructionMode())
708 bool flag
= view
->canReceiveDrag();
710 mTopView
->setDragView(view
);
713 mTopView
->setDragView(0);
715 [self displayIfNeeded
];
716 return flag ? YES
: NO
;
718 mTopView
->setDragView(0);
719 [self displayIfNeeded
];
724 - (void)concludeDragOperation
:(id)sender
{
725 if (mTopView
) mTopView
->setDragView(0);
726 [self displayIfNeeded
];
728 //post("concludeDragOperation %08X\n", self);
731 //static int ivxGUIScreen_frameNumber = 11;
733 - (void)drawRect
: (NSRect
)drawBounds
739 NSRect bounds
= [self bounds
];
740 screct.x
= bounds.origin.x
;
741 screct.y
= bounds.origin.y
;
742 screct.width
= bounds.size.width
;
743 screct.height
= bounds.size.height
;
745 if(!NSEqualRects(bounds
, oldBounds
)){
746 mTopView
->setInternalBounds(screct
);
751 screct.x
= drawBounds.origin.x
;
752 screct.y
= drawBounds.origin.y
;
753 screct.width
= drawBounds.size.width
;
754 screct.height
= drawBounds.size.height
;
756 CGContextRef cgc
= (CGContextRef
)[[NSGraphicsContext currentContext
] graphicsPort
];
757 CGContextSaveGState(cgc
);
758 //CGContextClipToRect(cgc, CGRectMake(screct.x, screct.y, screct.width, screct.height));
759 CGContextClipToRect(cgc
, *(CGRect
*)&bounds
);
764 SetRect(&qdrect, (int)screct.x, (int)screct.y,
765 (int)(screct.x + screct.width), (int)(screct.y + screct.height));
769 const CGRect
*dirtyRects
;
771 NSInteger numDirtyRects
;
773 [self getRectsBeingDrawn
:(const NSRect
**)&dirtyRects count
:(NSInteger
*)&numDirtyRects
];
776 //post("numrects: %i\n", numDirtyRects);
777 for(; i
< numDirtyRects
; ++i
) {
778 curRect
= *(dirtyRects
+i
);
780 screct.x
= curRect.origin.x
;
781 screct.y
= curRect.origin.y
;
782 screct.width
= curRect.size.width
;
783 screct.height
= curRect.size.height
;
784 //post("(%2.2f, %2.2f, %2.2f, %2.2f)\n", screct.x, screct.y, screct.width, screct.height);
786 CGContextSaveGState(cgc
);
787 CGContextClipToRect(cgc
, curRect
);
788 if(mTopView
->isSubViewScroller())
790 ((SCScrollView
*)mTopView
)->drawSubViewIfNecessary(screct
);
794 mTopView
->drawIfNecessary(screct
);
796 CGContextRestoreGState(cgc
);
799 CGContextRestoreGState(cgc
);
802 pthread_mutex_lock (&gLangMutex
);
803 if (mWindowObj
&& NotNil(mWindowObj
->slots
+6)) {
804 CGRect cgrect
= *(CGRect
*)&drawBounds
;
805 CGContextRef cgc
= (CGContextRef
)[[NSGraphicsContext currentContext
] graphicsPort
];
806 CGContextSaveGState(cgc
);
807 CGContextClipToRect(cgc
, cgrect
);
809 VMGlobals
*g
= gMainVMGlobals
;
811 ++g
->sp
; SetObject(g
->sp
, mWindowObj
); // push window obj
812 runInterpreter(g
, s_callDrawFunc
, 1);
813 g
->canCallOS
= false;
815 CGContextRestoreGState(cgc
);
817 pthread_mutex_unlock (&gLangMutex
);
821 NSDictionary
*makeFontAttrDict(char *cFontName
, float fontSize
, SCColor sccolor
)
823 NSMutableDictionary
*dict
= [NSMutableDictionary dictionary
];
825 NSString
*fontName
= [NSString stringWithCString
: cFontName
];
827 NSFont
*font
= [NSFont fontWithName
: fontName size
: fontSize
];
831 NSColor
*nscolor
= [NSColor colorWithCalibratedRed
: sccolor.red
834 alpha
: sccolor.alpha
];
835 [dict setObject
: font forKey
: NSFontAttributeName
];
836 [dict setObject
: nscolor forKey
: NSForegroundColorAttributeName
];
840 int nsStringDrawInRect(NSString
*nsstring
, SCRect screct
, char *cFontName
, float fontSize
, SCColor sccolor
)
842 NSDictionary
* dict
= makeFontAttrDict(cFontName
, fontSize
, sccolor
);
843 if (!dict
) return errFailed
;
845 [nsstring drawInRect
: SCtoNSRect(screct
) withAttributes
: dict
];
850 NSSize
nsStringSize(NSString
*nsstring
, char *cFontName
, float fontSize
, SCColor sccolor
)
852 NSDictionary
* dict
= makeFontAttrDict(cFontName
, fontSize
, sccolor
);
853 return [nsstring sizeWithAttributes
: dict
];
856 int nsStringDrawInRectAlign(NSString
*nsstring
, SCRect screct
, char *cFontName
, float fontSize
, SCColor sccolor
,
857 int hAlign
, int vAlign
, NSSize
*outSize
)
859 NSDictionary
* dict
= makeFontAttrDict(cFontName
, fontSize
, sccolor
);
860 if (!dict
) return errFailed
;
862 NSSize size
= [nsstring sizeWithAttributes
: dict
];
863 if (outSize
) *outSize
= size
;
865 NSRect drawBounds
= SCtoNSRect(screct
);
867 float hdiff
= drawBounds.size.width
- size.width
;
868 float vdiff
= drawBounds.size.height
- size.height
;
871 drawBounds.origin.x
+= hdiff
* .5;
872 } else if (hAlign
> 0) {
873 drawBounds.origin.x
+= hdiff
;
877 drawBounds.origin.y
+= vdiff
* .5;
878 } else if (vAlign
> 0) {
879 drawBounds.origin.y
+= vdiff
;
882 CGRect cgrect
= SCtoCGRect(screct
);
883 CGContextRef cgc
= (CGContextRef
)[[NSGraphicsContext currentContext
] graphicsPort
];
884 CGContextSaveGState(cgc
);
885 CGContextClipToRect(cgc
, cgrect
);
887 [nsstring drawInRect
: drawBounds withAttributes
: dict
];
889 CGContextRestoreGState(cgc
);
894 int stringDrawInRect(const char *cString
, SCRect screct
, char *cFontName
, float fontSize
, SCColor sccolor
)
896 NSString
*nsstring
= [NSString stringWithCString
: cString
];
897 return nsStringDrawInRect(nsstring
, screct
, cFontName
, fontSize
, sccolor
);
900 int stringDrawCenteredInRect(const char *cString
, SCRect screct
, char *cFontName
, float fontSize
, SCColor sccolor
)
902 NSString
*nsstring
= [NSString stringWithCString
: cString
];
903 return nsStringDrawInRectAlign(nsstring
, screct
, cFontName
, fontSize
, sccolor
, 0, 0, NULL
);
906 int stringDrawLeftInRect(const char *cString
, SCRect screct
, char *cFontName
, float fontSize
, SCColor sccolor
)
908 NSString
*nsstring
= [NSString stringWithCString
: cString
];
909 return nsStringDrawInRectAlign(nsstring
, screct
, cFontName
, fontSize
, sccolor
, -1, 0, NULL
);
912 int stringDrawRightInRect(const char *cString
, SCRect screct
, char *cFontName
, float fontSize
, SCColor sccolor
)
914 NSString
*nsstring
= [NSString stringWithCString
: cString
];
915 return nsStringDrawInRectAlign(nsstring
, screct
, cFontName
, fontSize
, sccolor
, 1, 0, NULL
);
918 SCColor
blendColor(float blend
, SCColor a
, SCColor b
)
921 c.red
= a.red
+ blend
* (b.red
- a.red
);
922 c.green
= a.green
+ blend
* (b.green
- a.green
);
923 c.blue
= a.blue
+ blend
* (b.blue
- a.blue
);
924 c.alpha
= a.alpha
+ blend
* (b.alpha
- a.alpha
);
928 void vPaintGradient(CGContextRef cgc
, CGRect bounds
, SCColor startColor
, SCColor endColor
, int numSteps
)
930 numSteps
= (int)sc_min(numSteps
, floor(bounds.size.height
));
931 float rNumSteps1
= 1.
/ (numSteps
- 1.
);
934 rect.origin.x
= bounds.origin.x
;
935 rect.size.width
= bounds.size.width
;
936 float step
= bounds.size.height
/ numSteps
;
937 rect.size.height
= ceil(step
);
939 for (int i
=0; i
<numSteps
; ++i
) {
940 float blend
= i
* rNumSteps1
;
941 SCColor color
= blendColor(blend
, startColor
, endColor
);
942 CGContextSetRGBFillColor(cgc
, color.red
, color.green
, color.blue
, color.alpha
);
944 rect.origin.y
= bounds.origin.y
+ floor(i
* step
);
945 rect.size.height
= ceil(bounds.origin.y
+ (i
+ 1) * step
) - rect.origin.y
;
947 CGContextFillRect(cgc
, rect
);
951 void hPaintGradient(CGContextRef cgc
, CGRect bounds
, SCColor startColor
, SCColor endColor
, int numSteps
)
953 numSteps
= (int)sc_min(numSteps
, floor(bounds.size.width
));
954 float rNumSteps1
= 1.
/ (numSteps
- 1.
);
957 rect.origin.y
= bounds.origin.y
;
958 rect.size.height
= bounds.size.height
;
959 float step
= bounds.size.width
/ numSteps
;
960 rect.size.width
= ceil(step
);
962 for (int i
=0; i
<numSteps
; ++i
) {
963 float blend
= i
* rNumSteps1
;
964 SCColor color
= blendColor(blend
, startColor
, endColor
);
965 CGContextSetRGBFillColor(cgc
, color.red
, color.green
, color.blue
, color.alpha
);
967 rect.origin.x
= bounds.origin.x
+ floor(i
* step
);
968 rect.size.width
= ceil(bounds.origin.x
+ (i
+ 1) * step
) - rect.origin.x
;
970 CGContextFillRect(cgc
, rect
);
974 void QDDrawBevelRect(CGContextRef cgc
, CGRect bounds
, float width
, bool inout)
977 CGContextSetRGBFillColor(cgc
, 0, 0, 0, 0.5);
979 CGContextSetRGBFillColor(cgc
, 1, 1, 1, 0.5);
981 CGContextMoveToPoint(cgc
, bounds.origin.x
, bounds.origin.y
);
982 CGContextAddLineToPoint(cgc
, bounds.origin.x
+ bounds.size.width
, bounds.origin.y
);
983 CGContextAddLineToPoint(cgc
, bounds.origin.x
+ bounds.size.width
- width
, bounds.origin.y
+ width
);
984 CGContextAddLineToPoint(cgc
, bounds.origin.x
+ width
, bounds.origin.y
+ width
);
985 CGContextAddLineToPoint(cgc
, bounds.origin.x
+ width
, bounds.origin.y
+ bounds.size.height
- width
);
986 CGContextAddLineToPoint(cgc
, bounds.origin.x
, bounds.origin.y
+ bounds.size.height
);
987 CGContextAddLineToPoint(cgc
, bounds.origin.x
, bounds.origin.y
);
988 CGContextFillPath(cgc
);
991 CGContextSetRGBFillColor(cgc
, 1, 1, 1, 0.5);
993 CGContextSetRGBFillColor(cgc
, 0, 0, 0, 0.5);
995 CGContextMoveToPoint(cgc
, bounds.origin.x
+ bounds.size.width
, bounds.origin.y
+ bounds.size.height
);
996 CGContextAddLineToPoint(cgc
, bounds.origin.x
, bounds.origin.y
+ bounds.size.height
);
997 CGContextAddLineToPoint(cgc
, bounds.origin.x
+ width
, bounds.origin.y
+ bounds.size.height
- width
);
998 CGContextAddLineToPoint(cgc
,
999 bounds.origin.x
+ bounds.size.width
- width
, bounds.origin.y
+ bounds.size.height
- width
);
1000 CGContextAddLineToPoint(cgc
, bounds.origin.x
+ bounds.size.width
- width
, bounds.origin.y
+ width
);
1001 CGContextAddLineToPoint(cgc
, bounds.origin.x
+ bounds.size.width
, bounds.origin.y
);
1002 CGContextAddLineToPoint(cgc
, bounds.origin.x
+ bounds.size.width
, bounds.origin.y
+ bounds.size.height
);
1003 CGContextFillPath(cgc
);
1006 - (void)startMenuTracking
: (SCView
*) inView
1011 - (IBAction
) toggleUIEditMode
: (id) sender
;
1013 // if (!mTopView) return;
1014 // mTopView->SetConstructionMode(!mTopView->GetConstructionMode());
1015 // [self setNeedsDisplay: YES];
1017 VMGlobals
*g
= gMainVMGlobals
;
1018 g
->canCallOS
= true;
1019 ++g
->sp
; SetObject(g
->sp
, mWindowObj
); // push window obj
1020 runInterpreter(g
, s_toggleEditMode
, 1);
1021 g
->canCallOS
= false;
1024 - (void)scrollViewResized
:(NSNotification
*)notification
1026 [self setFrameSizeToMinimum
];
1028 // this seems to be needed for correct resize behaivour
1029 SCVirtualMachine
* scvm
= [SCVirtualMachine sharedInstance
];
1030 SEL sel
= @selector(display
);
1031 NSMethodSignature
*sig
= [NSView instanceMethodSignatureForSelector
: sel
];
1033 NSInvocation
*anInvocation
= [NSInvocation invocationWithMethodSignature
: sig
];
1034 [anInvocation setTarget
: [[self window
] contentView
]];
1035 [anInvocation setSelector
: sel
];
1036 [scvm defer
: anInvocation
];
1039 extern PyrSymbol
* s_doaction
;
1041 - (void)userScrolled
:(NSNotification
*)notification
1043 // if this happens from a visibleOrigin method we can't use sendMessage, so the action gets called from the lang
1044 // similarly, this blocks the action from being fired due to scrolling because of incidental resize (i.e. remove a child)
1045 if(!((SCScrollTopView
*)mTopView
)->isInSetClipViewOrigin()) {
1046 mTopView
->sendMessage(s_doaction
, 0, 0, 0); // this must be a scroll view
1050 - (void)setFrameSizeToMinimum
1053 if (sv
= [self enclosingScrollView
]){
1055 NSSize visSize
= [[sv contentView
] documentVisibleRect
].size
;
1057 NSSize candidate
= SCtoNSRect(((SCScrollTopView
*)mTopView
)->checkMinimumSize()).size
;
1058 if((candidate.width
> visSize.width
) ||
(candidate.height
> visSize.height
)){
1059 [self setFrameSize
: candidate
]; // set then check visible rect again to account for scroll bars that may have appeared or vanished
1060 visSize
= [[sv contentView
] visibleRect
].size
;
1061 [self setFrameSize
: NSMakeSize(sc_max(candidate.width
, visSize.width
), sc_max(candidate.height
, visSize.height
))];
1063 [self setFrameSize
: visSize
]; // always at least this big
1066 [self setNeedsDisplay
: YES
];
1067 [sv setNeedsDisplay
: YES
];