class library: Spawner - don't access PriorityQueue-array
[supercollider.git] / editors / scapp / SCView.M
blobd7b0e40501118f41a6b77ddff0e49a14f19c91c2
1 /*
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
22 #include <Cocoa/Cocoa.h>
23 #include <Carbon/Carbon.h>
24 #include <pthread.h>
25 #include "SCBase.h"
26 #include "PyrSymbol.h"
27 #include "PyrPrimitive.h"
28 #include "PyrObject.h"
29 #include "PyrKernel.h"
30 #include "GC.h"
31 #include "VMGlobals.h"
32 #include "SC_RGen.h"
33 #include "SC_BoundsMacros.h"
34 #include "SC_InlineBinaryOp.h"
35 #include "SCGraphView.h"
36 #import "SCVirtualMachine.h"
39 #include "SCView.h"
40 #import "SCImage.h"
43 void QDDrawBevelRect(CGContextRef cgc, CGRect bounds, float width, bool inout);
45 SCViewMaker *gSCViewMakers = 0;
46 SCView *gAnimatedViews = 0;
48 extern PyrSymbol* s_color;
49 extern PyrSymbol* s_doaction;
50 extern PyrSymbol* s_draw;
52 PyrSymbol* s_x;
53 PyrSymbol* s_y;
54 PyrSymbol* s_lo;
55 PyrSymbol* s_hi;
56 PyrSymbol* s_range;
57 PyrSymbol* s_scview;
58 PyrSymbol* s_sccontview;
59 PyrSymbol* s_sctopview;
60 PyrSymbol* s_scscrollview;
61 PyrSymbol* s_beginDrag;
62 PyrSymbol* s_receiveDrag;
63 PyrSymbol* s_canReceiveDrag;
64 PyrSymbol* s_mouseDown;
65 PyrSymbol* s_mouseUp;
66 PyrSymbol* s_callDrawFunc;
67 PyrSymbol* s_toggleEditMode;
69 extern pthread_mutex_t gLangMutex;
71 int stringDrawCenteredInRect(const char *cString, SCRect screct, char *cFontName, float fontSize, SCColor sccolor);
72 int stringDrawLeftInRect(const char *cString, SCRect screct, char *cFontName, float fontSize, SCColor sccolor);
73 int stringDrawRightInRect(const char *cString, SCRect screct, char *cFontName, float fontSize, SCColor sccolor);
75 int nsStringDrawInRectAlign(NSString *nsstring, SCRect screct, char *cFontName, float fontSize, SCColor sccolor, int hAlign, int vAlign, NSSize *outSize);
77 RGBColor SCtoQDColor(SCColor sccolor)
79 RGBColor qdcolor;
81 qdcolor.red = (unsigned short)(sccolor.red * 65535.);
82 qdcolor.green = (unsigned short)(sccolor.green * 65535.);
83 qdcolor.blue = (unsigned short)(sccolor.blue * 65535.);
84 return qdcolor;
87 // CoreGraphics coords get switched around in an NSQuickDrawView
88 Rect SCtoQDRect(SCRect screct)
90 Rect qdrect;
92 qdrect.left = (int)screct.x;
93 qdrect.top = (int)screct.y;
94 qdrect.right = (int)(screct.x + screct.width);
95 qdrect.bottom = (int)(screct.y + screct.height);
96 return qdrect;
99 CGRect SCtoCGRect(SCRect screct)
101 CGRect cgrect;
103 cgrect.origin.x = screct.x;
104 cgrect.origin.y = screct.y;
105 cgrect.size.width = screct.width;
106 cgrect.size.height = screct.height;
107 return cgrect;
110 int slotColorVal(PyrSlot *slot, SCColor *sccolor)
112 if (!(isKindOfSlot(slot, s_color->u.classobj))) return errWrongType;
114 PyrSlot *slots = slotRawObject(slot)->slots;
116 int err;
117 err = slotFloatVal(slots+0, &sccolor->red);
118 if (err) return err;
119 err = slotFloatVal(slots+1, &sccolor->green);
120 if (err) return err;
121 err = slotFloatVal(slots+2, &sccolor->blue);
122 if (err) return err;
123 err = slotFloatVal(slots+3, &sccolor->alpha);
124 return err;
127 int setSlotColor(PyrSlot *slot, SCColor *sccolor)
129 if (!(isKindOfSlot(slot, s_color->u.classobj))) return errWrongType;
131 PyrSlot *slots = slotRawObject(slot)->slots;
133 SetFloat(slots+0, sccolor->red);
134 SetFloat(slots+1, sccolor->green);
135 SetFloat(slots+2, sccolor->blue);
136 SetFloat(slots+3, sccolor->alpha);
137 return errNone;
140 int slotGetSCRect(PyrSlot* a, SCRect *r)
142 if (!isKindOfSlot(a, s_rect->u.classobj)) return errWrongType; // arg check - br
143 PyrSlot *slots = slotRawObject(a)->slots;
144 int err;
145 err = slotFloatVal(slots+0, &r->x);
146 if (err) return err;
147 err = slotFloatVal(slots+1, &r->y);
148 if (err) return err;
149 err = slotFloatVal(slots+2, &r->width);
150 if (err) return err;
151 err = slotFloatVal(slots+3, &r->height);
152 if (err) return err;
154 return errNone;
158 int getBackgroundVal(PyrSlot *slot, DrawBackground *inPtr);
159 int getBackgroundVal(PyrSlot *slot, DrawBackground *inPtr)
161 SetNil(slot);
162 //inPtr->GetSlot(slot);
163 return errNone;
166 int slotBackgroundVal(PyrSlot *slot, DrawBackground **ioPtr);
167 int slotBackgroundVal(PyrSlot *slot, DrawBackground **ioPtr)
169 int err, direction, steps;
170 SCColor color1, color2;
171 PyrClass *classobj = classOfSlot(slot);
172 char *classname = slotRawSymbol(&classobj->name)->name;
174 if (strcmp(classname, "Color")==0) {
175 err = slotColorVal(slot, &color1);
176 if (err) return err;
178 delete *ioPtr;
179 *ioPtr = new SolidColorBackground(color1);
180 } else if (strcmp(classname, "Gradient") == 0) {
181 PyrObject *obj = slotRawObject(slot);
182 PyrSlot *slots = obj->slots;
184 err = slotColorVal(slots+0, &color1);
185 if (err) return err;
186 err = slotColorVal(slots+1, &color2);
187 if (err) return err;
189 if (IsSym(slots+2)) {
190 if (strncmp(slotRawSymbol(&slots[2])->name, "h", 1)==0) direction = grad_Horizontal;
191 else if (strncmp(slotRawSymbol(&slots[2])->name, "v", 1)==0) direction = grad_Vertical;
192 else if (strncmp(slotRawSymbol(&slots[2])->name, "n", 1)==0) direction = grad_Narrow;
193 else if (strncmp(slotRawSymbol(&slots[2])->name, "w", 1)==0) direction = grad_Wide;
194 else direction = grad_Vertical;
195 } else {
196 direction = grad_Horizontal;
199 err = slotIntVal(slots+3, &steps);
200 if (err) return err;
202 delete *ioPtr;
203 *ioPtr = new GradientBackground(color1, color2, direction, steps);
205 } else if (strcmp(classname, "HiliteGradient") == 0) {
206 PyrObject *obj = slotRawObject(slot);
207 PyrSlot *slots = obj->slots;
209 err = slotColorVal(slots+0, &color1);
210 if (err) return err;
211 err = slotColorVal(slots+1, &color2);
212 if (err) return err;
214 if (IsSym(slots+2)) {
215 if (strncmp(slotRawSymbol(&slots[2])->name, "h", 1)==0) direction = grad_Horizontal;
216 else if (strncmp(slotRawSymbol(&slots[2])->name, "v", 1)==0) direction = grad_Vertical;
217 else if (strncmp(slotRawSymbol(&slots[2])->name, "n", 1)==0) direction = grad_Narrow;
218 else if (strncmp(slotRawSymbol(&slots[2])->name, "w", 1)==0) direction = grad_Wide;
219 else direction = grad_Vertical;
220 } else {
221 direction = grad_Horizontal;
224 err = slotIntVal(slots+3, &steps);
225 if (err) return err;
227 float frac;
228 err = slotFloatVal(slots+4, &frac);
229 if (err) return err;
231 delete *ioPtr;
232 *ioPtr = new HiliteGradientBackground(color1, color2, direction, steps, frac);
235 return errNone;
238 int slotBackgroundImageVal(PyrSlot *slot, DrawBackground **ioPtr);
239 int slotBackgroundImageVal(PyrSlot *slot, DrawBackground **ioPtr)
241 if (!isKindOfSlot(slot, class_array)) return errWrongType;
243 PyrSlot *slots = slotRawObject(slot)->slots;
244 PyrClass *classobj = classOfSlot(slots + 0);
245 char *classname = slotRawSymbol(&classobj->name)->name;
246 if( strcmp(classname, "SCImage") == 0 )
248 int err;
249 SCImage *scImage;
250 PyrObject *obj = slotRawObject(slots + 0);
251 scImage = (SCImage *)slotRawPtr(obj->slots + 0); // Instance of Cocoa SCImage
253 int tileMode;
254 err = slotIntVal(slots+1, &tileMode);
255 if (err) return err;
257 float frac;
258 err = slotFloatVal(slots+2, &frac);
259 if (err) return err;
261 NSRect fromRect;
262 if (NotNil(slots+3)) {
264 SCRect screct;
265 err = slotGetSCRect(slots+3, &screct);
266 if (err) return err;
268 fromRect = NSMakeRect(screct.x, screct.y, screct.width, screct.height);
270 } else {
272 fromRect = NSMakeRect(0., 0., [scImage width], [scImage height]);
276 delete *ioPtr;
277 *ioPtr = new SCImageBackground(scImage, fromRect, tileMode, frac);
279 return errNone;
282 // for any sc class that supports mouseDown and mouseUp methods
283 #import "TabletEvents.h"
285 #define TABLETTRACK(METHOD,X,Y) \
286 if (mObj) { \
287 pthread_mutex_lock (&gLangMutex); \
288 VMGlobals *g = gMainVMGlobals; \
289 g->canCallOS = true; \
290 ++g->sp; SetObject(g->sp, mObj); \
291 SetFloat(++g->sp, X); \
292 SetFloat(++g->sp, Y); \
293 SetFloat(++g->sp, (float)[theEvent pressure]); \
294 NSPoint tilt; \
295 tilt = (NSPoint)[theEvent tilt]; \
296 SetFloat(++g->sp, tilt.x); \
297 SetFloat(++g->sp, tilt.y); \
298 SetInt(++g->sp,[theEvent deviceID]); \
299 SetInt(++g->sp,[theEvent buttonNumber]); \
300 SetInt(++g->sp,[theEvent clickCount]); \
301 SetInt(++g->sp,[theEvent absoluteZ]); \
302 SetFloat(++g->sp,[theEvent rotationInDegrees]); \
303 runInterpreter(g, METHOD, 11); \
304 g->canCallOS = false; \
305 pthread_mutex_unlock (&gLangMutex); \
312 Layout::Layout()
313 : mMinWidth(0.), mMaxWidth(10000.), mMinHeight(0.), mMaxHeight(10000.), mWeight(1.),
314 mShouldResize(true), mHResize(layout_FixedLeft), mVResize(layout_FixedTop) {
317 SCView::SCView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
318 : mNext(0), mNextAnimatedView(0), mPrevAnimatedView(0),
319 mParent(0), mTop(0), mObj(inObj), mBounds(inBounds),
320 mBackground(0), mBackgroundImage(0), mVisible(true), mEnabled(true),
321 mCanFocus(true), mDragHilite(false),
322 mConstructionMode(-1), mDragLabel(0)
324 mFocusColor = SCMakeColor(0.0,0.0,0.0, 0.5);
325 mBounds = inBounds;
326 if (inParent){
327 inParent->add(this);
328 if(!(inParent->isSubViewScroller())){
329 SCRect pbounds = inParent->getLayout().bounds;
330 mLayout.bounds.x = mBounds.x + pbounds.x;
331 mLayout.bounds.y = mBounds.y + pbounds.y;
332 mLayout.bounds.width = mBounds.width;
333 mLayout.bounds.height = mBounds.height;
334 } else {
335 mLayout.bounds = mBounds;
339 // store myself into sc object.
340 if (mObj) SetPtr(mObj->slots+0, this);
343 SCView::~SCView()
345 stopAnimation();
346 makeFocus(false);
347 mTop->forgetView(this);
348 if (mParent) mParent->remove(this);
349 if (mObj) SetNil(mObj->slots+0);
351 delete mBackground;
352 delete mBackgroundImage;
354 mTop = 0;
355 mParent = 0;
358 void SCView::startAnimation()
360 mNextAnimatedView = gAnimatedViews;
361 if (mNextAnimatedView) mNextAnimatedView->mPrevAnimatedView = this;
362 mPrevAnimatedView = 0;
363 gAnimatedViews = this;
366 void SCView::stopAnimation()
368 SCView *nextAnim = mNextAnimatedView;
369 SCView *prevAnim = mPrevAnimatedView;
370 if (nextAnim) nextAnim->mPrevAnimatedView = prevAnim;
371 if (prevAnim) prevAnim->mNextAnimatedView = nextAnim;
372 else if (gAnimatedViews == this) gAnimatedViews = nextAnim;
373 mPrevAnimatedView = mNextAnimatedView = 0;
377 bool SCView::hit(SCPoint where) const
379 SCRect bounds = mLayout.bounds;
380 return SCPointInRect(where, bounds);
383 void SCView::keyDown(int character, int modifiers, unsigned short keycode)
385 pthread_mutex_lock (&gLangMutex);
386 PyrSymbol *method = getsym("keyDown");
387 if (mObj) {
388 VMGlobals *g = gMainVMGlobals;
389 g->canCallOS = true;
390 ++g->sp; SetObject(g->sp, mObj);
391 ++g->sp; SetChar(g->sp, character);
392 ++g->sp; SetInt(g->sp, modifiers);
393 ++g->sp; SetInt(g->sp, character);
394 ++g->sp; SetInt(g->sp, keycode);
395 runInterpreter(g, method, 5);
396 g->canCallOS = false;
398 pthread_mutex_unlock (&gLangMutex);
401 void SCView::keyUp(int character, int modifiers, unsigned short keycode)
403 pthread_mutex_lock (&gLangMutex);
404 PyrSymbol *method = getsym("keyUp");
405 if (mObj) {
406 VMGlobals *g = gMainVMGlobals;
407 g->canCallOS = true;
408 ++g->sp; SetObject(g->sp, mObj);
409 ++g->sp; SetChar(g->sp, character);
410 ++g->sp; SetInt(g->sp, modifiers);
411 ++g->sp; SetInt(g->sp, character);
412 ++g->sp; SetInt(g->sp, keycode);
413 runInterpreter(g, method, 5);
414 g->canCallOS = false;
416 pthread_mutex_unlock (&gLangMutex);
419 void SCView::keyModifiersChanged(int modifiers)
421 pthread_mutex_lock (&gLangMutex);
422 PyrSymbol *method = getsym("keyModifiersChanged");
423 if (mObj) {
424 VMGlobals *g = gMainVMGlobals;
425 g->canCallOS = true;
426 ++g->sp; SetObject(g->sp, mObj);
427 ++g->sp; SetInt(g->sp, modifiers);
428 runInterpreter(g, method, 2);
429 g->canCallOS = false;
431 pthread_mutex_unlock (&gLangMutex);
435 void SCView::mouseDownAction(SCPoint where, int modifiers, NSEvent *theEvent)
437 pthread_mutex_lock (&gLangMutex);
438 PyrSymbol *method = getsym("mouseDown");
439 int clickCount = [theEvent clickCount];
440 int buttonNum = [theEvent buttonNumber];
441 if (mObj) {
442 VMGlobals *g = gMainVMGlobals;
443 g->canCallOS = true;
444 SCRect tbounds = getDrawBounds();
445 where.x = where.x - tbounds.x;
446 where.y = where.y - tbounds.y;
447 ++g->sp; SetObject(g->sp, mObj);
448 ++g->sp; SetFloat(g->sp, where.x);
449 ++g->sp; SetFloat(g->sp, where.y);
450 ++g->sp; SetInt(g->sp, modifiers);
451 ++g->sp; SetInt(g->sp,buttonNum);
452 ++g->sp; SetInt(g->sp,clickCount);
453 runInterpreter(g, method, 6);
454 g->canCallOS = false;
456 pthread_mutex_unlock (&gLangMutex);
458 void SCView::mouseMoveAction(SCPoint where, int modifiers, NSEvent *theEvent)
460 pthread_mutex_lock (&gLangMutex);
461 PyrSymbol *method = getsym("mouseMove");
462 if (mObj) {
463 VMGlobals *g = gMainVMGlobals;
464 g->canCallOS = true;
465 SCRect tbounds = getDrawBounds();
466 where.x = where.x - tbounds.x;
467 where.y = where.y - tbounds.y;
468 ++g->sp; SetObject(g->sp, mObj);
469 ++g->sp; SetFloat(g->sp, where.x);
470 ++g->sp; SetFloat(g->sp, where.y);
471 ++g->sp; SetInt(g->sp, modifiers);
472 runInterpreter(g, method, 4);
473 g->canCallOS = false;
475 pthread_mutex_unlock (&gLangMutex);
477 void SCView::mouseUpAction(SCPoint where, int modifiers, NSEvent *theEvent)
479 pthread_mutex_lock (&gLangMutex);
480 PyrSymbol *method = getsym("mouseUp");
481 if (mObj) {
482 VMGlobals *g = gMainVMGlobals;
483 g->canCallOS = true;
484 SCRect tbounds = getDrawBounds();
485 where.x = where.x - tbounds.x;
486 where.y = where.y - tbounds.y;
487 ++g->sp; SetObject(g->sp, mObj);
488 ++g->sp; SetFloat(g->sp, where.x);
489 ++g->sp; SetFloat(g->sp, where.y);
490 ++g->sp; SetInt(g->sp, modifiers);
491 runInterpreter(g, method, 4);
492 g->canCallOS = false;
494 pthread_mutex_unlock (&gLangMutex);
497 void SCView::setConstructionModeFromPoint(SCPoint where)
499 SCRect bounds;
500 bounds = SCMakeRect(mBounds.x, mBounds.y, mBounds.width*0.6, mBounds.height*0.6);
501 // post("point: x: %f, y: %f, bounds: x: %f, y: %f\n", where.x, where.y, mBounds.x, mBounds.y);
502 if( SCPointInRect(where, bounds)){
503 mConstructionMode = view_PositionConstructionMode;
504 // [[NSCursor openHandCursor] set];
506 }else{
507 // [[NSCursor crosshairCursor] set];
508 mConstructionMode = view_ResizeConstructionMode;
512 void SCView::doConstructionMove(SCPoint where)
515 if( mConstructionMode == view_ResizeConstructionMode){
516 mBounds.width = mBounds.width + (where.x - (mBounds.width + mBounds.x));
517 mBounds.height = mBounds.height + (where.y - (mBounds.height + mBounds.y));
518 }else if (mConstructionMode == view_PositionConstructionMode) {
519 mBounds.x = where.x;
520 mBounds.y = where.y;
522 refresh();
523 mTop->refresh();
526 NSMenu* SCView::contextMenu(SCPoint inPoint)
528 return 0;
531 void SCView::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
533 mouseTrack(where, modifiers,theEvent);
536 void SCView::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
540 void SCView::mouseEndTrack(SCPoint where, int modifiers, NSEvent *theEvent)
542 mouseTrack(where, modifiers,theEvent);
545 void SCView::mouseOver(SCPoint where, int modifiers, NSEvent *theEvent )
547 pthread_mutex_lock (&gLangMutex);
548 PyrSymbol *method = getsym("mouseOver");
549 if (mObj) {
550 VMGlobals *g = gMainVMGlobals;
551 g->canCallOS = true;
552 SCRect tbounds = getDrawBounds();
553 where.x = where.x - tbounds.x;
554 where.y = where.y - tbounds.y;
555 ++g->sp; SetObject(g->sp, mObj);
556 ++g->sp; SetInt(g->sp, (int) where.x);
557 ++g->sp; SetInt(g->sp, (int) where.y);
558 ++g->sp; SetInt(g->sp, modifiers);
559 runInterpreter(g, method, 4);
560 g->canCallOS = false;
562 pthread_mutex_unlock (&gLangMutex);
565 bool SCView::canReceiveDrag()
567 return false;
570 void SCView::receiveDrag()
574 void SCView::draggingEntered (SCPoint where)
576 mouseOver(where, 0, NULL);
578 void SCView::draggingUpdated (SCPoint where)
580 mouseOver(where, 0, NULL);
584 void SCView::setDragHilite(bool inFlag)
586 bool prevFlag = mDragHilite;
587 mDragHilite = inFlag;
588 if (mDragHilite != prevFlag) refresh();
591 void hPaintGradient(CGContextRef cgc, CGRect bounds, SCColor startColor, SCColor endColor, int numSteps);
593 void SCView::draw(SCRect inDamage)
595 CGContextRef cgc;
596 CGRect rect;
597 if ( mBackground || mBackgroundImage ) {
598 SCRect bounds;
599 bounds = getDrawBounds();
600 // NSLog(@"back bounds: %f, %f, %f, %f", bounds.x, bounds.y, bounds.width, bounds.height);
601 cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
602 rect = SCtoCGRect(bounds);
605 if (mBackground)
606 mBackground->draw(cgc, rect);
608 if (mBackgroundImage)
609 mBackgroundImage->draw(cgc, rect);
612 void SCView::drawDisabled(SCRect inDamage)
614 if (!mEnabled && shouldDim()) {
615 SCRect bounds = getDrawBounds();
616 CGRect rect = SCtoCGRect(bounds);
617 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
618 CGContextSaveGState(cgc);
619 CGContextSetRGBFillColor(cgc, 1., 1., 1., 0.5);
620 CGContextFillRect(cgc, rect);
621 CGContextRestoreGState(cgc);
625 void SCView::drawFocus(SCRect inDamage)
627 if (isFocus()) {
628 SCRect bounds = getDrawBounds();
629 CGRect rect = SCtoCGRect(bounds);
630 rect.origin.x -= 2;
631 rect.origin.y -= 2;
632 rect.size.width += 4;
633 rect.size.height += 4;
634 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
635 CGContextSaveGState(cgc);
636 CGContextSetLineWidth(cgc, 2);
637 // CGContextSetRGBStrokeColor(cgc, 0., 0., 0., 0.5);
638 CGContextSetRGBStrokeColor(cgc, mFocusColor.red, mFocusColor.green, mFocusColor.blue, mFocusColor.alpha);
640 CGContextStrokeRect(cgc, rect);
641 CGContextRestoreGState(cgc);
646 void SCView::drawDragHilite(SCRect inDamage)
648 if (mDragHilite) {
649 SCRect bounds = getDrawBounds();
651 CGRect rect = SCtoCGRect(bounds);
652 rect.origin.x += 2;
653 rect.origin.y += 2;
654 rect.size.width -= 4;
655 rect.size.height -= 4;
656 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
657 CGContextSaveGState(cgc);
658 CGContextSetLineWidth(cgc, 4);
659 CGContextSetRGBStrokeColor(cgc, 0., 0., 1., 0.4);
660 CGContextStrokeRect(cgc, rect);
661 CGContextRestoreGState(cgc);
665 void SCView::drawIfNecessary(SCRect inDamage)
667 SCRect bounds = getDrawBounds();
668 if(isFocus()) {
669 bounds.x -= 4; bounds.y -= 4;
670 bounds.width += 8; bounds.height += 8;
672 if (SCRectsDoIntersect(inDamage, bounds) && mVisible) {
673 draw(inDamage);
674 drawDisabled(inDamage);
675 drawDragHilite(inDamage);
676 drawFocus(inDamage);
680 SCView* SCView::findView(SCPoint where)
682 if (hit(where) && mEnabled && mVisible) return this;
683 else return 0;
686 SCView* SCView::findViewByID(int32 inID)
688 if (inID == mID) return this;
689 else return 0;
692 bool SCView::shouldDim()
694 return true;
697 bool SCView::canFocus()
699 bool flag = mEnabled && mVisible && mCanFocus;
700 if (mParent) flag = flag && mParent->canFocus();
701 return flag;
704 bool SCContainerView::canFocus()
706 bool flag = mEnabled && mVisible;
707 if (mParent) flag = flag && mParent->canFocus();
708 return flag;
711 SCRect NStoSCRect(NSRect nsrect)
713 SCRect screct;
714 screct.x = nsrect.origin.x;
715 screct.y = nsrect.origin.y;
716 screct.width = nsrect.size.width;
717 screct.height = nsrect.size.height;
718 return screct;
720 NSRect SCtoNSRect(SCRect screct);
722 void SCView::setBounds(SCRect inBounds)
724 mBounds = inBounds;
725 if(!(mParent->isSubViewScroller())){
726 SCRect pbounds = mParent->getLayout().bounds;
727 mLayout.bounds.x = mBounds.x + pbounds.x;
728 mLayout.bounds.y = mBounds.y + pbounds.y;
729 mLayout.bounds.width = mBounds.width;
730 mLayout.bounds.height = mBounds.height;
731 } else {
732 mLayout.bounds = mBounds;
737 SCRect SCView::getBounds()
739 return mBounds;
743 SCRect SCView::getDrawBounds() //relative to ContainerView
745 return mLayout.bounds;
748 Layout SCView::getLayout()
750 return mLayout;
753 void SCView::makeFocus(bool focus)
755 if (focus) {
756 if (canFocus() && !isFocus()) {
757 SCView *prevFocus = mTop->focusView();
758 if (prevFocus) prevFocus->makeFocus(false);
759 mTop->focusIs(this);
760 refreshFocus();
761 NSView* newFirstResponder = focusResponder();
762 [[newFirstResponder window] makeFirstResponder:newFirstResponder];
764 } else {
765 if (isFocus()) {
766 mTop->focusIs(0);
767 refreshFocus();
772 NSView* SCView::focusResponder() { return mTop->GetNSView(); }
774 void SCContainerView::makeFocus(bool focus)
778 SCView* SCView::nextFocus(bool *foundFocus, bool canFocus)
780 if (isFocus()) {
781 *foundFocus = true;
782 return 0;
784 canFocus = canFocus && mEnabled && mVisible && mCanFocus;
785 if (canFocus && *foundFocus) return this;
786 return 0;
789 SCView* SCView::prevFocus(SCView **prevView, bool canFocus)
791 if (isFocus() && *prevView) return *prevView;
792 canFocus = canFocus && mEnabled && mVisible && mCanFocus;
793 if (canFocus) *prevView = this;
794 return 0;
798 void SCView::refresh()
800 mTop->addDamage(mLayout.bounds);
803 void SCView::refreshInRect(SCRect b)
805 if(SCRectsDoIntersect(b, mLayout.bounds)) {
806 SCRect sect;
808 sect.x = sc_max(b.x, mLayout.bounds.x);
809 sect.y = sc_max(b.y, mLayout.bounds.y);
810 sect.width = sc_min(b.x + b.width, mLayout.bounds.x + mLayout.bounds.width);
811 sect.height = sc_min(b.y + b.height, mLayout.bounds.y + mLayout.bounds.height);
812 sect.width -= sect.x; sect.height -= sect.y;
813 mTop->addDamage(sect);
817 // cannot call from primitives. i.e. new view, or get/set property
818 void SCView::sendMessage(PyrSymbol *method, int numargs, PyrSlot *args, PyrSlot *result)
820 //CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
821 //CGContextSaveGState(cgc);
822 pthread_mutex_lock (&gLangMutex);
823 if (mObj) {
824 VMGlobals *g = gMainVMGlobals;
825 g->canCallOS = true;
826 ++g->sp; SetObject(g->sp, mObj);
827 for (int i=0; i<numargs; ++i) {
828 ++g->sp;
829 slotCopy(g->sp, &args[i]);
831 runInterpreter(g, method, numargs+1);
832 g->canCallOS = false;
833 if (result) slotCopy(result, &g->result);
835 pthread_mutex_unlock (&gLangMutex);
837 //CGContextRestoreGState(cgc);
840 bool SCView::isDragSource() const
842 return false;
845 int SCView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
847 int err;
848 char *name = symbol->name;
849 if (strcmp(name, "bounds")==0) {
850 SCRect screct;
851 err = slotGetSCRect(slot, &screct);
852 if (err) return err;
853 refreshFocus();
854 //mBounds = screct;
856 if(mTop->isScroller()) {
857 ((SCScrollTopView*)mTop)->setInSetClipViewOrigin(true);
858 setBounds(screct);
859 [(SCGraphView*)mTop->GetNSView() setFrameSizeToMinimum];
860 ((SCScrollTopView*)mTop)->setInSetClipViewOrigin(false);
861 } else {setBounds(screct);}
862 refreshFocus();
863 return errNone;
865 if (strcmp(name, "visible")==0) {
866 bool visible = IsTrue(slot);
867 if (mVisible != visible) {
868 mVisible = visible;
869 if (!mVisible) mTop->resetFocus(); //
870 refresh();
872 return errNone;
874 if (strcmp(name, "enabled")==0) {
875 bool enabled = IsTrue(slot);
876 if (mEnabled != enabled) {
877 mEnabled = enabled;
878 if (!mEnabled) mTop->resetFocus();
879 refresh();
881 return errNone;
883 if (strcmp(name, "canFocus")==0) {
884 bool canFocus = IsTrue(slot);
885 if (mCanFocus != canFocus) {
886 mCanFocus = canFocus;
887 if (!mCanFocus) mTop->resetFocus();
888 refresh();
890 return errNone;
892 if (strcmp(name, "resize")==0) {
893 // 1 2 3
894 // 4 5 6
895 // 7 8 9
896 int32 resize;
897 err = slotIntVal(slot, &resize);
898 if (err) return err;
899 if (resize < 1 || resize > 9) return errIndexOutOfRange;
900 mLayout.mHResize = ((resize - 1) % 3) - 1;
901 mLayout.mVResize = ((resize - 1) / 3) - 1;
902 mTop->refresh();
903 return errNone;
905 if(strcmp(name,"id") ==0) {
906 return slotIntVal(slot, &mID);
908 if(strcmp(name,"minWidth") ==0) {
909 err = slotFloatVal(slot, &mLayout.mMinWidth);
910 mTop->refresh();
911 return err;
913 if(strcmp(name,"maxWidth") ==0) {
914 err = slotFloatVal(slot, &mLayout.mMaxWidth);
915 mTop->refresh();
916 return err;
918 if(strcmp(name,"minHeight") ==0) {
919 err = slotFloatVal(slot, &mLayout.mMinHeight);
920 mTop->refresh();
921 return err;
923 if(strcmp(name,"maxHeight") ==0) {
924 err = slotFloatVal(slot, &mLayout.mMaxHeight);
925 mTop->refresh();
926 return err;
928 if (strcmp(name, "background")==0) {
929 err = slotBackgroundVal(slot, &mBackground);
930 if (err) return err;
931 refresh();
932 return errNone;
934 if (strcmp(name, "backgroundImage")==0) {
935 err = slotBackgroundImageVal(slot, &mBackgroundImage);
936 if (err) return err;
937 refresh();
938 return errNone;
940 if (strcmp(name, "focusColor")==0) {
941 err = slotColorVal(slot, &mFocusColor);
942 if (err) return err;
943 refresh();
944 return errNone;
946 if (strcmp(name, "dragLabel")==0) {
947 if(isKindOfSlot(slot, class_string)) {
948 PyrString* pstring = slotRawString(slot);
949 if(!pstring) return errNone;
950 if(mDragLabel) [mDragLabel release];
951 mDragLabel = [[NSString alloc] initWithCString: pstring->s length: pstring->size];
952 return errNone;
953 } else if (IsNil(slot)) {
954 if(mDragLabel) [mDragLabel release];
955 mDragLabel = 0;
956 return errNone;
957 } else return errWrongType;
959 return errPropertyNotFound;
962 int SCView::getProperty(PyrSymbol *symbol, PyrSlot *slot)
964 char *name = symbol->name;
965 if (strcmp(name, "bounds")==0) {
966 if (!(isKindOfSlot(slot, s_rect->u.classobj))) {
967 return errWrongType;
969 PyrSlot *slots = slotRawObject(slot)->slots;
970 SetFloat(slots+0, mBounds.x);
971 SetFloat(slots+1, mBounds.y);
972 SetFloat(slots+2, mBounds.width);
973 SetFloat(slots+3, mBounds.height);
974 return errNone;
976 if (strcmp(name, "absoluteBounds")==0) {
977 SCRect drawBounds;
978 if (!(isKindOfSlot(slot, s_rect->u.classobj))) {
979 return errWrongType;
981 drawBounds = mLayout.bounds;
982 PyrSlot *slots = slotRawObject(slot)->slots;
983 SetFloat(slots+0, drawBounds.x);
984 SetFloat(slots+1, drawBounds.y);
985 SetFloat(slots+2, drawBounds.width);
986 SetFloat(slots+3, drawBounds.height);
987 return errNone;
989 if (strcmp(name, "visible")==0) {
990 SetBool(slot, mVisible);
991 return errNone;
993 if (strcmp(name, "enabled")==0) {
994 SetBool(slot, mEnabled);
995 return errNone;
997 if (strcmp(name, "resize")==0) {
998 int resize = mLayout.mVResize * 3 + mLayout.mHResize + 5;
999 SetInt(slot, resize);
1000 return errNone;
1002 if (strcmp(name, "id")==0) {
1003 SetInt(slot, mID);
1004 return errNone;
1006 /*if (strcmp(name, "background")==0) {
1007 int err = getBackgroundVal(slot, mBackground);
1008 return err;
1010 /*if (strcmp(name, "backColor")==0) {
1011 return setSlotColor(slot, &mBackColor);
1014 if (strcmp(name, "focusColor")==0) {
1015 return setSlotColor(slot, &mFocusColor);;
1017 return errPropertyNotFound;
1020 void SCView::beginDrag(SCPoint where)
1022 sendMessage(s_beginDrag, 0, 0, 0);
1024 PyrSlot slot;
1025 PyrSlot stringSlot;
1026 NSString *string = 0;
1027 NSString *label = 0;
1028 pthread_mutex_lock (&gLangMutex);
1029 if (mObj) {
1030 VMGlobals *g = gMainVMGlobals;
1031 int classVarIndex = slotRawInt(&getsym("SCView")->u.classobj->classVarIndex);
1032 slotCopy(&slot, &g->classvars->slots[classVarIndex]);
1033 slotCopy(&stringSlot, &g->classvars->slots[classVarIndex+1]);
1034 if (isKindOfSlot(&stringSlot, class_string)) {
1035 string = [NSString stringWithCString: slotRawString(&stringSlot)->s length: slotRawString(&stringSlot)->size];
1037 if(mDragLabel) label = mDragLabel;
1039 pthread_mutex_unlock (&gLangMutex);
1041 mTop->beginDragCallback(where, &slot, string, label);
1044 ////////////////////////////////////////////////////////////////////////////////////////////////
1046 SCContainerView::SCContainerView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1047 : SCView(inParent, inObj, inBounds), mChildren(0), mNumChildren(0)
1049 mLayout.bounds = mBounds;
1050 if(mParent ){
1051 SCRect pBounds = mParent->getDrawBounds(); // or jsut absolute frame bounds ?
1052 mLayout.bounds.x = inBounds.x + pBounds.x;
1053 mLayout.bounds.y = inBounds.y + pBounds.y;
1057 SCContainerView::~SCContainerView()
1059 SCView *child = mChildren;
1060 while (child) {
1061 SCView *next = child->mNext;
1062 child->mParent = 0;
1063 delete child;
1064 child = next;
1069 int SCContainerView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
1071 int err;
1072 char *name = symbol->name;
1074 if (strcmp(name, "visible")==0) {
1075 bool visible = IsTrue(slot);
1076 if (mVisible != visible) {
1077 mVisible = visible;
1078 // SCView *child = mChildren;
1079 // while (child) {
1080 // SCView *next = child->mNext;
1081 // child->setVisibleFromParent(visible && mParent->isVisible()); // needed for Cocoa views
1082 // child = next;
1083 // }
1084 setVisibleFromParent();
1085 if (!mVisible) mTop->resetFocus(); //
1086 refresh();
1088 return errNone;
1091 return SCView::setProperty(symbol, slot);
1094 void SCContainerView::setVisibleFromParent()
1096 SCView *child = mChildren;
1097 while (child) {
1098 SCView *next = child->mNext;
1099 child->setVisibleFromParent(); // needed for Cocoa views
1100 child = next;
1104 void SCContainerView::add(SCView *inChild)
1106 inChild->mNext = mChildren;
1107 mChildren = inChild;
1108 mNumChildren++;
1109 inChild->mParent = this;
1110 inChild->mTop = mTop;
1111 inChild->refresh();
1114 void SCContainerView::remove(SCView *inChild)
1116 SCView *child = mChildren;
1117 SCView *prev = 0;
1118 inChild->makeFocus(false);
1119 while (child) {
1120 SCView *next = child->mNext;
1121 if (child == inChild) {
1122 if (prev) prev->mNext = child->mNext;
1123 else mChildren = child->mNext;
1124 child->mParent = 0;
1125 mNumChildren--;
1126 return;
1128 prev = child;
1129 child = next;
1134 void SCContainerView::drawIfNecessary(SCRect inDamage)
1136 SCRect drawBounds;
1137 drawBounds = getDrawBounds();
1138 if (SCRectsDoIntersect(inDamage, drawBounds) && mVisible) {
1139 draw(inDamage);
1140 SCView *child = mChildren;
1141 SCView *children[mNumChildren];
1142 int k = mNumChildren;
1143 while (child) {
1144 // child->drawIfNecessary(inDamage);
1145 children[--k] = child;
1146 child = child->next();
1148 for(int i=0; i < mNumChildren; i++ ) {
1149 child = children[i];
1150 child->drawIfNecessary(inDamage);
1152 drawDisabled(inDamage);
1153 drawDragHilite(inDamage);
1154 drawFocus(inDamage);
1158 SCView* SCContainerView::findView(SCPoint where)
1160 if (mEnabled && mVisible) {
1161 SCView *child = mChildren;
1162 while (child) {
1163 if(!(child->isScroller())) {
1164 SCView *found = child->findView(where);
1165 if (found) return found;
1167 child = child->mNext;
1170 return 0;
1173 SCView* SCContainerView::findViewByID(int32 inID)
1175 if (inID == mID) return this;
1176 SCView *child = mChildren;
1177 while (child) {
1178 SCView *found = child->findViewByID(inID);
1179 if (found) return found;
1180 child = child->mNext;
1182 return 0;
1185 SCView* SCContainerView::nextFocus(bool *foundFocus, bool canFocus)
1187 canFocus = canFocus && mEnabled && mVisible;
1188 SCView *child = mChildren;
1189 while (child) {
1190 SCView *view = child->nextFocus(foundFocus, canFocus);
1191 if (view) return view;
1192 child = child->mNext;
1194 return 0;
1197 SCView* SCContainerView::prevFocus(SCView **prevView, bool canFocus)
1199 canFocus = canFocus && mEnabled && mVisible;
1200 SCView *child = mChildren;
1201 while (child) {
1202 SCView *view = child->prevFocus(prevView, canFocus);
1203 if (view) return view;
1204 child = child->mNext;
1206 return 0;
1209 SCRect SCContainerView::checkMinimumSize() {
1210 SCView *child = mChildren;
1211 SCRect candidate = mBounds;
1212 // iterate through all the views and see if we need to be bigger (children may exceed the parent's bounds)
1213 while (child) {
1214 SCRect bounds = child->checkMinimumSize();
1215 candidate = SCRectUnion(bounds, candidate);
1216 child = child->next();
1218 return candidate;
1222 SCView* NewSCCompositeView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1224 return new SCCompositeView(inParent, inObj, inBounds);
1227 SCCompositeView::SCCompositeView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1228 : SCContainerView(inParent, inObj, inBounds)
1232 SCCompositeView::~SCCompositeView()
1236 void SCCompositeView::setBounds(SCRect inBounds)
1238 SCView *child = mChildren;
1239 SCView *myTop = mTop;
1240 SCRect topBounds = myTop->getBounds();
1241 SCRect topPBounds = myTop->getLayout().bounds;
1243 // float right = mBounds.x + mBounds.width;
1244 // float bottom = mBounds.y + mBounds.height;
1245 mLayout.bounds = inBounds;
1246 // if(isTopContainer()){
1247 // post("i'm my own parent ... \t");
1248 // post("in x:%f, y:%f\n", inBounds.x, inBounds.y);
1249 // }
1251 if(mParent){
1252 if(!(mParent->isSubViewScroller())){
1253 SCRect pBounds = mParent->getDrawBounds();
1254 mLayout.bounds.x = inBounds.x + pBounds.x;
1255 mLayout.bounds.y = inBounds.y + pBounds.y;
1256 } else {
1257 mLayout.bounds.x = inBounds.x;
1258 mLayout.bounds.y = inBounds.y;
1262 while (child) {
1263 SCRect bounds = child->getBounds();
1264 Layout layout = child->getLayout();
1265 // SCRect bounds = layout.bounds;
1267 float offset;
1268 switch (layout.mHResize) {
1269 case layout_FixedLeft :
1270 break;
1272 case layout_FixedRight :
1273 // if the parent is a top container, then relative or absolute are irrelevant.
1274 if(child->parent()->isTopContainer() || (inBounds.width != child->parent()->getBounds().width)){
1275 offset = (mBounds.x + mBounds.width) - (bounds.x + bounds.width);
1276 bounds.x = (inBounds.x + inBounds.width) - (bounds.width + offset);
1279 break;
1281 case layout_HElastic :
1282 offset = (mBounds.x + mBounds.width) - (bounds.x + bounds.width);
1283 /* bounds.width = sc_clip(
1284 (inBounds.width) - (bounds.x + offset),
1285 layout.mMinWidth ,
1286 sc_min(layout.mMaxWidth,right - bounds.x)
1287 );*/
1288 bounds.width = (inBounds.width) - ((bounds.x - mBounds.x) + offset);
1289 // }
1291 switch (layout.mVResize) {
1292 case layout_FixedTop :
1293 break;
1295 case layout_FixedBottom :
1297 // if the parent is a top container, then relative or absolute are irrelevant.
1298 if(child->parent()->isTopContainer() || (inBounds.height != child->parent()->getBounds().height)){
1299 offset = (mBounds.y + mBounds.height) - (bounds.y + bounds.height);
1300 bounds.y = (inBounds.y + inBounds.height) - (bounds.height + offset);
1303 break;
1305 case layout_VElastic :
1307 offset = (mBounds.y + mBounds.height) - (bounds.y + bounds.height);
1308 /*bounds.height = sc_clip(
1309 (inBounds.height) - (bounds.y + offset),
1310 layout.mMinHeight ,
1311 sc_min(layout.mMaxHeight,bottom - bounds.y)
1312 );*/
1313 bounds.height = (inBounds.height) - ((bounds.y - mBounds.y) + offset);
1314 // }
1317 child->setBounds(bounds);
1318 child = child->next();
1320 // should be limited by the limitations of the contents
1321 mBounds = inBounds;
1324 /////////////////////////////////////////////////////////////////////////////////////
1327 SCView* NewSCLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1329 return new SCLayoutView(inParent, inObj, inBounds);
1332 SCLayoutView::SCLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1333 : SCContainerView(inParent, inObj, inBounds), mSpacing(4.)
1337 SCLayoutView::~SCLayoutView()
1342 int SCLayoutView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
1344 int err;
1345 char *name = symbol->name;
1346 if (strcmp(name, "spacing")==0) {
1347 err = slotFloatVal(slot, &mSpacing);
1348 if (err) return err;
1349 refresh();
1350 return errNone;
1352 if (strcmp(name, "bounds")==0) {
1353 SCRect screct;
1354 err = slotGetSCRect(slot, &screct);
1355 if (err) return err;
1356 refreshFocus();
1357 setBounds(screct);
1358 refreshFocus();
1359 return errNone;
1361 return SCView::setProperty(symbol, slot);
1364 int SCLayoutView::getProperty(PyrSymbol *symbol, PyrSlot *slot)
1366 char *name = symbol->name;
1367 if (strcmp(name, "spacing")==0) {
1368 SetFloat(slot, mSpacing);
1369 return errNone;
1372 return SCView::getProperty(symbol, slot);
1375 void SCLayoutView::add(SCView *inChild)
1377 SCContainerView::add(inChild);
1378 setBounds(mBounds); // re-layout
1381 /////////////////////////////////////////////////////////////////////////////////////
1383 SCView* NewSCHLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1385 return new SCHLayoutView(inParent, inObj, inBounds);
1388 SCHLayoutView::SCHLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1389 : SCLayoutView(inParent, inObj, inBounds)
1393 SCHLayoutView::~SCHLayoutView()
1397 void SCHLayoutView::setBounds(SCRect inBounds)
1399 SCView *child = mChildren;
1400 float totalWeight = 0.0;
1401 //if reativeOrigin is true, the inBounds need to be moved to absolute bounds
1402 mBounds = inBounds;
1403 if(!(mParent->isSubViewScroller())){
1404 SCRect pbounds = mParent->getLayout().bounds;
1405 mLayout.bounds.x = mBounds.x + pbounds.x;
1406 mLayout.bounds.y = mBounds.y + pbounds.y;
1407 mLayout.bounds.width = mBounds.width;
1408 mLayout.bounds.height = mBounds.height;
1409 } else {
1410 mLayout.bounds = mBounds;
1412 SCRect absBounds = mLayout.bounds;
1413 while(child) {
1414 Layout layout = child->getLayout();
1415 // could store this when child added
1416 totalWeight += layout.mWeight;
1417 child = child->next();
1419 // subtract the spacers we will use
1420 float totalWidth = absBounds.width - (mSpacing * (mNumChildren - 1));
1422 // find views who are constrained by a minimum or maximum size
1423 // and remove them from the set of weights.
1424 float scaleWeight = sc_max(totalWidth,0.0) * (1.0 / sc_max(totalWeight,0.01));
1425 child = mChildren;
1426 float widths[mNumChildren];
1427 SCView *children[mNumChildren];
1428 int ri = mNumChildren;
1429 while(child) {
1430 float width;
1431 //reverse the array
1432 children[--ri] = child;
1433 Layout layout = child->getLayout();
1434 float weightedWidth = scaleWeight * layout.mWeight;
1435 if(layout.mHResize == 0) {// okay to resize
1436 if (weightedWidth < layout.mMinWidth) {
1437 width = layout.mMinWidth;
1438 widths[ri] = width;
1439 totalWidth -= width;
1440 totalWeight -= layout.mWeight;
1441 } else {
1442 if (weightedWidth > layout.mMaxWidth) {
1443 width = layout.mMaxWidth;
1444 widths[ri] = width;
1445 totalWidth -= width;
1446 totalWeight -= layout.mWeight;
1447 } else {
1448 widths[ri] = -1.0;
1451 } else {
1452 SCRect rect = child->getBounds();
1453 widths[ri] = rect.width;
1455 child = child->next();
1457 //totalWidth is now the remaining flexible width
1459 // now layout the views
1460 float left = 0.f; // subviews will automatically offset from window origin
1461 float top = 0.f;
1462 float height = absBounds.height;
1463 // NSLog(@"view bounds: %f, %f, %f, %f", absBounds.x, absBounds.y, absBounds.width, absBounds.height);
1464 scaleWeight = totalWidth * (1.0/totalWeight);
1465 child = mChildren;
1466 int i=0;
1467 for(; i < mNumChildren; i++ ) {
1468 child = children[i];
1469 Layout layout = child->getLayout();
1470 float width;
1471 if(widths[i] == -1.0) {
1472 width = scaleWeight * layout.mWeight;
1473 } else { // was constrained
1474 width = widths[i];
1476 child->setBounds(SCMakeRect( left, top, width, height));
1477 left += (width + mSpacing);
1478 child = child->next();
1483 /////////////////////////////////////////////////////////////////////////////////////
1485 SCView* NewSCVLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1487 return new SCVLayoutView(inParent, inObj, inBounds);
1490 SCVLayoutView::SCVLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1491 : SCLayoutView(inParent, inObj, inBounds)
1495 SCVLayoutView::~SCVLayoutView()
1499 void SCVLayoutView::setBounds(SCRect inBounds)
1501 SCView *child = mChildren;
1502 float totalWeight = 0.0;
1503 while(child) {
1504 Layout layout = child->getLayout();
1505 // could store this when child added
1506 totalWeight += layout.mWeight;
1507 child = child->next();
1509 //if reativeOrigin is true, the inBounds need to be moved to absolute bounds
1510 mBounds = inBounds;
1511 if(!(mParent->isSubViewScroller())){
1512 SCRect pbounds = mParent->getLayout().bounds;
1513 mLayout.bounds.x = mBounds.x + pbounds.x;
1514 mLayout.bounds.y = mBounds.y + pbounds.y;
1515 mLayout.bounds.width = mBounds.width;
1516 mLayout.bounds.height = mBounds.height;
1517 } else {
1518 mLayout.bounds = mBounds;
1520 SCRect absBounds = mLayout.bounds;
1521 // subtract the spacers we will use
1522 float totalHeight = absBounds.height - (mSpacing * (mNumChildren - 1));
1524 // find views who are constrained by a minimum or maximum size
1525 // and remove them from the set of weights.
1526 float scaleWeight = sc_max(totalHeight,0.0) * (1.0 / sc_max(totalWeight,0.01));
1527 child = mChildren;
1528 float heights[mNumChildren];
1529 SCView *children[mNumChildren];
1530 int ri = mNumChildren;
1531 while(child) {
1532 float height;
1533 //reverse the array
1534 children[--ri] = child;
1535 Layout layout = child->getLayout();
1536 float weightedHeight = scaleWeight * layout.mWeight;
1537 if(layout.mVResize == 0) {// okay to resize
1538 if (weightedHeight < layout.mMinHeight) {
1539 height = layout.mMinHeight;
1540 heights[ri] = height;
1541 totalHeight -= height;
1542 totalWeight -= layout.mWeight;
1543 } else {
1544 if (weightedHeight > layout.mMaxHeight) {
1545 height = layout.mMaxHeight;
1546 heights[ri] = height;
1547 totalHeight -= height;
1548 totalWeight -= layout.mWeight;
1549 } else {
1550 heights[ri] = -1.0;
1553 } else {
1554 SCRect rect = child->getBounds();
1555 heights[ri] = rect.height;
1557 child = child->next();
1559 //totalHeight is now the remaining flexible height
1561 // now layout the views
1562 float left = 0.f; // subviews will automatically offset from window origin
1563 float top = 0.f;
1564 float width = absBounds.width;
1565 scaleWeight = totalHeight * (1.0/totalWeight);
1566 child = mChildren;
1567 int i=0;
1568 for(; i < mNumChildren; i++ ) {
1569 child = children[i];
1570 Layout layout = child->getLayout();
1571 float height;
1572 if(heights[i] == -1.0) {
1573 height = scaleWeight * layout.mWeight;
1574 } else { // was constrained
1575 height = heights[i];
1577 child->setBounds(SCMakeRect( left, top, width, height));
1578 top += (height + mSpacing);
1579 child = child->next();
1585 /////////////////////////////////////////////////////////////////////////////////////
1588 SCView* NewSCTopView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1590 return new SCTopView(inObj, inBounds);
1593 SCTopView::SCTopView(PyrObject* inObj, SCRect inBounds)
1594 : SCCompositeView(0, inObj, inBounds), mFocusView(0), mDragView(0), mConstructionMode(false)
1596 mTop = this;
1597 //float ltgry = 0.8;
1598 //float dkgry = 0.5;
1599 //mBackground = new SolidColorBackground(
1600 // SCMakeColor(ltgry, ltgry, ltgry, 1.0));
1603 void SCTopView::addDamage(SCRect inRect)
1605 (*mDamageCallback)(inRect, mHostData);
1606 //mDamage = SCRectUnion(mDamage, inRect);
1609 void SCTopView::beginDragCallback(SCPoint where, PyrSlot* slot, NSString* string, NSString* label)
1611 (*mDragCallback)(where, slot, string, label, mHostData);
1614 void SCView::refreshFocus()
1616 SCRect focusBounds = getDrawBounds();
1617 focusBounds.x -= 4;
1618 focusBounds.y -= 4;
1619 focusBounds.width += 8;
1620 focusBounds.height += 8;
1621 mTop->addDamage(focusBounds);
1624 void SCTopView::resetFocus()
1626 SCView *view = focusView();
1627 if (view && !view->canFocus()) {
1628 focusIs(0);
1629 view->refreshFocus();
1633 void SCTopView::forgetView(SCView *view)
1635 if (view == mFocusView) mFocusView = 0;
1636 if (view == mDragView) mDragView = 0;
1639 void SCTopView::tabNextFocus()
1641 bool foundFocus = mFocusView ? false : true;
1642 SCView *view = nextFocus(&foundFocus, true);
1643 if (!view && foundFocus) view = nextFocus(&foundFocus, true);
1644 if (view) view->makeFocus(true);
1647 void SCTopView::tabPrevFocus()
1649 SCView *prevView = 0;
1650 SCView *view = prevFocus(&prevView, true);
1651 if (!view && prevView) view = prevView;
1652 if (view) view->makeFocus(true);
1655 void SCTopView::setDragView(SCView *inView)
1657 if (inView != mDragView) {
1658 if (mDragView) mDragView->setDragHilite(false);
1659 mDragView = inView;
1660 if (mDragView) mDragView->setDragHilite(true);
1664 void SCTopView::drawFocus(SCRect inDamage)
1666 if (ConstructionMode()) {
1667 CGRect rect = SCtoCGRect(mBounds);
1668 rect.origin.x += 2;
1669 rect.origin.y += 2;
1670 rect.size.width -= 4;
1671 rect.size.height -= 4;
1672 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
1673 CGContextSaveGState(cgc);
1674 CGContextSetLineWidth(cgc, 4);
1675 CGContextSetRGBStrokeColor(cgc, 1., 1., 0., 1.);
1676 CGContextStrokeRect(cgc, rect);
1677 CGContextRestoreGState(cgc);
1681 bool SCTopView::canReceiveDrag()
1683 PyrSlot result;
1684 sendMessage(s_canReceiveDrag, 0, 0, &result);
1685 return IsTrue(&result);
1688 void SCTopView::receiveDrag()
1690 sendMessage(s_receiveDrag, 0, 0, 0);
1693 void SCTopView::setInternalBounds(SCRect internalBounds)
1695 setBounds(internalBounds);
1698 /////////////////////////////////////////////////////////////////////////////////////
1701 SCView* NewSCScrollTopView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1703 return new SCScrollTopView(inObj, inBounds);
1706 SCScrollTopView::SCScrollTopView(PyrObject* inObj, SCRect inBounds)
1707 : SCTopView(inObj, inBounds), mInSetClipViewOrigin(false)
1712 SCRect SCScrollTopView::checkMinimumSize()
1714 // size of SCGraphView must be at least large enough to hold any contained view for correct scrolling
1715 // so test against the NSClipView
1716 SCView *child = mChildren;
1718 SCRect candidate = SCMakeRect(0.f, 0.f, 1.f, 1.f); // smallest measureable at rect at origin
1720 // iterate through all the views and see if we need to be bigger
1721 while (child) {
1722 SCRect bounds = child->checkMinimumSize();
1723 candidate = SCRectUnion(bounds, candidate);
1724 child = child->next();
1727 return candidate;
1730 SCRect SCScrollTopView::getDrawBounds() //relative to ContainerView
1732 return SCRectUnion(mBounds, checkMinimumSize());
1735 void SCScrollTopView::setInternalBounds(SCRect inBounds)
1737 // elasticity doesn't work with a scrolltopview
1738 mBounds = inBounds;
1741 int slotGetPoint(PyrSlot* a, NSPoint *p);
1743 int SCScrollTopView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
1745 int err;
1746 char *name = symbol->name;
1747 if (strcmp(name, "setHasHorizontalScroller")==0) {
1748 bool hasScroller = IsTrue(slot);
1749 setInSetClipViewOrigin(true);
1750 [mNSScrollView setHasHorizontalScroller:hasScroller];
1751 [(SCGraphView*)mNSView setFrameSizeToMinimum];
1752 setInSetClipViewOrigin(false);
1753 refresh();
1754 return errNone;
1757 if (strcmp(name, "setHasVerticalScroller")==0) {
1758 bool hasScroller = IsTrue(slot);
1759 setInSetClipViewOrigin(true);
1760 [mNSScrollView setHasVerticalScroller:hasScroller];
1761 [(SCGraphView*)mNSView setFrameSizeToMinimum];
1762 setInSetClipViewOrigin(false);
1763 refresh();
1764 return errNone;
1767 if (strcmp(name, "setAutohidesScrollers")==0) {
1768 bool autoHides = IsTrue(slot);
1769 setInSetClipViewOrigin(true);
1770 [mNSScrollView setAutohidesScrollers:autoHides];
1771 [(SCGraphView*)mNSView setFrameSizeToMinimum];
1772 [mNSScrollView setNeedsDisplay: YES];
1774 // trick scrollview into redrawing
1775 NSRect frame = [mNSScrollView frame];
1776 [mNSScrollView setFrame: NSInsetRect(frame,1,1)];
1777 [mNSScrollView setFrame: frame];
1778 setInSetClipViewOrigin(false);
1779 refresh();
1780 return errNone;
1783 if (strcmp(name, "clipViewOrigin")==0) {
1784 NSPoint origin;
1785 err = slotGetPoint(slot, &origin);
1786 if (err) return err;
1787 setInSetClipViewOrigin(true);
1788 [[mNSScrollView documentView] scrollPoint:origin];
1789 setInSetClipViewOrigin(false);
1790 refresh();
1791 return errNone;
1794 if (strcmp(name, "setAutoScrolls")==0) {
1795 bool autoScrolls = IsTrue(slot);
1796 [(SCGraphView*)mNSView setAutoScrolls:autoScrolls];
1797 return errNone;
1800 if (strcmp(name, "visible")==0) {
1801 bool visible = IsTrue(slot);
1802 if(visible)
1804 [mNSScrollView setHidden:NO];
1806 else
1808 [mNSScrollView setHidden:YES];
1810 mVisible = visible;
1811 setVisibleFromParent(); //SCContainerView
1812 resetFocus();
1813 return errNone;
1816 return SCCompositeView::setProperty(symbol, slot);
1819 int SCScrollTopView::getProperty(PyrSymbol *symbol, PyrSlot *slot)
1821 char *name = symbol->name;
1822 if (strcmp(name, "absoluteBounds")==0) {
1823 if (!(isKindOfSlot(slot, s_rect->u.classobj))) {
1824 return errWrongType;
1826 SCRect bounds = NStoSCRect([mNSScrollView frame]);
1827 PyrSlot *slots = slotRawObject(slot)->slots;
1828 SetFloat(slots+0, bounds.x);
1829 SetFloat(slots+1, bounds.y);
1830 SetFloat(slots+2, bounds.width);
1831 SetFloat(slots+3, bounds.height);
1832 return errNone;
1835 if (strcmp(name, "clipViewOrigin")==0) {
1836 if (!(isKindOfSlot(slot, s_point->u.classobj))) {
1837 return errWrongType;
1839 NSPoint origin = [mNSScrollView documentVisibleRect].origin;
1840 PyrSlot *slots = slotRawObject(slot)->slots;
1841 SetFloat(slots+0, origin.x);
1842 SetFloat(slots+1, origin.y);
1843 return errNone;
1846 if (strcmp(name, "innerBounds")==0) {
1847 if (!(isKindOfSlot(slot, s_rect->u.classobj))) {
1848 return errWrongType;
1850 SCRect bounds = NStoSCRect([mNSView frame]);
1851 PyrSlot *slots = slotRawObject(slot)->slots;
1852 SetFloat(slots+0, bounds.x);
1853 SetFloat(slots+1, bounds.y);
1854 SetFloat(slots+2, bounds.width);
1855 SetFloat(slots+3, bounds.height);
1856 return errNone;
1859 return SCCompositeView::getProperty(symbol, slot);
1862 void SCScrollTopView::add(SCView *inChild)
1864 setInSetClipViewOrigin(true);
1865 SCContainerView::add(inChild);
1866 [(SCGraphView*)GetNSView() setFrameSizeToMinimum];
1867 setInSetClipViewOrigin(false);
1870 void SCScrollTopView::remove(SCView *inChild)
1872 setInSetClipViewOrigin(true);
1873 SCContainerView::remove(inChild);
1874 [(SCGraphView*)GetNSView() setFrameSizeToMinimum];
1875 setInSetClipViewOrigin(false);
1878 /////////////////////////////////////////////////////////////////////////////////////
1881 SCView* NewSCScrollView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1883 return new SCScrollView(inParent, inObj, inBounds);
1886 SCScrollView::SCScrollView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1887 : SCScrollTopView(inObj, inBounds)
1890 NSRect bounds = SCtoNSRect(inBounds);
1892 if (inParent){
1893 inParent->add(this);
1894 if(!(inParent->isSubViewScroller())){
1895 SCRect pbounds = inParent->getLayout().bounds;
1896 mLayout.bounds.x = mBounds.x + pbounds.x;
1897 mLayout.bounds.y = mBounds.y + pbounds.y;
1898 mLayout.bounds.width = mBounds.width;
1899 mLayout.bounds.height = mBounds.height;
1900 } else {
1901 mLayout.bounds = mBounds;
1906 NSView *topGraphview = mTop->GetNSView();
1907 SCGraphView* view = [[SCGraphView alloc] initWithFrame: NSMakeRect(0, 0, bounds.size.width, bounds.size.height)];
1908 [view setSCObject: [(SCGraphView*)topGraphview getSCObject]];
1910 [view setSCTopView: this];
1911 NSScrollView *scrollView = [[NSScrollView alloc] initWithFrame: SCtoNSRect(mLayout.bounds)];
1912 [scrollView setHasVerticalScroller:YES];
1913 [scrollView setHasHorizontalScroller:YES];
1914 [scrollView setAutohidesScrollers:YES];
1915 [[scrollView horizontalScroller] setControlSize:NSSmallControlSize];
1916 [[scrollView verticalScroller] setControlSize:NSSmallControlSize];
1917 [[scrollView horizontalScroller] setControlTint:NSGraphiteControlTint];
1918 [[scrollView verticalScroller] setControlTint:NSGraphiteControlTint];
1920 [scrollView setBackgroundColor:[NSColor clearColor]];
1921 [scrollView setDrawsBackground:NO];
1922 // configure the scroller to have no visible border
1923 [scrollView setBorderType:NSNoBorder];
1924 [scrollView setAutoresizingMask:NSViewNotSizable];
1925 [scrollView setDocumentView:view];
1927 [scrollView setPostsFrameChangedNotifications: YES]; // we need this to resize the SCGraphView if the scroll view exceeds its bounds
1928 [[NSNotificationCenter defaultCenter] addObserver:view
1929 selector:@selector(scrollViewResized:)
1930 name:@"NSViewFrameDidChangeNotification"
1931 object:scrollView];
1933 NSClipView *contentView = [scrollView contentView];
1934 [contentView setPostsBoundsChangedNotifications:YES];
1935 [[NSNotificationCenter defaultCenter] addObserver:view
1936 selector:@selector(userScrolled:)
1937 name:@"NSViewBoundsDidChangeNotification"
1938 object:contentView];
1940 SetNSScrollView(scrollView);
1941 [topGraphview addSubview: scrollView];
1942 [view setFrameSizeToMinimum];
1943 setBounds(mLayout.bounds);
1944 setVisibleFromParent();
1948 void SCScrollView::add(SCView *inChild)
1950 inChild->mNext = mChildren;
1951 mChildren = inChild;
1952 mNumChildren++;
1953 inChild->mParent = this;
1954 inChild->mTop = this;
1955 inChild->refresh();
1956 [(SCGraphView*)GetNSView() setFrameSizeToMinimum];
1959 void SCScrollView::drawIfNecessary(SCRect inDamage)
1961 // only draw when our own SCGraphView wants it
1962 // not for the top level SCGraphView
1963 // so this returns nothing
1966 void SCScrollView::drawSubViewIfNecessary(SCRect inDamage)
1968 SCRect maxContentBounds;
1969 // its not my mBounds nor my drawBounds that we want to test against
1970 // but rather my contents' total bounds
1971 maxContentBounds = checkMinimumSize();
1972 // there might be a short cut to this
1974 if (SCRectsDoIntersect(inDamage, maxContentBounds) && mVisible) {
1975 draw(inDamage);
1976 SCView *child = mChildren;
1977 SCView *children[mNumChildren];
1978 int k = mNumChildren;
1979 while (child) {
1980 children[--k] = child;
1981 child = child->next();
1983 for(int i=0; i < mNumChildren; i++ ) {
1984 child = children[i];
1985 child->drawIfNecessary(inDamage);
1988 drawDisabled(inDamage);
1989 drawDragHilite(inDamage);
1990 drawFocus(inDamage);
1994 void SCScrollView::setBounds(SCRect inBounds)
1996 [mNSScrollView setFrame: SCtoNSRect(inBounds)];
1999 SCRect SCScrollView::getBounds()
2001 return NStoSCRect([mNSScrollView frame]);
2004 int SCScrollView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
2006 int err;
2007 char *name = symbol->name;
2008 if (strcmp(name, "bounds")==0) {
2009 SCRect screct;
2010 err = slotGetSCRect(slot, &screct);
2011 if (err) return err;
2012 refreshFocus();
2013 SCRect pbounds = mParent->getLayout().bounds; // relative origin fix
2014 screct.x += pbounds.x;
2015 screct.y += pbounds.y;
2017 setBounds(screct);
2018 refreshFocus();
2019 return errNone;
2022 if (strcmp(name, "border")==0) {
2023 bool hasBorder = IsTrue(slot);
2024 if(hasBorder) {
2025 [mNSScrollView setBorderType:NSLineBorder];
2026 } else {
2027 [mNSScrollView setBorderType:NSNoBorder];
2029 [(SCGraphView*)mNSView setFrameSizeToMinimum];
2030 refresh();
2031 return errNone;
2034 if (strcmp(name, "visible")==0) {
2035 bool visible = IsTrue(slot);
2036 mVisible = visible;
2037 setVisibleFromParent();
2038 return errNone;
2041 return SCScrollTopView::setProperty(symbol, slot);
2044 void SCScrollView::setVisibleFromParent()
2046 if(mVisible && mParent->isVisible()) {
2047 [mNSScrollView setHidden:NO];
2048 } else {
2049 [mNSScrollView setHidden:YES];
2051 SCContainerView::setVisibleFromParent();
2052 mTop->resetFocus();
2055 SCScrollView::~SCScrollView()
2057 [mNSScrollView removeFromSuperview];
2058 [mNSScrollView release];
2061 ///////////////////////////////////////////////////////////////////////////////////////
2063 SCView* NewSCSlider(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
2065 return new SCSlider(inParent, inObj, inBounds);
2068 SCSlider::SCSlider(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
2069 : SCView(inParent, inObj, inBounds), mStepSize(0.), mStepScale(0.), mKnob(0), mThumbSize(12.)
2071 mValue = 1.;
2072 setValue(0.0, false);
2075 //int drawBevelRect(Rect r, int width, int inout, RGBColor color, int drawop);
2077 void SCSlider::draw(SCRect inDamage)
2079 SCRect bounds = getDrawBounds();
2080 calcThumbRect(bounds);
2082 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
2083 CGContextSaveGState(cgc);
2084 CGRect rect = SCtoCGRect(bounds);
2085 if (mBackground) mBackground->draw(cgc, rect);
2087 if (mBackgroundImage)
2088 mBackgroundImage->draw(cgc, rect);
2090 #if 1
2091 QDDrawBevelRect(cgc, rect, 1, true);
2092 #endif
2094 CGRect cgThumbRect = SCtoCGRect(mThumbRect);
2095 if (mKnob) mKnob->draw(cgc, cgThumbRect);
2096 QDDrawBevelRect(cgc, cgThumbRect, 2, false);
2097 CGContextRestoreGState(cgc);
2099 //drawBevelRect(SCtoQDRect(mBounds), 1, 1, SCtoQDColor(mBackColor), 2);
2100 //drawBevelRect(SCtoQDRect(mThumbRect), 2, 0, SCtoQDColor(mKnobColor), 2);
2103 bool SCSlider::setValue(double inValue, bool send)
2105 inValue = sc_clip(inValue, 0., 1.);
2106 if (mStepSize > 0.) {
2107 inValue = floor(inValue * mStepScale + 0.5) * mStepSize;
2109 bool changed = inValue != mValue;
2110 if (changed) {
2111 mValue = inValue;
2112 refresh();
2114 if (send) sendMessage(s_doaction, 0, 0, 0);
2116 return changed;
2119 void SCSlider::setValueFromPoint(SCPoint point)
2121 double moveableRange, value;
2122 SCRect bounds = getDrawBounds();
2123 if (bounds.width > bounds.height) {
2124 moveableRange = bounds.width - mThumbSize - 2;
2125 value = (point.x - bounds.x - 1 - mThumbSize/2) / moveableRange;
2126 } else {
2127 moveableRange = bounds.height - mThumbSize - 2;
2128 value = 1. - (point.y - bounds.y - 1 - mThumbSize/2) / moveableRange;
2130 setValue(value, true);
2133 void SCSlider::calcThumbRect(SCRect bounds)
2135 double moveableRange;
2137 moveableRange = (bounds.width > bounds.height)
2138 ? bounds.width : bounds.height;
2139 moveableRange -= mThumbSize + 2;
2141 double offset = mValue * moveableRange;
2143 if (bounds.width > bounds.height) {
2144 mThumbRect = SCMakeRect(bounds.x + offset + 1, bounds.y + 1,
2145 mThumbSize, bounds.height - 2);
2146 } else {
2147 mThumbRect = SCMakeRect(bounds.x + 1, bounds.y + bounds.height - offset - 1 - mThumbSize,
2148 bounds.width - 2, mThumbSize);
2152 void SCSlider::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
2154 if (modifiers & NSCommandKeyMask) {
2155 beginDrag(where);
2156 } else {
2157 setValueFromPoint(where);
2161 int SCSlider::setProperty(PyrSymbol *symbol, PyrSlot *slot)
2163 int err;
2164 if (symbol == s_value) {
2165 double value;
2166 err = slotDoubleVal(slot, &value);
2167 if (err) return err;
2168 bool changed = setValue(value, false);
2169 SetBool(slot, changed);
2170 return errNone;
2172 char *name = symbol->name;
2173 if (strcmp(name, "knobColor")==0) {
2174 err = slotBackgroundVal(slot, &mKnob);
2175 if (err) return err;
2176 refresh();
2177 return errNone;
2179 if (strcmp(name, "step")==0) {
2180 err = slotDoubleVal(slot, &mStepSize);
2181 if (!err) {
2182 mStepScale = 1. / mStepSize;
2183 bool changed = setValue(mValue, false);
2184 SetBool(slot, changed);
2186 return errNone;
2188 if (strcmp(name, "thumbSize")==0) {
2189 err = slotFloatVal(slot, &mThumbSize);
2190 if (err) return err;
2191 refresh();
2192 return errNone;
2195 return SCView::setProperty(symbol, slot);
2198 int SCSlider::getProperty(PyrSymbol *symbol, PyrSlot *slot)
2200 if (symbol == s_value) {
2201 SetFloat(slot, mValue);
2202 return errNone;
2204 char *name = symbol->name;
2205 if (strcmp(name, "step")==0) {
2206 SetFloat(slot, mStepSize);
2207 return errNone;
2209 if (strcmp(name, "thumbSize")==0) {
2210 SetFloat(slot, mThumbSize);
2211 return errNone;
2214 return SCView::getProperty(symbol, slot);
2219 bool SCSlider::canReceiveDrag()
2221 PyrSlot result;
2222 sendMessage(s_canReceiveDrag, 0, 0, &result);
2223 return IsTrue(&result);
2226 void SCSlider::receiveDrag()
2228 sendMessage(s_receiveDrag, 0, 0, 0);
2231 ///////////////////////////////////////////////////////////////////////////////////////
2233 SCView* NewSCRangeSlider(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
2235 return new SCRangeSlider(inParent, inObj, inBounds);
2238 SCRangeSlider::SCRangeSlider(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
2239 : SCView(inParent, inObj, inBounds), mStepSize(0.), mStepScale(0.)
2241 mKnob = new HiliteGradientBackground(SCMakeColor(0,0,0.5,1), SCMakeColor(0.5,0.5,1,1), grad_Narrow, 24);
2242 mLo = -1.;
2243 mHi = -1.;
2244 setValue(0.0, 0.0, false);
2247 //int drawBevelRect(Rect r, int width, int inout, RGBColor color, int drawop);
2249 void SCRangeSlider::draw(SCRect inDamage)
2251 calcRangeRect();
2252 SCRect bounds = getDrawBounds();
2254 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
2255 CGContextSaveGState(cgc);
2257 CGRect cgBounds = SCtoCGRect(bounds);
2258 if (mBackground) mBackground->draw(cgc, cgBounds);
2260 if (mBackgroundImage)
2261 mBackgroundImage->draw(cgc, cgBounds);
2263 QDDrawBevelRect(cgc, cgBounds, 1, true);
2265 CGRect cgRangeRect = SCtoCGRect(mRangeRect);
2266 if (mKnob) mKnob->draw(cgc, cgRangeRect);
2267 QDDrawBevelRect(cgc, cgRangeRect, 1, false);
2268 CGContextRestoreGState(cgc);
2270 //drawBevelRect(SCtoQDRect(mBounds), 2, 1, SCtoQDColor(mBackColor), 2);
2271 //drawBevelRect(SCtoQDRect(mRangeRect), 1, 0, SCtoQDColor(mKnobColor), 2);
2274 bool SCRangeSlider::setValue(double inLo, double inHi, bool send)
2276 inLo = sc_clip(inLo, 0., 1.);
2277 inHi = sc_clip(inHi, 0., 1.);
2279 if (mStepSize > 0.) {
2280 inLo = floor(inLo * mStepScale + 0.5) * mStepSize;
2281 inHi = floor(inHi * mStepScale + 0.5) * mStepSize;
2283 bool changed = inLo != mLo || inHi != mHi;
2284 if (changed) {
2285 mLo = inLo;
2286 mHi = inHi;
2287 refresh();
2289 if (send) sendMessage(s_doaction, 0, 0, 0);
2291 return changed;
2294 void SCRangeSlider::setValueFromPoint(SCPoint where)
2296 double moveableRange, lo, hi;
2297 SCRect bounds = getDrawBounds();
2299 if (bounds.width > bounds.height) {
2300 moveableRange = bounds.width - 5;
2301 lo = (sc_min(mAnchor.x, where.x) - bounds.x - 2) / moveableRange;
2302 hi = (sc_max(mAnchor.x, where.x) - bounds.x - 2) / moveableRange;
2303 } else {
2304 moveableRange = bounds.height - 5;
2305 lo = 1. - (sc_max(mAnchor.y, where.y) - bounds.y - 2) / moveableRange;
2306 hi = 1. - (sc_min(mAnchor.y, where.y) - bounds.y - 2) / moveableRange;
2308 setValue(lo, hi, true);
2311 void SCRangeSlider::calcRangeRect()
2313 double moveableRange;
2314 SCRect bounds = getDrawBounds();
2315 moveableRange = (bounds.width > bounds.height)
2316 ? bounds.width : bounds.height;
2317 moveableRange -= 5;
2319 double lo = mLo * moveableRange;
2320 double hi = mHi * moveableRange + 1;
2322 if (bounds.width > bounds.height) {
2323 mRangeRect = SCMakeRect(bounds.x + lo + 2, bounds.y + 1,
2324 hi - lo, bounds.height - 2);
2325 } else {
2326 mRangeRect = SCMakeRect(bounds.x + 1, bounds.y + bounds.height - hi - 2,
2327 bounds.width - 2, hi - lo);
2331 void SCRangeSlider::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
2333 mAnchor = where;
2334 // sc.solar: allow drag
2335 //setValueFromPoint(where);
2338 void SCRangeSlider::moveRangeFromPoint(SCPoint where)
2340 double moveableRange, lo, hi, pos, range;
2341 SCRect bounds = getDrawBounds();
2342 if (bounds.width > bounds.height) {
2343 moveableRange = bounds.width - 5;
2344 pos = (where.x - bounds.x - 2) / moveableRange;
2345 range = mHi - mLo;
2346 if (pos-(range/2) < 0.0) {
2347 lo = 0;
2348 hi = range;
2349 } else if (pos+(range/2) > 1.0) {
2350 hi = 1;
2351 lo = 1 - range;
2352 } else {
2353 lo = pos-(range/2);
2354 hi = pos+(range/2);
2356 } else {
2357 moveableRange = bounds.height - 5;
2358 pos = 1.0 - (where.y - bounds.y - 2) / moveableRange;
2359 range = mHi - mLo;
2360 if (pos-(range/2) < 0.0) {
2361 lo = 0;
2362 hi = range;
2363 } else if (pos+(range/2) > 1.0) {
2364 hi = 1;
2365 lo = 1 - range;
2366 } else {
2367 lo = pos-(range/2);
2368 hi = pos+(range/2);
2371 setValue(lo, hi, true);
2374 void SCRangeSlider::adjustLoFromPoint(SCPoint where)
2376 double moveableRange, lo, hi, pos;
2377 SCRect bounds = getDrawBounds();
2378 if (bounds.width > bounds.height) {
2379 moveableRange = bounds.width - 5;
2380 pos = (where.x - bounds.x - 2) / moveableRange;
2381 lo = pos;
2382 hi = mHi;
2383 } else {
2384 moveableRange = bounds.height - 5;
2385 pos = (where.y - bounds.y - 2) / moveableRange;
2386 lo = pos;
2387 hi = mHi;
2389 setValue(lo, hi, true);
2391 void SCRangeSlider::adjustHiFromPoint(SCPoint where)
2393 double moveableRange, lo, hi, pos;
2394 SCRect bounds = getDrawBounds();
2395 if (bounds.width > bounds.height) {
2396 moveableRange = bounds.width - 5;
2397 pos = (where.x - bounds.x - 2) / moveableRange;
2398 lo = mLo;
2399 hi = pos;
2400 } else {
2401 moveableRange = bounds.height - 5;
2402 pos = (where.y - bounds.y - 2) / moveableRange;
2403 lo = mLo;
2404 hi = pos;
2406 setValue(lo, hi, true);
2409 void SCRangeSlider::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
2411 if (modifiers & NSCommandKeyMask) {
2412 beginDrag(where);
2413 } else if (modifiers & NSControlKeyMask) {
2414 moveRangeFromPoint(where);
2415 } else if (modifiers & NSShiftKeyMask) {
2416 adjustLoFromPoint(where);
2417 } else if (modifiers & NSAlternateKeyMask) {
2418 adjustHiFromPoint(where);
2419 } else {
2420 setValueFromPoint(where);
2424 int SCRangeSlider::setProperty(PyrSymbol *symbol, PyrSlot *slot)
2426 int err;
2427 if (symbol == s_lo || symbol == s_value) {
2428 double lo;
2429 err = slotDoubleVal(slot, &lo);
2430 if (err) return err;
2431 bool changed = setValue(lo, mHi, false);
2432 SetBool(slot, changed);
2433 return errNone;
2435 if (symbol == s_hi) {
2436 double hi;
2437 err = slotDoubleVal(slot, &hi);
2438 if (err) return err;
2439 bool changed = setValue(mLo, hi, false);
2440 SetBool(slot, changed);
2441 return errNone;
2443 if (symbol == s_range) {
2444 double range;
2445 err = slotDoubleVal(slot, &range);
2446 if (err) return err;
2447 bool changed = setValue(mLo, mLo + range, false);
2448 SetBool(slot, changed);
2449 return errNone;
2451 char *name = symbol->name;
2452 if (strcmp(name, "step")==0) {
2453 err = slotDoubleVal(slot, &mStepSize);
2454 if (!err) {
2455 mStepScale = 1. / mStepSize;
2456 bool changed = setValue(mLo, mHi, false);
2457 SetBool(slot, changed);
2459 return errNone;
2461 if (strcmp(name, "knobColor")==0) {
2462 err = slotBackgroundVal(slot, &mKnob);
2463 if (err) return err;
2464 refresh();
2465 return errNone;
2468 return SCView::setProperty(symbol, slot);
2471 int SCRangeSlider::getProperty(PyrSymbol *symbol, PyrSlot *slot)
2473 if (symbol == s_lo || symbol == s_value) {
2474 SetFloat(slot, mLo);
2475 return errNone;
2477 if (symbol == s_hi) {
2478 SetFloat(slot, mHi);
2479 return errNone;
2481 if (symbol == s_range) {
2482 SetFloat(slot, mHi - mLo);
2483 return errNone;
2485 char *name = symbol->name;
2486 if (strcmp(name, "step")==0) {
2487 SetFloat(slot, mStepSize);
2488 return errNone;
2491 return SCView::getProperty(symbol, slot);
2495 bool SCRangeSlider::canReceiveDrag()
2497 PyrSlot result;
2498 sendMessage(s_canReceiveDrag, 0, 0, &result);
2499 return IsTrue(&result);
2502 void SCRangeSlider::receiveDrag()
2504 sendMessage(s_receiveDrag, 0, 0, 0);
2507 ///////////////////////////////////////////////////////////////////////////////////////
2509 SCView* NewSC2DSlider(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
2511 return new SC2DSlider(inParent, inObj, inBounds);
2514 SC2DSlider::SC2DSlider(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
2515 : SCView(inParent, inObj, inBounds), mStepSize(0.), mStepScale(0.), mKnob(0)
2517 mX = -1.;
2518 mY = -1.;
2519 setValue(0.0, 0.0, false);
2522 //int drawBevelRect(Rect r, int width, int inout, RGBColor color, int drawop);
2524 void SC2DSlider::draw(SCRect inDamage)
2526 calcThumbRect();
2528 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
2529 CGContextSaveGState(cgc);
2530 CGRect rect = SCtoCGRect(getDrawBounds());
2531 if (mBackground) mBackground->draw(cgc, rect);
2533 if (mBackgroundImage)
2534 mBackgroundImage->draw(cgc, rect);
2536 QDDrawBevelRect(cgc, rect, 1, true);
2538 CGRect cgThumbRect = SCtoCGRect(mThumbRect);
2539 if (mKnob) mKnob->draw(cgc, cgThumbRect);
2540 QDDrawBevelRect(cgc, cgThumbRect, 2, false);
2541 CGContextRestoreGState(cgc);
2543 // drawBevelRect(SCtoQDRect(mBounds), 1, 1, SCtoQDColor(mBackColor), 2);
2544 // drawBevelRect(SCtoQDRect(mThumbRect), 2, 0, SCtoQDColor(mKnobColor), 2);
2547 bool SC2DSlider::setValue(double inX, double inY, bool send)
2549 inX = sc_clip(inX, 0., 1.);
2550 inY = sc_clip(inY, 0., 1.);
2551 if (mStepSize > 0.) {
2552 inX = floor(inX * mStepScale + 0.5) * mStepSize;
2553 inY = floor(inY * mStepScale + 0.5) * mStepSize;
2555 bool changed = inX != mX || inY != mY;
2556 if (changed) {
2557 mX = inX;
2558 mY = inY;
2559 refresh();
2561 if (send) sendMessage(s_doaction, 0, 0, 0);
2563 return changed;
2566 const int THUMBSIZE = 12;
2568 void SC2DSlider::setValueFromPoint(SCPoint where)
2570 SCRect bounds = getDrawBounds();
2571 double x = (where.x - bounds.x - 1 - THUMBSIZE/2) / (bounds.width - THUMBSIZE - 2);
2572 double y = 1. - (where.y - bounds.y - 1 - THUMBSIZE/2) / (bounds.height - THUMBSIZE - 2);
2573 setValue(x, y, true);
2576 void SC2DSlider::calcThumbRect()
2578 SCRect bounds = getDrawBounds();
2579 double x = mX * (bounds.width - THUMBSIZE - 2);
2580 double y = mY * (bounds.height - THUMBSIZE - 2);
2582 mThumbRect = SCMakeRect(bounds.x + x + 1, bounds.y + bounds.height - y - 1 - THUMBSIZE, THUMBSIZE, THUMBSIZE);
2585 void SC2DSlider::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
2587 if (modifiers & NSCommandKeyMask) {
2588 beginDrag(where);
2589 } else {
2590 setValueFromPoint(where);
2594 int SC2DSlider::setProperty(PyrSymbol *symbol, PyrSlot *slot)
2596 int err;
2597 if (symbol == s_x) {
2598 double x;
2599 err = slotDoubleVal(slot, &x);
2600 if (err) return err;
2601 bool changed = setValue(x, mY, false);
2602 SetBool(slot, changed);
2603 return errNone;
2605 if (symbol == s_y) {
2606 double y;
2607 err = slotDoubleVal(slot, &y);
2608 if (err) return err;
2609 bool changed = setValue(mX, y, false);
2610 SetBool(slot, changed);
2611 return errNone;
2613 char *name = symbol->name;
2614 if (strcmp(name, "knobColor")==0) {
2615 err = slotBackgroundVal(slot, &mKnob);
2616 if (err) return err;
2617 refresh();
2618 return errNone;
2620 if (strcmp(name, "step")==0) {
2621 err = slotDoubleVal(slot, &mStepSize);
2622 if (!err) {
2623 mStepScale = 1. / mStepSize;
2624 bool changed = setValue(mX, mY, false);
2625 SetBool(slot, changed);
2627 return errNone;
2630 return SCView::setProperty(symbol, slot);
2633 int SC2DSlider::getProperty(PyrSymbol *symbol, PyrSlot *slot)
2635 if (symbol == s_x) {
2636 SetFloat(slot, mX);
2637 return errNone;
2639 if (symbol == s_y) {
2640 SetFloat(slot, mY);
2641 return errNone;
2643 char *name = symbol->name;
2644 if (strcmp(name, "step")==0) {
2645 SetFloat(slot, mStepSize);
2646 return errNone;
2649 return SCView::getProperty(symbol, slot);
2652 bool SC2DSlider::canReceiveDrag()
2654 PyrSlot result;
2655 sendMessage(s_canReceiveDrag, 0, 0, &result);
2656 return IsTrue(&result);
2659 void SC2DSlider::receiveDrag()
2661 sendMessage(s_receiveDrag, 0, 0, 0);
2664 ///////////////////////////////////////////////////////////////////////////////////////
2665 ///////////////////////////////////////////////////////////////////////////////////////
2667 SCView* NewSCScope(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
2669 return new SCScope(inParent, inObj, inBounds);
2672 SCScope::SCScope(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
2673 : SCView(inParent, inObj, inBounds), mBufNum(0), mStyle(0), mGridOn(true)
2675 mZoom = mInvZoom = SCMakePoint(1.,1.);
2676 mScroll = SCMakePoint(0.,0.);
2677 memset(&mSndBuf, 0, sizeof(SndBuf));
2678 mGridColor = SCMakeColor(0.2,0.2,1.0, 1.0);
2679 mBackground = new SolidColorBackground(
2680 SCMakeColor(0.,0.,0., 1.0));
2681 SCColor waveColor = SCMakeColor(1.0,1.0,0.0, 1.0);
2682 for (int i=0; i<kMaxScopeChannels; ++i) mWaveColors[i] = waveColor;
2683 startAnimation();
2686 SCScope::~SCScope()
2688 stopAnimation();
2689 free(mSndBuf.data);
2692 int getScopeBuf(uint32 index, SndBuf *buf, bool& didChange);
2694 void SCScope::animate()
2696 bool didChange;
2697 /*int err =*/ getScopeBuf(mBufNum, &mSndBuf, didChange);
2698 if (didChange) refresh();
2701 void SCScope::draw0(CGContextRef cgc)
2703 float *data = mSndBuf.data;
2704 if (!data) return;
2706 int samples = mSndBuf.samples;
2707 SCRect bounds = getDrawBounds();
2708 // draw scope.
2709 CGRect rect = SCtoCGRect(bounds);
2710 int width = (int)bounds.width - 2;
2711 int channels = sc_min(mSndBuf.channels, kMaxScopeChannels);
2712 //post("channels %d\n", channels);
2713 float chanHeight = (bounds.height - 2.) / channels;
2714 float chanHeight2 = 0.5 * chanHeight;
2715 float yScale = mZoom.y * chanHeight2;
2717 for (int j=0; j<channels; ++j)
2719 CGContextSetRGBFillColor(cgc, mWaveColors[j].red, mWaveColors[j].green, mWaveColors[j].blue, mWaveColors[j].alpha);
2720 float fframe = mScroll.x;
2721 float hzoom = mZoom.x;
2722 int iframe = (int)floor(fframe);
2723 int isample = iframe * channels;
2724 float val = -data[isample + j];
2726 CGRect chanRect;
2727 chanRect.origin.x = rect.origin.x + 1.;
2728 chanRect.origin.y = rect.origin.y + 1. + chanHeight * j + chanHeight2;
2729 chanRect.size.width = width;
2730 chanRect.size.height = chanHeight;
2732 //post("width %d\n", width);
2733 for (int i = 0; i < width && isample < samples; i++)
2735 float ymin, ymax;
2736 ymin = ymax = val;
2737 float nextfframe = fframe + hzoom;
2738 int nextiframe = (int)floor(nextfframe);
2739 int nscan = nextiframe - iframe;
2740 for (int k=0; k<nscan && isample < samples; ++k)
2742 val = -data[isample + j];
2743 if (val < ymin) ymin = val;
2744 else if (val > ymax) ymax = val;
2745 isample += channels;
2747 iframe = nextiframe;
2748 fframe = nextfframe;
2750 CGRect wrect;
2751 wrect.origin.x = rect.origin.x + 1. + i;
2752 wrect.size.width = 1.;
2753 wrect.origin.y = chanRect.origin.y + ymin * yScale;
2754 wrect.size.height = (ymax - ymin) * yScale + 1.;
2756 //if (i == 64) post("%g %g %g %g %g\n", ymin, ymin, wrect.origin.x, wrect.origin.y, wrect.size.height);
2758 CGContextFillRect(cgc, wrect);
2763 void SCScope::draw1(CGContextRef cgc)
2765 float *data = mSndBuf.data;
2766 if (!data) return;
2768 int samples = mSndBuf.samples;
2769 SCRect bounds = getDrawBounds();
2771 // draw scope.
2772 CGRect rect = SCtoCGRect(bounds);
2773 int width = (int)bounds.width - 2;
2774 int channels = sc_min(mSndBuf.channels, kMaxScopeChannels);
2775 //post("channels %d\n", channels);
2776 float chanHeight = bounds.height - 2.;
2777 float chanHeight2 = 0.5 * chanHeight;
2778 float yScale = mZoom.y * chanHeight2;
2780 for (int j=0; j < channels; ++j)
2782 CGContextSetRGBFillColor(cgc, mWaveColors[j].red, mWaveColors[j].green, mWaveColors[j].blue, mWaveColors[j].alpha);
2783 float fframe = mScroll.x;
2784 float hzoom = mZoom.x;
2785 int iframe = (int)floor(fframe);
2786 int isample = iframe * channels;
2787 float val = -data[isample + j];
2789 CGRect chanRect;
2790 chanRect.origin.x = rect.origin.x + 1.;
2791 chanRect.origin.y = rect.origin.y + 1. + chanHeight2;
2792 chanRect.size.width = rect.size.width - 2.;
2793 chanRect.size.height = chanHeight;
2795 //post("width %d\n", width);
2796 for (int i = 0; i < width && isample < samples; i++)
2798 float ymin, ymax;
2799 ymin = ymax = val;
2800 float nextfframe = fframe + hzoom;
2801 int nextiframe = (int)floor(nextfframe);
2802 int nscan = nextiframe - iframe;
2803 for (int k=0; k<nscan; ++k)
2805 val = -data[isample + j];
2806 if (val < ymin) ymin = val;
2807 else if (val > ymax) ymax = val;
2808 isample += channels;
2810 iframe = nextiframe;
2811 fframe = nextfframe;
2813 CGRect wrect;
2814 wrect.origin.x = rect.origin.x + 1. + i;
2815 wrect.size.width = 1.;
2816 wrect.origin.y = chanRect.origin.y + ymin * yScale;
2817 wrect.size.height = (ymax - ymin) * yScale + 1.;
2819 //if (i == 64) post("%g %g %g %g %g\n", ymin, ymin, wrect.origin.x, wrect.origin.y, wrect.size.height);
2821 CGContextFillRect(cgc, wrect);
2826 void SCScope::draw2(CGContextRef cgc)
2828 float *data = mSndBuf.data;
2829 if (!data) return;
2831 int samples = mSndBuf.samples;
2832 SCRect bounds = getDrawBounds();
2834 // draw scope.
2835 CGRect rect = SCtoCGRect(bounds);
2836 int channels = sc_min(mSndBuf.channels, kMaxScopeChannels);
2837 float height = rect.size.height - 2.;
2838 float height2 = 0.5 * height;
2839 float width = mBounds.width - 2.;
2840 float width2 = 0.5 * width;
2841 float yScale = mZoom.y * height2;
2842 float xScale = mZoom.x * width2;
2843 float xoff = rect.origin.x + width2 + 1.;
2844 float yoff = rect.origin.y + height2 + 1.;
2847 for (int k=0, j=0; j<channels; k++, j+=2)
2849 CGContextSetRGBStrokeColor(cgc, mWaveColors[k].red, mWaveColors[k].green, mWaveColors[k].blue, mWaveColors[k].alpha);
2850 float x = xoff + data[j] * xScale;
2851 float y = yoff - data[j+1] * yScale;
2852 CGContextMoveToPoint(cgc, x, y);
2854 for (int i=channels; i<samples; i+=channels) {
2855 x = xoff + data[i+j] * xScale;
2856 y = yoff - data[i+j+1] * yScale;
2857 CGContextAddLineToPoint(cgc, x, y);
2859 CGContextStrokePath(cgc);
2865 void SCScope::draw(SCRect inDamage)
2867 bool didChange;
2868 int err = getScopeBuf(mBufNum, &mSndBuf, didChange);
2869 if (err) return;
2870 SCRect bounds = getDrawBounds();
2871 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
2872 CGContextSaveGState(cgc);
2873 CGRect rect = SCtoCGRect(bounds);
2874 if (mBackground) mBackground->draw(cgc, rect);
2876 if (mBackgroundImage)
2877 mBackgroundImage->draw(cgc, rect);
2879 QDDrawBevelRect(cgc, rect, 1, true);
2881 // draw grid.
2883 switch (mStyle) {
2884 case 0 : draw0(cgc); break;
2885 case 1 : draw1(cgc); break;
2886 case 2 : draw2(cgc); break;
2889 CGContextRestoreGState(cgc);
2893 void SCScope::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
2897 int SCScope::setProperty(PyrSymbol *symbol, PyrSlot *slot)
2899 int err;
2900 if (symbol == s_x) {
2901 double x;
2902 err = slotDoubleVal(slot, &x);
2903 if (err) return err;
2904 mScroll.x = x;
2905 return errNone;
2907 if (symbol == s_y) {
2908 double y;
2909 err = slotDoubleVal(slot, &y);
2910 if (err) return err;
2911 mScroll.y = y;
2912 return errNone;
2914 char *name = symbol->name;
2915 if (strcmp(name, "xZoom")==0) {
2916 double x;
2917 err = slotDoubleVal(slot, &x);
2918 if (err) return err;
2919 mZoom.x = x;
2920 mInvZoom.x = 1./x;
2921 return errNone;
2923 if (strcmp(name, "yZoom")==0) {
2924 double y;
2925 err = slotDoubleVal(slot, &y);
2926 if (err) return err;
2927 mZoom.y = y;
2928 mInvZoom.y = 1./y;
2929 refresh();
2930 return errNone;
2932 if (strcmp(name, "bufnum")==0) {
2933 err = slotIntVal(slot, &mBufNum);
2934 if (err) return err;
2935 refresh();
2936 return errNone;
2938 if (strcmp(name, "gridColor")==0) {
2939 err = slotColorVal(slot, &mGridColor);
2940 if (err) return err;
2941 refresh();
2942 return errNone;
2944 if (strcmp(name, "waveColors")==0) {
2945 if (!isKindOfSlot(slot, class_array)) return errWrongType;
2946 PyrSlot *slots = slotRawObject(slot)->slots;
2947 for (int i=0; i<slotRawObject(slot)->size; ++i)
2949 err = slotColorVal(slots+i, mWaveColors+i);
2950 if (err) return err;
2952 refresh();
2953 return errNone;
2955 if (strcmp(name, "style")==0) {
2956 err = slotIntVal(slot, &mStyle);
2957 if (err) return err;
2958 refresh();
2959 return errNone;
2962 return SCView::setProperty(symbol, slot);
2965 int SCScope::getProperty(PyrSymbol *symbol, PyrSlot *slot)
2967 if (symbol == s_x) {
2968 SetFloat(slot, mScroll.x);
2969 return errNone;
2971 if (symbol == s_y) {
2972 SetFloat(slot, mScroll.y);
2973 return errNone;
2976 char *name = symbol->name;
2977 if (strcmp(name, "xZoom")==0) {
2978 SetFloat(slot, mZoom.x);
2979 return errNone;
2981 if (strcmp(name, "yZoom")==0) {
2982 SetFloat(slot, mZoom.y);
2983 return errNone;
2985 if (strcmp(name, "bufnum")==0) {
2986 SetInt(slot, mBufNum);
2987 return errNone;
2989 if (strcmp(name, "gridColor")==0) {
2990 return setSlotColor(slot, &mGridColor);
2992 if (strcmp(name, "waveColors")==0) {
2993 if (!isKindOfSlot(slot, class_array)) return errWrongType;
2994 PyrSlot *slots = slotRawObject(slot)->slots;
2995 for (int i=0; i<slotRawObject(slot)->size; ++i)
2997 int err = setSlotColor(slots+i, mWaveColors+i);
2998 if (err) return err;
3000 refresh();
3001 return errNone;
3004 return SCView::getProperty(symbol, slot);
3007 ///////////////////////////////////////////////////////////////////////////////////////
3009 SCView* NewSC2DTabletSlider(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
3011 return new SC2DTabletSlider(inParent, inObj, inBounds);
3013 SC2DTabletSlider::SC2DTabletSlider(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
3014 : SC2DSlider(inParent, inObj, inBounds), mClipInBounds(1)
3018 int SC2DTabletSlider::setProperty(PyrSymbol *symbol, PyrSlot *slot)
3020 char *name = symbol->name;
3021 if (strcmp(name, "clipInBounds")==0) {
3022 slotIntVal(slot, &mClipInBounds);
3023 return errNone;
3025 return SC2DSlider::setProperty(symbol, slot);
3028 bool SC2DTabletSlider::setValue(double inX, double inY,bool )
3030 if(mClipInBounds) {
3031 inX = sc_clip(inX, 0., 1.);
3032 inY = sc_clip(inY, 0., 1.);
3034 if (mStepSize > 0.) {
3035 inX = floor(inX * mStepScale + 0.5) * mStepSize;
3036 inY = floor(inY * mStepScale + 0.5) * mStepSize;
3038 bool changed = inX != mX || inY != mY;
3039 if (changed) {
3040 mX = inX;
3041 mY = inY;
3042 refresh();
3044 return changed;
3047 void SC2DTabletSlider::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
3049 if (modifiers & NSCommandKeyMask) {
3050 beginDrag(where);
3051 } else {
3052 setValueFromPoint(where);
3053 TABLETTRACK(s_mouseDown,mX,mY)
3057 void SC2DTabletSlider::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
3059 if (! (modifiers & NSCommandKeyMask)) {
3060 setValueFromPoint(where);
3061 TABLETTRACK(s_doaction,mX,mY)
3065 void SC2DTabletSlider::mouseEndTrack(SCPoint where, int modifiers, NSEvent *theEvent)
3067 if (modifiers & NSCommandKeyMask) {
3068 receiveDrag();
3069 } else {
3070 setValueFromPoint(where);
3071 TABLETTRACK(s_mouseUp,mX,mY)
3074 void SC2DTabletSlider::mouseDownAction(SCPoint where, int modifiers, NSEvent *theEvent)
3077 void SC2DTabletSlider::mouseMoveAction(SCPoint where, int modifiers, NSEvent *theEvent)
3080 void SC2DTabletSlider::mouseUpAction(SCPoint where, int modifiers, NSEvent *theEvent)
3085 ///////////////////////////////////////////////////////////////////////////////////////////////
3088 SCView* NewSCButton(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
3090 return new SCButton(inParent, inObj, inBounds);
3093 SCButton::SCButton(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
3094 : SCView(inParent, inObj, inBounds), mNumStates(0), mStates(0), mPushed(false)
3096 setValue(0, false, 0);
3097 strcpy(mFontName, "Helvetica");
3098 mFontSize = 12.;
3101 SCButton::~SCButton()
3103 delete [] mStates;
3106 void SCButton::draw(SCRect inDamage)
3108 SCColor buttonColor;
3109 SCRect bounds = getDrawBounds();
3111 if (mStates) {
3112 SCButtonState *state = mStates + mValue;
3113 buttonColor = state->mButtonColor;
3114 //drawBevelRect(SCtoQDRect(mBounds), 2, mPushed ? 1 : 0, SCtoQDColor(buttonColor), 2);
3116 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
3117 CGContextSaveGState(cgc);
3119 CGRect cgrect = SCtoCGRect(bounds);
3120 if (buttonColor.alpha > 0.0) {
3121 CGContextSetRGBFillColor(cgc, buttonColor.red, buttonColor.green, buttonColor.blue, buttonColor.alpha);
3122 CGContextFillRect(cgc, cgrect);
3124 QDDrawBevelRect(cgc, cgrect, 2, mPushed);
3125 CGContextRestoreGState(cgc);
3127 SCRect innerBounds = bounds;
3128 int inset = 2;
3129 int pushOffset = mPushed ? 2 : 0;
3130 innerBounds.x += inset + pushOffset;
3131 innerBounds.y += inset + pushOffset;
3132 innerBounds.width -= inset * 2 + pushOffset;
3133 innerBounds.height -= inset * 2 + pushOffset;
3134 stringDrawCenteredInRect(state->mLabel, innerBounds, mFontName, mFontSize, state->mLabelColor);
3138 bool SCButton::setValue(int inValue, bool send, int modifiers)
3140 bool changed = inValue != mValue;
3141 PyrSlot args[1];
3142 if (inValue < 0 || inValue >= mNumStates) inValue = 0;
3143 if (inValue != mValue || mNumStates < 2) {
3144 mValue = inValue;
3145 refresh();
3146 SetInt(args, modifiers);
3147 if (send) sendMessage(s_doaction, 1, args, 0);
3149 return changed;
3153 void SCButton::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
3155 if (modifiers & NSCommandKeyMask) {
3156 beginDrag(where);
3157 } else {
3158 bool inside = hit(where);
3159 if (inside != mPushed) {
3160 mPushed = inside;
3161 refresh();
3166 void SCButton::mouseEndTrack(SCPoint where, int modifiers, NSEvent *theEvent)
3168 bool inside = hit(where);
3169 if (inside) setValue(mValue+1, true, modifiers);
3170 mPushed = false;
3173 int SCMakeButtonState(SCButton* view, SCButtonState *inState, PyrSlot *slot)
3175 int err;
3176 if (!isKindOfSlot(slot, class_array)) return errWrongType;
3177 PyrSlot *slots = slotRawObject(slot)->slots;
3179 inState->mLabel[0] = 0;
3180 inState->mLabelColor = SCMakeColor(0,0,0,1); // black
3181 inState->mButtonColor = SCMakeColor(0.7,0.7,0.7,1);
3183 if (slotRawObject(slot)->size < 1) return errNone;
3184 err = slotStrVal(slots+0, inState->mLabel, kLabelSize);
3185 if (err) return err;
3187 if (slotRawObject(slot)->size < 2) return errNone;
3188 err = slotColorVal(slots+1, &inState->mLabelColor);
3189 if (err) {
3190 inState->mLabelColor = SCMakeColor(0,0,0,1); // black
3193 if (slotRawObject(slot)->size < 3) return errNone;
3194 err = slotColorVal(slots+2, &inState->mButtonColor);
3195 if (err) {
3196 //inState->mButtonColor = view->getBackColor();
3198 return errNone;
3201 int SCButton::setProperty(PyrSymbol *symbol, PyrSlot *slot)
3203 int err;
3204 if (symbol == s_value) {
3205 int value;
3206 err = slotIntVal(slot, &value);
3207 if (err) return err;
3208 bool changed = setValue(value, false, 0);
3209 SetBool(slot, changed);
3210 return errNone;
3212 char *name = symbol->name;
3213 if (strcmp(name, "font")==0) {
3214 if (!isKindOfSlot(slot, getsym("SCFont")->u.classobj)) return errWrongType;
3215 PyrSlot *slots = slotRawObject(slot)->slots;
3217 float fontSize;
3218 err = slotFloatVal(slots+1, &fontSize);
3219 if (err) return err;
3221 err = slotStrVal(slots+0, mFontName, kFontNameSize);
3222 if (err) return err;
3224 mFontSize = fontSize;
3225 return errNone;
3227 if (strcmp(name, "states")==0) {
3228 if (!isKindOfSlot(slot, class_array)) return errWrongType;
3230 // wipe out old
3231 delete [] mStates;
3232 mStates = 0;
3233 mNumStates = 0;
3235 PyrObject *array = slotRawObject(slot);
3236 int numStates = array->size;
3237 SCButtonState* states = new SCButtonState[numStates];
3238 if (!states) return errFailed;
3239 for (int i=0; i<numStates; ++i) {
3240 SCButtonState *state = states + i;
3241 PyrSlot *slot = array->slots + i;
3242 err = SCMakeButtonState(this, state, slot);
3243 if (err) {
3244 delete [] states;
3245 return err;
3248 mStates = states;
3249 mNumStates = numStates;
3250 return errNone;
3253 return SCView::setProperty(symbol, slot);
3256 int SCButton::getProperty(PyrSymbol *symbol, PyrSlot *slot)
3258 if (symbol == s_value) {
3259 SetInt(slot, mValue);
3260 return errNone;
3262 //char *name = symbol->name;
3264 return SCView::getProperty(symbol, slot);
3267 bool SCButton::canReceiveDrag()
3269 PyrSlot result;
3270 sendMessage(s_canReceiveDrag, 0, 0, &result);
3271 return IsTrue(&result);
3274 void SCButton::receiveDrag()
3276 sendMessage(s_receiveDrag, 0, 0, 0);
3279 ///////////////////////////////////////////////////////////////////////////////////////////////
3281 @implementation SCNSMenu
3282 - (id) init
3284 if ([super init])
3286 current = 0;
3289 return self;
3292 - (void) selectedItem:(id)item
3294 NSMenuItem *s = (NSMenuItem *) item;
3295 current = [s tag];
3298 - (int) current
3300 return current;
3302 @end
3304 SCView* NewSCPopUpMenu(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
3306 return new SCPopUpMenu(inParent, inObj, inBounds);
3309 SCPopUpMenu::SCPopUpMenu(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
3310 : SCView(inParent, inObj, inBounds), mValue(0), mMenu(0)
3312 mStringColor = SCMakeColor(0,0,0,1);
3313 //mArrowColor = SCMakeColor(0,0,0,0);
3314 strcpy(mFontName, "Helvetica");
3315 mFontSize = 12.;
3318 SCPopUpMenu::~SCPopUpMenu()
3320 if (mMenu) [mMenu release];
3323 void SCPopUpMenu::draw(SCRect inDamage)
3325 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
3326 CGContextSaveGState(cgc);
3327 SCRect dbounds = getDrawBounds();
3329 CGRect rect = SCtoCGRect(dbounds);
3330 if (mBackground) mBackground->draw(cgc, rect);
3332 if (mBackgroundImage)
3333 mBackgroundImage->draw(cgc, rect);
3335 CGRect bounds = SCtoCGRect(dbounds);
3336 QDDrawBevelRect(cgc, bounds, 1, false);
3338 CGContextSetRGBFillColor(cgc, mStringColor.red, mStringColor.green, mStringColor.blue, mStringColor.alpha);
3340 int vc = (int)(bounds.origin.y + bounds.size.height/2);
3341 int hc = (int)(bounds.origin.x + 7);
3342 CGContextMoveToPoint(cgc, hc-3, vc-3);
3344 CGContextAddLineToPoint(cgc, hc+3, vc-3);
3345 CGContextAddLineToPoint(cgc, hc, vc+3);
3346 CGContextAddLineToPoint(cgc, hc-3, vc-3);
3347 CGContextFillPath(cgc);
3349 CGContextRestoreGState(cgc);
3351 if (mMenu) {
3352 int numberOfItems = [mMenu numberOfItems];
3353 if (numberOfItems) {
3354 char *cstring = NULL;
3355 NSMenuItem *item = [mMenu itemAtIndex:mValue];
3356 if (item)
3358 NSString *title = [item title];
3359 if (title)
3361 int length = [title lengthOfBytesUsingEncoding:NSMacOSRomanStringEncoding];
3362 cstring = (char *) malloc(length+1);
3363 [title getCString:cstring maxLength:length+1 encoding:NSMacOSRomanStringEncoding];
3366 SCRect innerBounds = dbounds;
3367 int inset = 2;
3368 innerBounds.x += inset + 10;
3369 innerBounds.y += inset;
3370 innerBounds.width -= inset * 2 + 10;
3371 innerBounds.height -= inset * 2;
3372 stringDrawCenteredInRect((const char *) (cstring ? cstring : "[text not retrieved]"), innerBounds, mFontName, mFontSize, mStringColor);
3373 if (cstring) free(cstring);
3378 bool SCPopUpMenu::setValue(int inValue, bool send)
3380 if (!mMenu) return false;
3382 bool changed = inValue != mValue;
3383 int numberOfItems = [mMenu numberOfItems];
3384 inValue = sc_mod(inValue, numberOfItems);
3385 if (inValue != mValue || numberOfItems < 2) {
3386 mValue = inValue;
3387 refresh();
3388 if (send) sendMessage(s_doaction, 0, 0, 0);
3390 return changed;
3394 void SCPopUpMenu::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
3396 if (modifiers & NSCommandKeyMask) {
3397 beginDrag(where);
3398 } else {
3399 if (!mMenu) return;
3400 SCRect bounds = getDrawBounds();
3402 [(SCGraphView*)mTop->GetNSView() startMenuTracking: this];
3404 int numberOfItems = [mMenu numberOfItems];
3405 for (int i=0; i<numberOfItems; ++i) {
3406 [[mMenu itemAtIndex:i] setState:mValue==i];
3409 NSPoint p = NSMakePoint(bounds.x, bounds.y);
3410 NSView *view = mTop->GetNSView();
3411 [NSMenu popUpContextMenu:mMenu withEvent:theEvent forView:view];
3412 setValue([mMenu current], true);
3416 int SCPopUpMenu::setProperty(PyrSymbol *symbol, PyrSlot *slot)
3418 int err;
3419 if (symbol == s_value) {
3420 int value;
3421 err = slotIntVal(slot, &value);
3422 if (err) return err;
3423 bool changed = setValue(value, false);
3424 SetBool(slot, changed);
3425 return errNone;
3427 char *name = symbol->name;
3428 if (strcmp(name, "font")==0) {
3429 if (!isKindOfSlot(slot, getsym("SCFont")->u.classobj)) return errWrongType;
3430 PyrSlot *slots = slotRawObject(slot)->slots;
3432 float fontSize;
3433 err = slotFloatVal(slots+1, &fontSize);
3434 if (err) return err;
3436 err = slotStrVal(slots+0, mFontName, kFontNameSize);
3437 if (err) return err;
3439 mFontSize = fontSize;
3440 return errNone;
3442 if (strcmp(name, "items")==0) {
3443 if (!isKindOfSlot(slot, class_array)) return errWrongType;
3445 // wipe out old
3446 if (mMenu) [mMenu release];
3448 PyrObject *array = slotRawObject(slot);
3449 int numItems = array->size;
3451 mMenu = [[SCNSMenu alloc] init];
3453 for (int i=0; i<numItems; ++i) {
3454 PyrSlot *slot = array->slots + i;
3456 char title[256];
3457 int err = slotStrVal(slot, title, 255);
3458 if (err) return err;
3460 NSString *t = [NSString stringWithCString:(const char *)title encoding:NSMacOSRomanStringEncoding];
3461 NSMenuItem *item = [mMenu addItemWithTitle:t action:@selector(selectedItem:) keyEquivalent:@""];
3462 [item setTarget:mMenu];
3463 [item setTag:i];
3465 refresh();
3466 return errNone;
3468 if (strcmp(name, "stringColor")==0) {
3469 err = slotColorVal(slot, &mStringColor);
3470 if (err) return err;
3471 refresh();
3472 return errNone;
3475 return SCView::setProperty(symbol, slot);
3478 int SCPopUpMenu::getProperty(PyrSymbol *symbol, PyrSlot *slot)
3480 if (symbol == s_value) {
3481 SetInt(slot, mValue);
3482 return errNone;
3484 char* name = symbol->name;
3485 if (strcmp(name, "stringColor")==0) {
3486 return setSlotColor(slot, &mStringColor);
3489 return SCView::getProperty(symbol, slot);
3493 bool SCPopUpMenu::canReceiveDrag()
3495 PyrSlot result;
3496 sendMessage(s_canReceiveDrag, 0, 0, &result);
3497 return IsTrue(&result);
3500 void SCPopUpMenu::receiveDrag()
3502 sendMessage(s_receiveDrag, 0, 0, 0);
3505 /////////////////////////////////////////////////////////////////
3506 //SCMultiSliderView by jan trutzschler jan.21.03 //jan.23.03 changed draw added more prop.//jan.28.03 debug
3507 //jan.29.03 value 1.0 up // draw . //feb.03.02 ..
3509 int allocSlotDoubleArrayVal(PyrSlot *slot, double **arr);
3510 int allocSlotDoubleArrayVal(PyrSlot *slot, double **arr)
3512 int len;
3513 int err;
3514 if (*arr) {
3515 delete [] *arr;
3516 *arr = 0;
3518 if (isKindOfSlot(slot, class_array)) {
3519 len = slotRawObject(slot)->size;
3520 *arr = new double[len];
3521 // memcpy(*arr, slotRawObject(slot)->slots, len * sizeof(double));
3522 for(int i =0; i<len; i++){
3523 err = slotDoubleVal(slotRawObject(slot)->slots+i, *arr+i);
3524 if (err) *(*arr+i) = 0.0;
3526 return errNone;
3528 return errWrongType;
3530 SCView* NewSCMultiSliderView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
3532 return new SCMultiSliderView(inParent, inObj, inBounds);
3535 SCMultiSliderView::SCMultiSliderView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
3536 : SCView(inParent, inObj, inBounds), mThumbSize(12.), mStepSize(0.),
3537 mStepScale(0.), mKnob(0), mXOffset(1)
3539 mTabSize = (int) (inBounds.width / mThumbSize);
3540 mCurrentIndex = mStartIndex = 0;
3541 mThumbSizeY = mThumbSize;
3542 mSelectionSize = 1;
3543 mCurrentY = 0.0;
3544 mCurrentX = 0.0;
3545 mYValues = new double [mTabSize];
3546 memset(mYValues, 0, mTabSize * sizeof(double));
3547 mReadOnly = mShowIndex = false;
3548 mFillColor = SCMakeColor(0,0,0,1); // black
3549 mStrokeColor = SCMakeColor(0,0,0,1); // black
3550 mIsFilled = mDrawLinesActive = false;
3551 mDrawRectsActive = true;
3552 mSecYValues = NULL;
3553 mIsHorizontal = true;
3554 mElasticMode = 0;
3555 //setVisibleSize();
3557 SCMultiSliderView::~SCMultiSliderView()
3559 delete mYValues;
3560 if(mSecYValues) delete mSecYValues;
3564 void SCMultiSliderView::draw(SCRect inDamage)
3566 SCRect bounds = getDrawBounds();
3568 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
3569 CGContextSaveGState(cgc);
3570 CGRect rect = SCtoCGRect(bounds);
3571 CGContextClipToRect(cgc, rect);
3572 double * vals = mYValues;
3573 int xpixels = mTabSize;
3574 int xstart = mStartIndex;
3575 if(mElasticMode) {
3576 if(mIsHorizontal) mElasticIndexStep = (bounds.width - 2)/(mTabSize-mStartIndex);
3577 else mElasticIndexStep = (bounds.height - 2)/(mTabSize-mStartIndex);
3578 } else mElasticIndexStep = 0.0;
3579 double step = mElasticIndexStep;
3581 if (mBackground) mBackground->draw(cgc, rect);
3583 if (mBackgroundImage)
3584 mBackgroundImage->draw(cgc, rect);
3586 QDDrawBevelRect(cgc, rect, 1, true);
3588 CGContextSetRGBFillColor(cgc, mFillColor.red, mFillColor.green, mFillColor.blue, mFillColor.alpha);
3589 CGContextSetRGBStrokeColor(cgc, mStrokeColor.red, mStrokeColor.green, mStrokeColor.blue, mStrokeColor.alpha);
3591 CGRect drawRect;
3592 float yval = 0;
3594 //draw dots for multislider
3595 if(mDrawRectsActive)
3597 int j = 0;
3598 for(int i = xstart; i < xpixels; i++, j++){
3599 drawRect = SCtoCGRect(calcThumbRect(j, vals[i], step));
3600 CGContextFillRect (cgc, drawRect);
3601 if (mThumbSize > 1.) CGContextStrokeRect(cgc,drawRect);
3602 if(mSecYValues){ //draw the upper part of a wave view
3603 drawRect = SCtoCGRect(calcThumbRect(j, mSecYValues[i], step));
3604 CGContextFillRect (cgc, drawRect);
3605 if (mThumbSize > 1.) CGContextStrokeRect(cgc,drawRect);
3609 //draw lines
3610 if (mDrawLinesActive) {
3611 float xadd, gcx, gcy;
3612 if(mElasticMode){
3613 xadd = (step > mThumbSize) ? (mThumbSize * 0.5) : (step>1.0) ? (step* 0.5) : 1;
3614 }else{
3615 if(mThumbSize > 1) xadd = mThumbSize * 0.5;
3616 else xadd = 0;
3618 int j = 0;
3619 for(int i = xstart; i < xpixels; i++, j++){
3620 yval = vals[i];
3621 drawRect = SCtoCGRect(calcThumbRect(j, yval, step));
3622 gcx = drawRect.origin.x + xadd;
3623 gcy = drawRect.origin.y;
3624 if( i == xstart)
3625 CGContextMoveToPoint(cgc, gcx, gcy);
3626 else
3627 CGContextAddLineToPoint(cgc, gcx, gcy);
3629 //these are fixed values: used for the max of soundfiles, need to go backwards to fill
3630 if (mSecYValues != NULL) {
3631 int j = xpixels - 1 - xstart;
3632 for(int i = xpixels - 1; i >= xstart; i--, j--){
3633 yval = mSecYValues[i];
3634 drawRect = SCtoCGRect(calcThumbRect(j, yval, step));
3635 gcx = drawRect.origin.x + xadd;
3636 gcy = drawRect.origin.y + xadd;
3637 CGContextAddLineToPoint(cgc, gcx, gcy);
3640 if(mIsFilled) CGContextEOFillPath(cgc);
3641 else CGContextStrokePath(cgc);
3643 //draw selection:
3644 if(mShowIndex) {
3645 if(mCurrentIndex + mSelectionSize >= xstart){
3646 int currentI, selsize;
3647 if(mCurrentIndex < xstart) {
3648 currentI = 0;
3649 selsize = sc_clip(mSelectionSize, xstart, mTabSize);
3650 } else {
3651 currentI = mCurrentIndex - xstart;
3652 selsize = mSelectionSize;
3654 if(mIsHorizontal){
3655 if(mElasticMode)
3656 drawRect = CGRectMake(bounds.x + 1 + (currentI * mElasticIndexStep),
3657 bounds.y + 1,
3658 (selsize * mElasticIndexStep),
3659 bounds.height);
3660 else
3661 drawRect = CGRectMake(bounds.x + 1 + (currentI * ( mXOffset + mThumbSize)),
3662 bounds.y + 1,
3663 (selsize * ( mXOffset + mThumbSize)) - mXOffset,
3664 bounds.height);
3665 } else {
3666 if(mElasticMode)
3667 drawRect = CGRectMake( bounds.x + 1,
3668 bounds.y + 1 + (currentI * mElasticIndexStep),
3669 bounds.width,
3670 (selsize * mElasticIndexStep));
3671 else
3672 drawRect = CGRectMake( bounds.x + 1,
3673 bounds.y + 1 + (currentI * ( mXOffset + mThumbSize)),
3674 bounds.width,
3675 (selsize * ( mXOffset + mThumbSize)) - mXOffset);
3677 CGContextSetRGBFillColor(cgc, mFillColor.red, mFillColor.green, mFillColor.blue, 0.4);
3678 CGContextFillRect (cgc, drawRect);
3681 CGContextRestoreGState(cgc);
3685 bool SCMultiSliderView::setValue(int xIn, double yIn, bool send)
3687 bool changed;
3688 yIn = sc_clip(yIn, 0., 1.);
3689 xIn = sc_clip(xIn, 0, mTabSize - 1);
3691 if (mStepSize > 0.) {
3692 yIn = floor(yIn * mStepScale + 0.5) * mStepSize;
3694 if(!mReadOnly){
3695 mCurrentIndex = xIn;
3696 changed = mYValues[xIn] != yIn;
3697 if (changed) {
3698 mYValues[xIn] = yIn;
3699 mCurrentY = yIn;
3700 if (send) sendMessage(s_doaction, 0, 0, 0);
3701 // post("new val: %f x: %d \n", (float) yIn, xIn);
3702 refresh();
3704 } else {
3705 int xindx, lastindx, maxSize;
3706 lastindx = mCurrentIndex;
3707 changed = false;
3708 xindx = (int) xIn ;
3709 xindx = sc_clip(xindx, 0, mTabSize - 1);
3710 mCurrentIndex = xindx;
3711 mCurrentY = mYValues[mCurrentIndex];
3712 if(mCurrentIndex > (lastindx + mSelectionSize)) mSelectionSize = 1;
3713 maxSize = mTabSize - mCurrentIndex;
3714 if(mSelectionSize > maxSize) mSelectionSize = maxSize;
3716 if (send) sendMessage(s_doaction, 0, 0, 0);
3717 //post("readOnly: x: %d \n", mCurrentIndex);
3718 if(mShowIndex) refresh();
3720 return changed;
3724 int SCMultiSliderView::indexFromPoint(SCPoint where)
3726 SCRect bounds = getDrawBounds();
3728 if(mIsHorizontal){
3729 if(mElasticMode)
3730 return (int) ((where.x - bounds.x -1)/mElasticIndexStep);
3731 else
3732 return (int) ((where.x - bounds.x -1)/(mThumbSize + mXOffset)) + mStartIndex;
3733 } else {
3734 return (int) ((where.y - bounds.y -1)/(mThumbSize + mXOffset)) + mStartIndex;
3738 double SCMultiSliderView::valueFromPoint(SCPoint where)
3740 SCRect bounds = getDrawBounds();
3742 if(mIsHorizontal){
3743 return 1.0 - (where.y - bounds.y - 1 - mThumbSizeY/2) / (bounds.height - mThumbSizeY - 2);
3744 } else {
3745 return (where.x - bounds.x - 1 - mThumbSizeY/2) / (bounds.width - mThumbSizeY - 2);
3749 void SCMultiSliderView::setValueFromPoint(SCPoint where)
3751 double y = valueFromPoint(where);
3752 int xIndx = indexFromPoint(where);
3753 setValue(xIndx, y, true);
3756 SCRect SCMultiSliderView::calcThumbRect(int indexIn, double valIn, double step)
3758 double x,y, thumbx, thumby;
3759 float xoffset = mXOffset;
3760 SCRect bounds = getDrawBounds();
3762 //post("step is: %f ", step);
3764 if(mIsHorizontal){
3765 thumby = mThumbSizeY;
3766 if(mElasticMode){
3767 thumbx = (step > mThumbSize) ? mThumbSize : (step>1.0) ? step : 1;
3768 x = indexIn * step ;
3769 }else{
3770 x = (double) indexIn * ( xoffset + mThumbSize);
3771 thumbx = mThumbSize;
3773 y = valIn * (bounds.height - thumby - 2);
3774 y = bounds.y + bounds.height - y - 1 - thumby;
3775 x = bounds.x + x + 1;
3776 if(mIsFilled) thumby = bounds.height;
3777 } else {
3778 thumbx = mThumbSizeY;
3779 if(mElasticMode){
3780 thumbx = (step > mThumbSize) ? mThumbSize : step;
3781 y = indexIn * step ;
3782 }else{
3783 y = (double) indexIn * ( xoffset + mThumbSize);
3785 x = valIn * (bounds.width - thumbx - 2);
3786 //x = bounds.x + bounds.width - x - 1 - thumby;
3787 x = bounds.x + x + 1;
3788 y = bounds.y + y + 1;
3789 if(mIsFilled){
3790 thumbx += x - bounds.x;
3791 x = bounds.x;
3793 thumby = mThumbSize;
3795 return SCMakeRect( x, y, thumbx, thumby);
3798 void SCMultiSliderView::setSelection(SCPoint where)
3800 int wx;
3801 int visiIn = mCurrentIndex - mStartIndex;
3802 int maxSize = mTabSize - mCurrentIndex;
3803 wx = indexFromPoint(where);
3804 if(wx > visiIn) mSelectionSize = (int) wx - visiIn;
3805 else {
3806 setValueFromPoint(where);
3807 mSelectionSize = (int) mCurrentIndex - wx;
3809 if(mSelectionSize > maxSize) mSelectionSize = maxSize;
3810 refresh();
3813 void SCMultiSliderView::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
3815 mPrevPoint = where;
3816 mouseTrack(where, modifiers,theEvent);
3818 void SCMultiSliderView::mouseEndTrack(SCPoint where, int modifiers, NSEvent *theEvent){
3819 // sendMessage(getsym("mouseEndTrack"), 0, 0, 0);
3820 mouseTrack(where, modifiers,theEvent);
3822 void SCMultiSliderView::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
3824 if (modifiers & NSCommandKeyMask) {
3825 beginDrag(where);
3826 } else if (modifiers & NSShiftKeyMask) {
3827 if(mShowIndex) {
3828 setSelection(where);
3829 sendMessage(getsym("doAction"), 0, 0, 0);
3831 } else if (modifiers & NSControlKeyMask) {
3832 if(mIsHorizontal) mCurrentX = where.x; //absolute y mouse position
3833 else mCurrentX = where.y;
3834 sendMessage(getsym("doMetaAction"), 0, 0, 0);
3835 } else {
3836 int prevIndex = indexFromPoint(mPrevPoint);
3837 int index = indexFromPoint(where);
3838 double prevValue = valueFromPoint(mPrevPoint);
3839 double value = valueFromPoint(where);
3840 if (prevIndex == index) {
3841 setValue(index, value, true);
3842 } else if (prevIndex < index) {
3843 double val = prevValue;
3844 double delta = (value - prevValue) / (index - prevIndex);
3845 for (int i=prevIndex; i<=index; ++i) {
3846 setValue(i, val, true);
3847 val += delta;
3849 } else {
3850 double val = value;
3851 double delta = (prevValue - value) / (prevIndex - index);
3852 for (int i=index; i<=prevIndex; ++i) {
3853 setValue(i, val, true);
3854 val += delta;
3857 mPrevPoint = where;
3861 int SCMultiSliderView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
3863 int err;
3864 char *name = symbol->name;
3865 if (strcmp(name, "step")==0) {
3866 err = slotDoubleVal(slot, &mStepSize);
3867 if (!err) {
3868 mStepScale = 1. / mStepSize;
3869 bool changed = false;
3870 bool changedout = false;
3871 for(int i=0; i< mTabSize; ++i){
3872 changed = setValue(i, mYValues[i], false);
3873 if(changed) changedout = changed;
3875 SetBool(slot, changedout);
3877 return errNone;
3879 if (strcmp(name, "thumbSize")==0) {
3880 err = slotFloatVal(slot, &mThumbSize);
3881 //setVisibleSize();
3882 refresh();
3883 return errNone;
3885 if (strcmp(name, "thumbWidth")==0) {
3886 err = slotFloatVal(slot, &mThumbSizeY);
3887 //setVisibleSize();
3888 refresh();
3889 return errNone;
3891 if (strcmp(name, "indexThumbSize")==0) {
3892 err = slotFloatVal(slot, &mThumbSize);
3893 //setVisibleSize();
3894 refresh();
3895 return errNone;
3897 if (strcmp(name, "valueThumbSize")==0) {
3898 err = slotFloatVal(slot, &mThumbSizeY);
3899 //setVisibleSize();
3900 refresh();
3901 return errNone;
3903 if (strcmp(name, "xOffset")==0) {
3904 err = slotFloatVal(slot, &mXOffset);
3905 if(mXOffset < 1.0) mXOffset = 0.0; //mResamp = (int) 1.0 / mXOffset;
3906 //setVisibleSize();
3907 refresh();
3908 return errNone;
3910 if (strcmp(name, "fillColor")==0) {
3911 err = slotColorVal(slot, &mFillColor);
3912 refresh();
3913 return errNone;
3915 if (strcmp(name, "strokeColor")==0) {
3916 err = slotColorVal(slot, &mStrokeColor);
3917 refresh();
3918 return errNone;
3920 if (strcmp(name, "startIndex")==0) {
3921 err = slotIntVal(slot, &mStartIndex);
3922 //setVisibleSize();
3923 refresh();
3924 return errNone;
3926 if (strcmp(name, "readOnly")==0) {
3927 mReadOnly = IsTrue(slot);
3928 refresh();
3929 return errNone;
3931 if (strcmp(name, "isHorizontal")==0) {
3932 mIsHorizontal = IsTrue(slot);
3933 refresh();
3934 return errNone;
3936 if (strcmp(name, "drawLines")==0) {
3937 mDrawLinesActive = IsTrue(slot);
3938 refresh();
3939 return errNone;
3941 if (strcmp(name, "drawRects")==0) {
3942 mDrawRectsActive = IsTrue(slot);
3943 refresh();
3944 return errNone;
3946 if (strcmp(name, "isFilled")==0) {
3947 mIsFilled = IsTrue(slot);
3948 refresh();
3949 return errNone;
3951 if (strcmp(name, "showIndex")==0) {
3952 mShowIndex = IsTrue(slot);
3953 refresh();
3954 return errNone;
3956 if (symbol == s_x) {
3957 slotIntVal(slot, &mCurrentIndex);
3958 mCurrentIndex = sc_clip(mCurrentIndex, 0, mTabSize - 1);
3959 int maxSize = mTabSize - mCurrentIndex;
3960 if(mSelectionSize > maxSize) mSelectionSize = maxSize;
3961 refresh();
3962 return errNone;
3964 if (symbol == s_y) {
3965 slotDoubleVal(slot, &mCurrentY);
3966 mCurrentY = sc_clip(mCurrentY, 0.0, 1.0);
3967 mYValues[mCurrentIndex] = mCurrentY;
3968 refresh();
3969 return errNone;
3971 if (symbol == s_value) {
3972 if (!isKindOfSlot(slot, class_array)) return errWrongType;
3973 if(slotRawObject(slot)->size != mTabSize) {
3974 err = allocSlotDoubleArrayVal(slot, &mYValues);
3975 mTabSize = slotRawObject(slot)->size;
3976 SetBool(slot, true);
3978 } else {
3979 int len = slotRawObject(slot)->size;
3980 double val;
3981 bool changed = false;
3982 // memcpy(mYValues, slotRawObject(slot)->slots, len * sizeof(double));
3983 for(int i =0; i<len; i++){
3984 err = slotDoubleVal(slotRawObject(slot)->slots+i, &val);
3985 if(mYValues[i] != val) changed = true;
3986 if (err) mYValues[i] = 0.0; else mYValues[i] = val;
3988 SetBool(slot, changed);
3991 //setVisibleSize();
3992 refresh();
3993 return errNone;
3995 if (strcmp(name, "referenceValues")==0) {
3996 if (!isKindOfSlot(slot, class_array)) return errWrongType;
3997 if(slotRawObject(slot)->size == mTabSize && mSecYValues != NULL) {
3998 err = allocSlotDoubleArrayVal(slot, &mSecYValues);
3999 } else {
4000 err = allocSlotDoubleArrayVal(slot, &mSecYValues);
4002 refresh();
4003 return errNone;
4005 if (strcmp(name, "selectionSize")==0) {
4006 slotIntVal(slot, &mSelectionSize);
4007 refresh();
4008 return errNone;
4011 if (strcmp(name, "elasticResizeMode")==0) {
4012 slotIntVal(slot, &mElasticMode);
4013 refresh();
4014 return errNone;
4019 return SCView::setProperty(symbol, slot);
4022 int SCMultiSliderView::getProperty(PyrSymbol *symbol, PyrSlot *slot)
4025 char *name = symbol->name;
4026 if (strcmp(name, "step")==0) {
4027 SetFloat(slot, mStepSize);
4028 return errNone;
4030 if (symbol == s_x) {
4031 SetInt(slot, mCurrentIndex);
4032 return errNone;
4034 if (symbol == s_y) {
4035 SetFloat(slot, mCurrentY);
4036 return errNone;
4038 if (symbol == s_value) {
4039 int len;
4040 if (isKindOfSlot(slot, class_array)) {
4041 len = slotRawObject(slot)->size;
4042 if(len > mTabSize) return errWrongType;
4043 memcpy(slotRawObject(slot)->slots, mYValues, len * sizeof(double));
4045 return errNone;
4047 if (strcmp(name, "referenceValues")==0) {
4048 int len;
4049 if (isKindOfSlot(slot, class_array)) {
4050 len = slotRawObject(slot)->size;
4051 if(len > mTabSize) return errWrongType;
4052 if (mSecYValues != NULL)
4053 memcpy(slotRawObject(slot)->slots, mSecYValues, len * sizeof(double));
4054 else SetNil(slot);
4056 return errNone;
4058 if (strcmp(name, "selectionSize")==0) {
4059 SetInt(slot, mSelectionSize);
4060 return errNone;
4062 if (strcmp(name, "absoluteX")==0) {
4063 SetInt(slot, (int) mCurrentX);
4064 return errNone;
4068 return SCView::getProperty(symbol, slot);
4071 bool SCMultiSliderView::canReceiveDrag()
4073 PyrSlot result;
4074 sendMessage(s_canReceiveDrag, 0, 0, &result);
4075 return IsTrue(&result);
4078 void SCMultiSliderView::receiveDrag()
4080 sendMessage(s_receiveDrag, 0, 0, 0);
4082 //////////////////////////////////////////////////////////////////////////////////
4085 SCView* NewSCUserView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
4087 return new SCUserView(inParent, inObj, inBounds);
4090 SCUserView::SCUserView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
4091 : SCView(inParent, inObj, inBounds)
4093 mClearOnRefresh = true;
4094 mDrawingEnabled = true;
4095 mNSImageForLayering = nil;
4096 for(char i = 0; i<kFrameLastTimes; i++) {
4097 mFrameLastTimes[i] = (float)i;
4099 mFrameRate = 0.f;
4100 mFrameCounter = 0;
4103 SCUserView::~SCUserView()
4105 if( mNSImageForLayering )
4106 [ mNSImageForLayering release ];
4110 extern NSBitmapImageRep* CreateBitmapContextRGBA(const int width, const int height);
4111 extern NSBitmapImageRep* BitmapContextRGBAWithImage(const int width, const int height, id image);
4113 void SCUserView::draw(SCRect inDamage)
4116 #define USE_BITMAPREP 0
4118 NSGraphicsContext *lGCtx = NULL;
4119 CGContextRef mainGC = NULL;
4120 SCRect bounds = getDrawBounds();
4121 CGRect cgBounds = SCtoCGRect( bounds );
4123 SCView::draw(bounds); // draw background
4125 lGCtx = [NSGraphicsContext currentContext];
4126 mainGC = (CGContextRef)[lGCtx graphicsPort];
4128 if( !mDrawingEnabled || !mainGC )
4129 return;
4131 if( bounds.width <= 0 || bounds.height <= 0)
4132 return;
4134 mFrameRate = 0.f;
4135 for( uint8_t i = 1; i < kFrameLastTimes; ++i )
4137 mFrameRate = mFrameRate + ( mFrameLastTimes[i] - mFrameLastTimes[i-1] );
4138 mFrameLastTimes[i-1] = mFrameLastTimes[i];
4141 mFrameRate = 1.f / ( mFrameRate / (kFrameLastTimes-1) );
4142 ++mFrameCounter;
4144 struct timeval tv;
4145 gettimeofday(&tv, 0);
4146 mFrameLastTimes[kFrameLastTimes-1] = (double)tv.tv_sec + 1.0e-6 * (double)tv.tv_usec;
4148 CGContextSaveGState( mainGC );
4149 if( !mClearOnRefresh )
4152 !mNSImageForLayering ||
4153 [ mNSImageForLayering size ].width != bounds.width ||
4154 [ mNSImageForLayering size ].height != bounds.height
4157 if( mNSImageForLayering )
4158 [ mNSImageForLayering release ];
4160 mNSImageForLayering = [[NSImage alloc]initWithSize: *(NSSize*)&cgBounds.size];
4161 [mNSImageForLayering setFlipped:YES]; // important to provide compatibility with SC flipped view
4162 if( !mNSImageForLayering )
4164 post( "Error: Failed creating valid NSBitmapImageRep for SCUserView" );
4165 return;
4168 #if USE_BITMAPREP
4169 mImageRep = CreateBitmapContextRGBA((int)bounds.width, (int)bounds.height);
4170 if( !mImageRep )
4172 post( "Error: Failed creating valid NSBitmapImageRep for SCUserView" );
4173 return;
4175 [mNSImageForLayering addRepresentation: mImageRep];
4176 [mImageRep release];
4177 #else
4178 [mNSImageForLayering setCacheMode: NSImageCacheBySize]; // should be also bitmap based
4179 #endif
4181 [mNSImageForLayering lockFocus];
4184 else
4186 CGContextClipToRect( mainGC, cgBounds );
4187 CGContextTranslateCTM( mainGC, cgBounds.origin.x, cgBounds.origin.y );
4190 sendMessage(s_draw, 0, 0, 0);
4192 if( !mClearOnRefresh )
4194 [mNSImageForLayering unlockFocus];
4195 NSAffineTransform* trs = [NSAffineTransform transform];
4196 [trs translateXBy:cgBounds.origin.x yBy:cgBounds.origin.y + cgBounds.size.height];
4197 [trs scaleXBy:1.0 yBy:-1.0];
4198 [trs concat];
4199 [mNSImageForLayering drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.f];
4201 CGContextRestoreGState( mainGC );
4204 void SCUserView::clearDrawing()
4206 if( mClearOnRefresh )
4207 return;
4209 //SCRect bounds = getDrawBounds();
4210 //CGContextClearRect ( mNSImageForLayering , CGRectMake( 0, 0, bounds.width, bounds.height));
4211 [ mNSImageForLayering lockFocus ];
4212 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext]graphicsPort];
4213 CGContextClearRect( cgc, CGRectMake( 0.f, 0.f, [mNSImageForLayering size].width, [mNSImageForLayering size].height ) );
4214 [ mNSImageForLayering unlockFocus ];
4218 void SCUserView::mouseAction(PyrSymbol *method, SCPoint where, int modifiers)
4220 // SCRect bounds = getDrawBounds();
4222 // mRealtiveMousePoint.x = where.x - bounds.x;
4223 // mRealtiveMousePoint.y = where.y - bounds.y;
4225 // PyrSlot args[3];
4226 // SetFloat(args+0, where.x);
4227 // SetFloat(args+1, where.y);
4228 // SetInt(args+2, modifiers);
4229 // sendMessage(method, 3, args, 0);
4232 void SCUserView::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
4234 SCRect bounds = getDrawBounds();
4236 mRealtiveMousePoint.x = where.x - bounds.x;
4237 mRealtiveMousePoint.y = where.y - bounds.y;
4238 // mouseAction(getsym("mouseBeginTrack"), where, modifiers);
4241 void SCUserView::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
4243 // SCRect bounds = getDrawBounds();
4244 // mRealtiveMousePoint.x = where.x - bounds.x;
4245 // mRealtiveMousePoint.y = where.y - bounds.y;
4246 // if (modifiers & NSCommandKeyMask) {
4247 // beginDrag(where);
4248 // }
4250 // else {
4251 // mouseAction(getsym("mouseTrack"), where, modifiers);
4252 // }
4255 void SCUserView::mouseDownAction(SCPoint where, int modifiers, NSEvent *theEvent)
4257 SCRect bounds = getDrawBounds();
4259 if(parent()->isTopContainer()) {
4260 mRealtiveMousePoint.x = where.x - bounds.x;
4261 mRealtiveMousePoint.y = where.y - bounds.y;
4262 }else{
4263 mRealtiveMousePoint.x = where.x - mBounds.x;
4264 mRealtiveMousePoint.y = where.y - mBounds.y;
4267 SCView::mouseDownAction(where, modifiers, theEvent);
4269 if (modifiers & NSCommandKeyMask) {
4270 beginDrag(where);
4274 void SCUserView::mouseMoveAction(SCPoint where, int modifiers, NSEvent *theEvent)
4276 SCRect bounds = getDrawBounds();
4278 if(parent()->isTopContainer()) {
4279 mRealtiveMousePoint.x = where.x - bounds.x;
4280 mRealtiveMousePoint.y = where.y - bounds.y;
4281 }else{
4282 mRealtiveMousePoint.x = where.x - mBounds.x;
4283 mRealtiveMousePoint.y = where.y - mBounds.y;
4286 SCView::mouseMoveAction( where, modifiers, theEvent);
4290 void SCUserView::mouseUpAction(SCPoint where, int modifiers, NSEvent *theEvent)
4292 SCRect bounds = getDrawBounds();
4294 if(parent()->isTopContainer()) {
4295 mRealtiveMousePoint.x = where.x - bounds.x;
4296 mRealtiveMousePoint.y = where.y - bounds.y;
4297 }else{
4298 mRealtiveMousePoint.x = where.x - mBounds.x;
4299 mRealtiveMousePoint.y = where.y - mBounds.y;
4302 SCView::mouseUpAction( where, modifiers, theEvent);
4306 void SCUserView::mouseOver(SCPoint where, int modifiers, NSEvent *theEvent )
4308 SCRect bounds = getDrawBounds();
4310 if(parent()->isTopContainer()) {
4311 mRealtiveMousePoint.x = where.x - bounds.x;
4312 mRealtiveMousePoint.y = where.y - bounds.y;
4313 }else{
4314 mRealtiveMousePoint.x = where.x - mBounds.x;
4315 mRealtiveMousePoint.y = where.y - mBounds.y;
4318 SCView::mouseOver( where, modifiers, theEvent);
4321 void SCUserView::mouseEndTrack(SCPoint where, int modifiers, NSEvent *theEvent)
4323 // mouseAction(getsym("mouseEndTrack"), where, modifiers);
4326 void SCUserView::keyDown(int character, int modifiers)
4330 void SCUserView::keyUp(int character, int modifiers)
4334 bool SCUserView::canReceiveDrag()
4336 PyrSlot result;
4337 sendMessage(s_canReceiveDrag, 0, 0, &result);
4338 return IsTrue(&result);
4341 void SCUserView::receiveDrag()
4343 PyrSlot args[2];
4344 SetFloat(args+0, mRealtiveMousePoint.x);
4345 SetFloat(args+1, mRealtiveMousePoint.y);
4346 sendMessage(s_receiveDrag, 2, args, 0);
4349 int SCUserView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
4351 char *name = symbol->name;
4353 if (strcmp(name, "clearOnRefresh")==0) {
4354 mClearOnRefresh = IsTrue(slot);
4355 return errNone;
4357 if (strcmp(name, "clearDrawing")==0) {
4358 clearDrawing();
4359 return errNone;
4361 if (strcmp(name, "drawingEnabled")==0) {
4362 mDrawingEnabled = IsTrue(slot);
4363 return errNone;
4365 if (strcmp(name, "animate")==0) {
4366 if (IsTrue(slot)) {
4367 startAnimation();
4368 } else {
4369 stopAnimation();
4371 return errNone;
4374 return SCView::setProperty(symbol, slot);
4377 int SCUserView::getProperty(PyrSymbol *symbol, PyrSlot *slot)
4379 char *name = symbol->name;
4381 if (strcmp(name, "mousePosition")==0) {
4382 if(isKindOfSlot(slot, s_point->u.classobj)){
4384 PyrSlot *slots = slotRawObject(slot)->slots;
4385 SetFloat(slots+0, mRealtiveMousePoint.x);
4386 SetFloat(slots+1, mRealtiveMousePoint.y);
4388 return errNone;
4390 if (strcmp(name, "frame")==0) {
4391 SetInt(slot, mFrameCounter);
4392 return errNone;
4394 if (strcmp(name, "frameRate")==0) {
4395 SetFloat(slot, mFrameRate);
4396 return errNone;
4399 return SCView::getProperty(symbol, slot);
4402 void SCUserView::refreshInRect(SCRect b)
4404 b.x += mLayout.bounds.x;
4405 b.y += mLayout.bounds.y;
4406 SCView::refreshInRect(b);
4410 ////////////////////////////////////////////////
4412 SCView* NewSCStaticText(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
4414 return new SCStaticText(inParent, inObj, inBounds);
4417 SCStaticText::SCStaticText(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
4418 : SCView(inParent, inObj, inBounds), mString(0), mAlignment(kSCAlignLeft)
4420 strcpy(mFontName, "Helvetica");
4421 mFontSize = 12.;
4422 mStringColor = SCMakeColor(0,0,0,1);
4423 mEnabled = false;
4424 mCanFocus = false;
4427 SCStaticText::~SCStaticText()
4429 delete [] mString;
4432 bool SCStaticText::shouldDim()
4434 return false;
4437 void SCStaticText::draw(SCRect inDamage)
4439 SCView::draw(inDamage);
4440 SCRect bounds = getDrawBounds();
4442 drawString(bounds);
4445 void SCStaticText::drawString(SCRect bounds)
4447 if (mString) {
4448 if (mAlignment < 0) {
4449 stringDrawLeftInRect(mString, bounds, mFontName, mFontSize, mStringColor);
4450 } else if (mAlignment > 0) {
4451 stringDrawRightInRect(mString, bounds, mFontName, mFontSize, mStringColor);
4452 } else {
4453 stringDrawCenteredInRect(mString, bounds, mFontName, mFontSize, mStringColor);
4458 int allocSlotStrVal(PyrSlot *slot, char **str)
4460 int len;
4461 if (*str) {
4462 delete [] *str;
4463 *str = 0;
4465 if (IsSym(slot)) {
4466 len = strlen(slotRawSymbol(slot)->name);
4467 *str = new char[len+1];
4468 strcpy(*str, slotRawSymbol(slot)->name);
4469 return errNone;
4470 } else if (isKindOfSlot(slot, class_string)) {
4471 len = slotRawObject(slot)->size;
4472 *str = new char[len+1];
4473 memcpy(*str, slotRawString(slot)->s, len);
4474 (*str)[len] = 0;
4475 return errNone;
4477 return errWrongType;
4480 int SCStaticText::setProperty(PyrSymbol *symbol, PyrSlot *slot)
4482 int err;
4483 char *name = symbol->name;
4484 if (strcmp(name, "string")==0) {
4485 err = allocSlotStrVal(slot, &mString);
4486 if (err) return err;
4487 refresh();
4488 return errNone;
4490 if (strcmp(name, "font")==0) {
4491 if (!isKindOfSlot(slot, getsym("SCFont")->u.classobj)) return errWrongType;
4492 PyrSlot *slots = slotRawObject(slot)->slots;
4494 float fontSize;
4495 err = slotFloatVal(slots+1, &fontSize);
4496 if (err) return err;
4498 err = slotStrVal(slots+0, mFontName, kFontNameSize);
4499 if (err) return err;
4501 mFontSize = fontSize;
4502 refresh();
4503 return errNone;
4505 if (strcmp(name, "stringColor")==0) {
4506 err = slotColorVal(slot, &mStringColor);
4507 if (err) return err;
4508 refresh();
4509 return errNone;
4511 if (strcmp(name, "align")==0) {
4512 int align;
4513 if (IsSym(slot)) {
4514 if (slotRawSymbol(slot)->name[0] == 'l') mAlignment = -1;
4515 else if (slotRawSymbol(slot)->name[0] == 'r') mAlignment = 1;
4516 else if (slotRawSymbol(slot)->name[0] == 'c') mAlignment = 0;
4517 else return errFailed;
4518 } else {
4519 err = slotIntVal(slot, &align);
4520 if (err) return err;
4521 mAlignment = align;
4523 refresh();
4524 return errNone;
4526 return SCView::setProperty(symbol, slot);
4529 int SCStaticText::getProperty(PyrSymbol *symbol, PyrSlot *slot)
4531 char *name = symbol->name;
4533 if (strcmp(name, "stringColor")==0) {
4534 return setSlotColor(slot, &mStringColor);
4537 return SCView::getProperty(symbol, slot);
4542 ////////////////////////////////////////////////
4544 SCView* NewSCListView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
4546 return new SCListView(inParent, inObj, inBounds);
4549 SCListView::SCListView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
4550 : SCView(inParent, inObj, inBounds), mArray(0), mScroll(0), mAlignment(kSCAlignLeft)
4552 strcpy(mFontName, "Helvetica");
4553 mFontSize = 12.;
4554 mStringColor = SCMakeColor(0,0,0,1);
4555 mSelectedStringColor = SCMakeColor(1,1,1,1);
4556 mHiliteColor = SCMakeColor(0,0,0,1);
4557 mValue = 0;
4558 mItemBackgroundColor = NULL;
4561 SCListView::~SCListView()
4563 if (mArray) CFRelease(mArray);
4566 NSSize nsStringSize(NSString *nsstring, char *cFontName, float fontSize, SCColor sccolor);
4567 NSRect SCtoNSRect(SCRect screct);
4569 void SCListView::draw(SCRect inDamage)
4571 SCView::draw(inDamage);
4572 SCRect bounds = getDrawBounds();
4573 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
4574 CGContextSaveGState(cgc);
4576 CGRect bevelRect = SCtoCGRect(bounds);
4577 QDDrawBevelRect(cgc, bevelRect, 1, true);
4579 int numItems = mArray ? CFArrayGetCount(mArray) : 0;
4581 mStrSize = nsStringSize((NSString*)CFSTR("XWYjpgy"), mFontName, mFontSize, mStringColor);
4583 float itemHeight = mStrSize.height + 3.f;
4584 //float totalHeight = itemHeight * numItems;
4585 float visibleItems = bounds.height / itemHeight;
4586 float fraction = visibleItems / (float)numItems;
4588 float totalHeight = itemHeight * numItems;
4590 float maxScroll = totalHeight - bounds.height;
4591 if (maxScroll < 0) maxScroll = 0;
4592 mScroll = sc_clip(mScroll, 0, maxScroll);
4594 SCRect itemBounds = bounds;
4595 itemBounds.x += 4;
4596 itemBounds.y += 2 - mScroll;
4597 itemBounds.width -= 6; itemBounds.height -= 4;
4599 itemBounds.height = itemHeight;
4601 if (fraction < 1.f)
4604 itemBounds.width -= 16;
4606 // draw slider
4607 SCRect sliderBounds = bounds;
4608 sliderBounds.x = bounds.x + bounds.width - 16;
4609 sliderBounds.width = 15;
4610 sliderBounds.y += 1;
4611 sliderBounds.height -= 2;
4612 bevelRect = SCtoCGRect(sliderBounds);
4613 QDDrawBevelRect(cgc, bevelRect, 1, true);
4615 float travel = (1.f - fraction) * (bounds.height - 4);
4616 SCRect thumbBounds = sliderBounds;
4617 thumbBounds.y = 1.f + sliderBounds.y + travel * (mScroll / maxScroll);
4618 thumbBounds.height = (sliderBounds.height - 2) * fraction;
4619 thumbBounds.x += 1;
4620 thumbBounds.width -= 2;
4621 bevelRect = SCtoCGRect(thumbBounds);
4622 QDDrawBevelRect(cgc, bevelRect, 2, false);
4625 if (mArray) {
4626 CGRect clipRect = SCtoCGRect(bounds);
4627 clipRect.origin.y += 1;
4628 clipRect.size.height -= 2;
4629 CGContextClipToRect(cgc, clipRect);
4631 int minIndex = (int)((mScroll - itemHeight + 1) / itemHeight);
4632 int maxIndex = (int)(minIndex + 1 + (bounds.height + itemHeight - 1) / itemHeight);
4633 if (maxIndex > numItems - 1) maxIndex = numItems - 1;
4634 itemBounds.y += minIndex * itemHeight;
4637 for (int i = minIndex; i <= maxIndex; ++i)
4639 NSString* nsstring = (NSString*)CFArrayGetValueAtIndex(mArray, i);
4640 NSSize size;
4641 if(mItemBackgroundColor){
4642 SCColor color = mItemBackgroundColor[i];
4643 CGContextSetRGBFillColor(cgc, color.red, color.green, color.blue, color.alpha);
4644 CGRect drawRect = SCtoCGRect(itemBounds);
4645 CGContextFillRect (cgc, drawRect);
4647 if (i == mValue) {
4648 CGContextSetRGBFillColor(cgc, mHiliteColor.red, mHiliteColor.green, mHiliteColor.blue, mHiliteColor.alpha);
4649 CGRect drawRect = SCtoCGRect(itemBounds);
4650 CGContextFillRect (cgc, drawRect);
4651 nsStringDrawInRectAlign(nsstring, itemBounds, mFontName, mFontSize, mSelectedStringColor, mAlignment, -1, &size);
4652 } else {
4653 nsStringDrawInRectAlign(nsstring, itemBounds, mFontName, mFontSize, mStringColor, mAlignment, -1, &size);
4656 itemBounds.y += itemBounds.height;
4658 CGContextRestoreGState(cgc);
4662 void SCListView::scrollToValue()
4664 int numItems = mArray ? CFArrayGetCount(mArray) : 0;
4665 SCRect bounds = getDrawBounds();
4667 float itemHeight = mStrSize.height + 3.f;
4668 //float visibleItems = mBounds.height / itemHeight;
4669 //float fraction = visibleItems / (float)numItems;
4670 float totalHeight = itemHeight * numItems;
4672 float maxScroll = totalHeight - bounds.height;
4673 if (maxScroll < 0) maxScroll = 0;
4675 SCRect itemBounds = bounds;
4676 itemBounds.x += 4;
4677 itemBounds.y += 2 - mScroll;
4678 itemBounds.width -= 6; itemBounds.height -= 4;
4679 itemBounds.height = itemHeight;
4681 itemBounds.y += mValue * itemHeight;
4683 if (itemBounds.y < bounds.y) mScroll = mValue * itemHeight;
4684 else if (itemBounds.y + itemHeight > bounds.y + bounds.height) mScroll = (mValue + 1) * itemHeight - bounds.height;
4687 bool SCListView::setValue(int inValue, bool send)
4689 bool changed = inValue != mValue;
4690 int numItems = mArray ? CFArrayGetCount(mArray) : 0;
4691 if (inValue < 0) inValue = numItems - 1;
4692 else if (inValue >= numItems) inValue = 0;
4693 if (inValue != mValue || numItems < 2) {
4694 mValue = inValue;
4696 scrollToValue();
4698 refresh();
4699 if (send) sendMessage(s_doaction, 0, 0, 0);
4701 return changed;
4704 int SCListView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
4706 int err;
4708 if (symbol == s_value) {
4709 int value;
4710 err = slotIntVal(slot, &value);
4711 if (err) return err;
4712 bool changed = setValue(value, false);
4713 SetBool(slot, changed);
4714 return errNone;
4717 char *name = symbol->name;
4718 if (strcmp(name, "items")==0) {
4719 if (IsNil(slot)) {
4720 if (mArray) {
4721 CFRelease(mArray);
4722 mArray = NULL;
4724 refresh();
4725 return errNone;
4727 if (!isKindOfSlot(slot, class_array)) return errWrongType;
4729 // wipe out old
4730 if (mArray) {
4731 CFRelease(mArray);
4732 mArray = NULL;
4735 PyrObject *array = slotRawObject(slot);
4736 int numItems = array->size;
4738 mArray = (CFMutableArrayRef)CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
4740 for (int i=0; i<numItems; ++i) {
4741 PyrSlot *slot = array->slots + i;
4743 char cstr[1024];
4744 CFStringRef cfstr;
4745 int err = slotStrVal(slot, cstr, 1023);
4746 if (err) return err;
4748 cfstr = CFStringCreateWithCString(kCFAllocatorDefault, cstr, kCFStringEncodingUTF8);
4750 CFArrayAppendValue(mArray, cfstr);
4751 CFRelease(cfstr);
4753 refresh();
4754 return errNone;
4756 if (strcmp(name, "font")==0) {
4757 if (!isKindOfSlot(slot, getsym("SCFont")->u.classobj)) return errWrongType;
4758 PyrSlot *slots = slotRawObject(slot)->slots;
4760 float fontSize;
4761 err = slotFloatVal(slots+1, &fontSize);
4762 if (err) return err;
4764 err = slotStrVal(slots+0, mFontName, kFontNameSize);
4765 if (err) return err;
4767 mFontSize = fontSize;
4768 refresh();
4769 return errNone;
4771 if (strcmp(name, "stringColor")==0) {
4772 err = slotColorVal(slot, &mStringColor);
4773 if (err) return err;
4774 refresh();
4775 return errNone;
4777 if (strcmp(name, "itemColors")==0) {
4778 if (IsNil(slot)) {
4779 if (mItemBackgroundColor) {
4780 // CFRelease(mItemBackgroundColor);
4781 delete(mItemBackgroundColor);
4782 mItemBackgroundColor = NULL;
4784 refresh();
4785 return errNone;
4787 if (!isKindOfSlot(slot, class_array)) return errWrongType;
4789 // wipe out old
4790 if (mItemBackgroundColor) {
4791 // CFRelease(mItemBackgroundColor);
4792 delete(mItemBackgroundColor);
4793 mItemBackgroundColor = NULL;
4796 PyrObject *array = slotRawObject(slot);
4797 int numItems = array->size;
4799 // mItemBackgroundColor = (CFMutableArrayRef)CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
4800 mItemBackgroundColor = (SCColor*) malloc(numItems * sizeof(SCColor));
4801 for (int i=0; i<numItems; ++i) {
4802 PyrSlot *slot = array->slots + i;
4804 SCColor color;
4805 int err = slotColorVal(slot, &color);
4806 if (err) return err;
4807 mItemBackgroundColor[i] = color;
4809 refresh();
4810 return errNone;
4813 if (strcmp(name, "selectedStringColor")==0) {
4814 err = slotColorVal(slot, &mSelectedStringColor);
4815 if (err) return err;
4816 refresh();
4817 return errNone;
4819 if (strcmp(name, "hiliteColor")==0) {
4820 err = slotColorVal(slot, &mHiliteColor);
4821 if (err) return err;
4822 refresh();
4823 return errNone;
4825 if (strcmp(name, "align")==0) {
4826 int align;
4827 if (IsSym(slot)) {
4828 if (slotRawSymbol(slot)->name[0] == 'l') mAlignment = -1;
4829 else if (slotRawSymbol(slot)->name[0] == 'r') mAlignment = 1;
4830 else if (slotRawSymbol(slot)->name[0] == 'c') mAlignment = 0;
4831 else return errFailed;
4832 } else {
4833 err = slotIntVal(slot, &align);
4834 if (err) return err;
4835 mAlignment = align;
4837 refresh();
4838 return errNone;
4840 return SCView::setProperty(symbol, slot);
4843 int SCListView::getProperty(PyrSymbol *symbol, PyrSlot *slot)
4845 if (symbol == s_value) {
4846 SetInt(slot, mValue);
4847 return errNone;
4849 char *name = symbol->name;
4851 if (strcmp(name, "stringColor")==0) {
4852 return setSlotColor(slot, &mStringColor);
4855 if (strcmp(name, "itemColors")==0) {
4856 int size, err;
4857 PyrSlot * slots;
4858 slots = slotRawObject(slot)->slots;
4859 size = slotRawObject(slot)->size;
4860 for(int i=0; i<size; i++)
4862 err = setSlotColor(slots+i, &mItemBackgroundColor[i]);
4863 if(err) return err;
4865 return errNone;
4868 return SCView::getProperty(symbol, slot);
4872 bool SCListView::canReceiveDrag()
4874 PyrSlot result;
4875 sendMessage(s_canReceiveDrag, 0, 0, &result);
4876 return IsTrue(&result);
4879 void SCListView::receiveDrag()
4881 sendMessage(s_receiveDrag, 0, 0, 0);
4884 void SCListView::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
4887 mAnchor = where;
4888 mAnchorScroll = mScroll;
4889 SCRect bounds = getDrawBounds();
4891 mStrSize = nsStringSize((NSString*)CFSTR("XWYjpgy"), mFontName, mFontSize, mStringColor);
4892 int numItems = mArray ? CFArrayGetCount(mArray) : 0;
4894 float itemHeight = mStrSize.height + 3.f;
4895 float visibleItems = bounds.height / itemHeight;
4896 float fraction = visibleItems / (float)numItems;
4898 mScrolling = fraction < 1.f && where.x >= bounds.x + bounds.width - 16;
4899 if (!mScrolling) {
4900 int value = (int)((where.y - bounds.y - 2 + mScroll) / itemHeight);
4901 setValue(value, true);
4905 void SCListView::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
4907 if (modifiers & NSCommandKeyMask) {
4908 beginDrag(where);
4909 } else {
4910 if (mScrolling) {
4911 SCRect bounds = getDrawBounds();
4913 int numItems = mArray ? CFArrayGetCount(mArray) : 0;
4915 float itemHeight = mStrSize.height + 3.f;
4916 float visibleItems = bounds.height / itemHeight;
4917 float fraction = visibleItems / (float)numItems;
4918 float totalHeight = itemHeight * numItems;
4919 float travel = (1.f - fraction) * (bounds.height - 4);
4921 float maxScroll = totalHeight - bounds.height;
4922 if (maxScroll < 0) maxScroll = 0;
4923 float sliderOffset = travel * (mAnchorScroll / maxScroll);
4925 float change = where.y - mAnchor.y;
4926 float newSliderOffset = sliderOffset + change;
4927 mScroll = maxScroll * newSliderOffset / travel;
4929 mScroll = sc_clip(mScroll, 0, maxScroll);
4931 refresh();
4936 ////////////////////////////////////////////////
4937 //////////////////////////////////////////////////////////////////////////////////
4939 ////////////////////////////////////////////////
4940 //////////////////////////////////////////////////////////////////////////////////
4941 //////////////////////////////////////////////////////////////////////////////////
4942 //SCEnvelopeView by jan trutzschler feb.02.03 // udated feb.22.03
4943 int allocSlot2DDoubleArrayPyrSlot (PyrSlot *slot, double **arr, int position);
4944 int allocSlot2DDoubleArrayPyrSlot(PyrSlot *slot, double **arr, int position)
4946 int len;
4947 if (*arr) {
4948 delete [] *arr;
4949 *arr = 0;
4952 if (isKindOfSlot(slot, class_array)) {
4953 len = slotRawObject(slotRawObject(slot)->slots + position)->size;
4954 *arr = new double[len];
4955 memcpy(*arr, ((PyrDoubleArray*)slotRawObject(slotRawObject(slot)->slots+position))->d, len * sizeof(double));
4956 return errNone;
4958 return errWrongType;
4960 int allocEnvArray (int size, SCEnvObject **arr);
4961 int allocEnvArray (int size, SCEnvObject **arr){
4963 * arr = new SCEnvObject[size];
4965 return errNone;
4967 //int allocSlotEnvObjArray(PyrSlot *slot, SCEnvObject **arr);
4970 SCView* NewSCEnvelopeView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
4972 return new SCEnvelopeView(inParent, inObj, inBounds);
4975 SCEnvelopeView::SCEnvelopeView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
4976 : SCView(inParent, inObj, inBounds), mThumbSize(5), mStepSize(0.),mStepScale(0.)
4979 mTabSize = 0;
4980 mActiveSize = mTabSize;
4981 mCurrentIndex = mStartIndex = 0;
4982 mThumbSizeY = mThumbSize;
4983 mSelectionSize = 1;
4984 mCurrentY = 0.0;
4985 mCurrentX = 0.0;
4986 mLastIndex = 0;
4987 mIsEnvView = true;
4988 mIsTracking = false;
4990 mEnvObj = 0;
4991 drawOrder = 0;
4993 mFillColor = mStrokeColor = SCMakeColor(0,0,0,1); // black
4994 mSelectedColor = SCMakeColor(1.f,0,0,1);
4995 mIsFilled = mDrawLinesActive = true;
4996 mDrawRectsActive = true;
4997 // setVisibleSize();
4998 mSelectedIndex = -1;
4999 mAbsoluteX = 0.0;
5000 mIsFixedSelection = false;
5002 strcpy(mFontName, "Helvetica");
5003 mFontSize = 12.;
5004 mDrawCenteredConnection = true;
5005 mGridOn = false;
5006 mGridColor = SCMakeColor(0, 0, 0.8, 0.3);
5007 mGrid = SCMakePoint(0.1, 0.1);
5009 SCEnvelopeView::~SCEnvelopeView()
5012 for(int i = 0; i < mTabSize; i++){
5013 if( (mEnvObj+i)->mString)
5014 delete [] (mEnvObj+i)->mString;
5015 if((mEnvObj+i)->mConnections)
5016 delete [] (mEnvObj+i)->mConnections;
5018 if((mEnvObj+i)->mConnectionOutputs)
5019 delete [] (mEnvObj+i)->mConnectionOutputs;
5020 if((mEnvObj+i)->mConnectionInputs)
5021 delete [] (mEnvObj+i)->mConnectionInputs;
5026 delete [] mEnvObj;
5028 if(drawOrder) delete [] drawOrder;
5032 int SCEnvelopeView::allocSlotEnvObjArray(PyrSlot *slot, SCEnvObject **arr)
5034 int size = slotRawObject(&(slotRawObject(slot)->slots[0]))->size;
5036 SCEnvObject * scenv = 0;
5037 int err = allocEnvArray(size, &scenv);
5038 if(err) return err;
5039 if (*arr) {
5040 if(size > mTabSize){
5041 memcpy(scenv, *arr, mTabSize * sizeof(SCEnvObject));
5042 for(int i=mTabSize; i< size; i++){
5043 (scenv+i)->mObjectColor = mFillColor;
5044 (scenv+i)->mString = 0;
5045 (scenv+i)->mConnections = 0;
5046 (scenv+i)->mColor = mFillColor;
5047 (scenv+i)->mEditable = true;
5048 (scenv+i)->mIsSelected = false;
5049 (scenv+i)->mNumConnection = 0;
5050 (scenv+i)->mRect.height = mThumbSizeY;
5051 (scenv+i)->mRect.width = mThumbSize;
5052 (scenv+i)->shape = 1;
5053 (scenv+i)->curve = 1.0;
5056 } else { //meaning size < mTabSize
5057 memcpy(scenv, *arr, size * sizeof(SCEnvObject));
5059 delete [] *arr;
5060 *arr = 0;
5062 } else {
5063 for(int i=0; i< size; i++){
5064 (scenv+i)->mObjectColor = mFillColor;
5065 (scenv+i)->mString = 0;
5066 (scenv+i)->mConnections = 0;
5067 (scenv+i)->mColor = mFillColor;
5068 (scenv+i)->mEditable = true;
5069 (scenv+i)->mIsSelected = false;
5070 (scenv+i)->mNumConnection = 0;
5071 (scenv+i)->mRect.height = mThumbSizeY;
5072 (scenv+i)->mRect.width = mThumbSize;
5073 (scenv+i)->shape = 1;
5074 (scenv+i)->curve = 1.0;
5078 err = allocEnvArray(size, arr);
5079 if(err) return err;
5080 memcpy(*arr, scenv, size * sizeof(SCEnvObject));
5081 delete [] scenv;
5082 return errNone;
5085 // helper constants for shape calculation
5086 #define EXPM1 (float) exp(-1.f)
5087 #define EXPM1R (float) (1.f - exp(-1.f))
5089 inline double linlinNoClip(double x, double a, double b, double c, double d)
5091 // if (x <= a) return c;
5092 // if (x >= b) return d;
5093 return (x-a)/(b-a) * (d-c) + c;
5096 void SCEnvelopeView::draw(SCRect inDamage)
5098 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
5099 CGContextSaveGState(cgc);
5100 SCRect bounds = getDrawBounds();
5102 CGRect rect = SCtoCGRect(bounds);
5103 CGContextClipToRect(cgc, rect);
5105 int xpixels = mActiveSize;
5106 int xstart = 0;
5108 if (mBackground) mBackground->draw(cgc, rect);
5110 if (mBackgroundImage)
5111 mBackgroundImage->draw(cgc, rect);
5113 QDDrawBevelRect(cgc, rect, 1, true);
5117 CGRect drawRect;
5118 SCColor fillcolor;
5119 SCEnvObject * envobj;
5121 //draw grid
5122 if(mGridOn){
5123 float xgrid, ygrid, xgridpos, ygridpos;
5124 float maxwidth = (bounds.width + bounds.x) - 2.f;
5125 float maxheight = (bounds.height + bounds.y) - 2.f;
5127 xgrid = mGrid.x;
5128 ygrid = mGrid.y;
5130 CGContextSetRGBFillColor(cgc, mGridColor.red, mGridColor.green, mGridColor.blue, mGridColor.alpha);
5131 xgrid = xgrid*bounds.width;
5132 xgridpos = bounds.x+1.f + xgrid;
5133 ygrid = ygrid*bounds.height;
5134 ygridpos = bounds.y+1.f + ygrid;
5135 while(xgridpos < maxwidth && (xgrid > 0.0))
5137 drawRect = CGRectMake(xgridpos,
5138 bounds.y + 1.f,
5139 1.f,
5140 bounds.height-2.f);
5141 CGContextFillRect (cgc, drawRect);
5142 xgridpos += xgrid;
5145 while(ygridpos < maxheight && (ygrid > 0.0))
5147 drawRect = CGRectMake(bounds.x+1.f,
5148 ygridpos,
5149 bounds.width-2.f,
5150 1.f);
5151 CGContextFillRect (cgc, drawRect);
5152 ygridpos += ygrid;
5156 CGContextSetRGBFillColor(cgc, mFillColor.red, mFillColor.green, mFillColor.blue, mFillColor.alpha);
5157 CGContextSetRGBStrokeColor(cgc, mStrokeColor.red, mStrokeColor.green, mStrokeColor.blue, mStrokeColor.alpha);
5159 //draw lines
5160 if (mDrawLinesActive) {
5162 int numConnection, num;
5164 for(int i = xstart; i < xpixels; i++){
5165 // float gcoDx;
5166 envobj = &mEnvObj[i];
5167 setEnvRect(envobj->x, envobj->y, envobj);
5169 if(mIsEnvView){ //straight connection
5170 if(i == xstart)
5171 CGContextMoveToPoint(cgc, envobj->mDrawPoint.x, envobj->mDrawPoint.y);
5172 else {
5173 float gcx, gcy, gcox, gcoy;
5174 SCEnvObject * conObj = (mEnvObj + (i-1));
5175 float curve;
5176 float dur, numpointsY, yLevel, pos;
5177 float begTime, endTime, begLevel, endLevel, stepsize, ar, br, yrange;
5178 int numsteps;
5179 float startPointX, endPointX, startPointY, endPointY;
5180 curve = conObj->curve;
5181 gcox = envobj->mDrawPoint.x;
5182 gcoy = envobj->mDrawPoint.y;
5183 gcx = conObj->mDrawPoint.x;
5184 gcy = conObj->mDrawPoint.y;
5185 // post("shape at i: %i, is: %i\n", i, conObj->shape);
5186 switch(conObj->shape){
5187 case shape_Step:
5188 CGContextMoveToPoint(cgc, gcox, gcoy);
5189 CGContextAddLineToPoint(cgc, gcox, gcy);
5190 CGContextAddLineToPoint(cgc, gcx, gcy);
5191 break;
5192 case shape_Linear:
5193 CGContextMoveToPoint(cgc, gcox, gcoy);
5194 CGContextAddLineToPoint(cgc, gcx, gcy);
5195 break;
5197 case shape_Exponential:
5199 if(conObj->x <= envobj->x)
5201 startPointX = gcx;
5202 endPointX = gcox;
5204 startPointY = gcy;
5205 endPointY= gcoy;
5207 begTime = conObj->x;
5208 begLevel = sc_clip(conObj->y, 0.000001f, 1.f);
5210 endTime = envobj->x;
5211 endLevel = sc_clip(envobj->y, 0.000001f, 1.f);
5213 } else {
5214 startPointX = gcox;
5215 endPointX = gcx;
5217 startPointY = gcoy;
5218 endPointY= gcy;
5220 begTime = envobj->x;
5221 begLevel = sc_clip(envobj->y, 0.000001f, 1.f);
5223 endTime = conObj->x;
5224 endLevel = sc_clip(conObj->y, 0.000001f, 1.f);
5227 numsteps = (int) endPointX - startPointX;
5228 dur = endTime - begTime;
5229 stepsize = dur/numsteps;
5230 CGContextMoveToPoint(cgc, startPointX, startPointY);
5232 for(int i=1; i<=numsteps+1; i++){
5233 double step = sc_clip((i*stepsize), 0.0, dur); // need to clip when here when clipping endLevel or begLevel
5234 double pos = step / dur;
5235 yLevel = begLevel * pow(endLevel / begLevel, pos);
5236 CGContextAddLineToPoint(cgc, linlinNoClip((i*stepsize), 0.f, dur, startPointX, endPointX), linlinNoClip(yLevel, begLevel, endLevel, startPointY, endPointY));
5238 CGContextAddLineToPoint(cgc, endPointX, endPointY);
5241 break;
5243 case shape_Sine:
5244 CGContextMoveToPoint(cgc, gcox, gcoy);
5245 CGContextAddCurveToPoint(cgc, gcox * EXPM1R + gcx * EXPM1, gcoy, gcox * EXPM1 + gcx * EXPM1R, gcy, gcx, gcy );
5246 break;
5248 case shape_Welch:
5249 CGContextMoveToPoint(cgc, gcox, gcoy);
5250 if( gcoy < gcy ) {
5251 CGContextAddCurveToPoint(cgc, gcox * 0.556f + gcx * 0.444f, gcoy * 0.278f + gcy * 0.722f, gcox * 0.29f + gcx * 0.71f, gcy, gcx, gcy );
5252 } else {
5253 CGContextAddCurveToPoint(cgc, gcx * 0.29f + gcox * 0.71f, gcoy, gcx * 0.556f + gcox * 0.444f, gcy * 0.278f + gcoy * 0.722f, gcx, gcy );
5255 break;
5256 case shape_Curve:
5258 if(conObj->x <= envobj->x)
5260 startPointX = gcx;
5261 endPointX = gcox;
5263 startPointY = gcy;
5264 endPointY= gcoy;
5266 begTime = conObj->x;
5267 begLevel = sc_clip(conObj->y, 0.000001f, 1.f);
5269 endTime = envobj->x;
5270 endLevel = sc_clip(envobj->y, 0.000001f, 1.f);
5272 } else {
5273 startPointX = gcox;
5274 endPointX = gcx;
5276 startPointY = gcoy;
5277 endPointY= gcy;
5279 begTime = envobj->x;
5280 begLevel = sc_clip(envobj->y, 0.000001f, 1.f);
5282 endTime = conObj->x;
5283 endLevel = sc_clip(conObj->y, 0.000001f, 1.f);
5286 numsteps = (int) endPointX - startPointX;
5287 dur = endTime - begTime;
5288 stepsize = dur/numsteps;
5289 CGContextMoveToPoint(cgc, startPointX, startPointY);
5291 for(int i=1; i<=numsteps+1; i++){
5292 double step = sc_clip((i*stepsize), 0.0, dur); // need to clip when here when clipping endLevel or begLevel
5293 double pos = step / dur;
5294 if (fabs(curve) < 0.0001) {
5295 yLevel = pos * (endLevel - begLevel) + begLevel;
5296 } else {
5297 double denom = 1. - exp(curve);
5298 double numer = 1. - exp(pos * curve);
5299 yLevel = begLevel + (endLevel - begLevel) * (numer/denom);
5302 CGContextAddLineToPoint(cgc, linlinNoClip((i*stepsize), 0.f, dur, startPointX, endPointX), linlinNoClip(yLevel, begLevel, endLevel, startPointY, endPointY));
5304 CGContextAddLineToPoint(cgc, endPointX, endPointY);
5307 break;
5309 case shape_Squared:
5310 CGContextMoveToPoint(cgc, gcox, gcoy);
5311 if( gcoy < gcy ) {
5312 CGContextAddCurveToPoint(cgc, gcox * 0.9f + gcx * 0.1f, gcoy, gcox * 0.5f + gcx * 0.5f, gcoy, gcx, gcy );
5313 } else {
5314 CGContextAddCurveToPoint(cgc, gcx * 0.5f + gcox * 0.5f, gcy, gcx * 0.9f + gcox * 0.1f, gcy, gcx, gcy );
5316 break;
5318 case shape_Cubed:
5319 CGContextMoveToPoint(cgc, gcox, gcoy);
5320 if( gcoy < gcy ) {
5321 CGContextAddCurveToPoint(cgc, gcox * 0.6667f + gcx * 0.3333f, gcoy, gcox * 0.3333f + gcx * 0.6667f, gcoy, gcx, gcy );
5322 } else {
5323 CGContextAddCurveToPoint(cgc, gcx * 0.3333f + gcox * 0.6667f, gcy, gcx * 0.6667f + gcox * 0.3333f, gcy, gcx, gcy );
5325 break;
5329 } else {
5331 numConnection = envobj->mNumConnection;
5333 for(int j = 0; j < numConnection; j++){
5334 float gcx, gcy, gcox, gcoy, curve;
5335 num = (int) (envobj->mConnections[j]);
5336 SCEnvObject * conObj = (mEnvObj + num);
5337 curve = conObj->curve;
5338 // post("shape at num: %i, is: %i\n", num, conObj->shape);
5339 gcox = envobj->mDrawPoint.x;
5340 gcoy = envobj->mDrawPoint.y;
5341 gcx = conObj->mDrawPoint.x;
5342 gcy = conObj->mDrawPoint.y;
5343 if (num >=0 ){
5344 switch(conObj->shape){
5345 case shape_Step:
5346 CGContextMoveToPoint(cgc, gcox, gcoy);
5347 CGContextAddLineToPoint(cgc, gcox, gcy);
5348 CGContextAddLineToPoint(cgc, gcx, gcy);
5349 break;
5350 case shape_Linear:
5351 CGContextMoveToPoint(cgc, gcox, gcoy);
5352 CGContextAddLineToPoint(cgc, gcx, gcy);
5353 break;
5354 case shape_Sine:
5355 CGContextMoveToPoint(cgc, gcox, gcoy);
5356 CGContextAddCurveToPoint(cgc, gcox * EXPM1R + gcx * EXPM1, gcox, gcox * EXPM1 + gcx * EXPM1R, gcy, gcx, gcy );
5357 break;
5359 case shape_Exponential:
5360 float dur, numpointsY, yLevel, pos;
5361 float begTime, endTime, begLevel, endLevel, stepsize, ar, br, yrange;
5362 int numsteps;
5363 float startPointX, endPointX, startPointY, endPointY;
5365 if(conObj->x <= envobj->x)
5367 startPointX = gcx;
5368 endPointX = gcox;
5370 startPointY = gcy;
5371 endPointY= gcoy;
5373 begTime = conObj->x;
5374 begLevel = sc_clip(conObj->y, 0.000001f, 1.f);
5376 endTime = envobj->x;
5377 endLevel = sc_clip(envobj->y, 0.000001f, 1.f);
5379 } else {
5380 startPointX = gcox;
5381 endPointX = gcx;
5383 startPointY = gcoy;
5384 endPointY= gcy;
5386 begTime = envobj->x;
5387 begLevel = sc_clip(envobj->y, 0.000001f, 1.f);
5389 endTime = conObj->x;
5390 endLevel = sc_clip(conObj->y, 0.000001f, 1.f);
5393 numsteps = (int) endPointX - startPointX;
5394 dur = endTime - begTime;
5395 stepsize = dur/numsteps;
5396 CGContextMoveToPoint(cgc, startPointX, startPointY);
5398 for(int i=1; i<=numsteps+1; i++){
5399 double step = sc_clip((i*stepsize), 0.0, dur); // need to clip when here when clipping endLevel or begLevel
5400 double pos = step / dur;
5401 yLevel = begLevel * pow(endLevel / begLevel, pos);
5402 CGContextAddLineToPoint(cgc, linlinNoClip((i*stepsize), 0.f, dur, startPointX, endPointX), linlinNoClip(yLevel, begLevel, endLevel, startPointY, endPointY));
5404 CGContextAddLineToPoint(cgc, endPointX, endPointY);
5407 break;
5409 case shape_Welch:
5410 CGContextMoveToPoint(cgc, gcox, gcoy);
5411 if( gcoy < gcy ) {
5412 CGContextAddCurveToPoint(cgc, gcox * 0.556f + gcx * 0.444f, gcoy * 0.278f + gcy * 0.722f, gcox * 0.29f + gcx * 0.71f, gcy, gcx, gcy );
5413 } else {
5414 CGContextAddCurveToPoint(cgc, gcx * 0.29f + gcox * 0.71f, gcoy, gcx * 0.556f + gcox * 0.444f, gcy * 0.278f + gcoy * 0.722f, gcx, gcy );
5416 break;
5417 case shape_Curve:
5419 if(conObj->x <= envobj->x)
5421 startPointX = gcx;
5422 endPointX = gcox;
5424 startPointY = gcy;
5425 endPointY= gcoy;
5427 begTime = conObj->x;
5428 begLevel = sc_clip(conObj->y, 0.000001f, 1.f);
5430 endTime = envobj->x;
5431 endLevel = sc_clip(envobj->y, 0.000001f, 1.f);
5433 } else {
5434 startPointX = gcox;
5435 endPointX = gcx;
5437 startPointY = gcoy;
5438 endPointY= gcy;
5440 begTime = envobj->x;
5441 begLevel = sc_clip(envobj->y, 0.000001f, 1.f);
5443 endTime = conObj->x;
5444 endLevel = sc_clip(conObj->y, 0.000001f, 1.f);
5447 numsteps = (int) endPointX - startPointX;
5448 dur = endTime - begTime;
5449 stepsize = dur/numsteps;
5450 CGContextMoveToPoint(cgc, startPointX, startPointY);
5452 for(int i=1; i<=numsteps+1; i++){
5453 double step = sc_clip((i*stepsize), 0.0, dur); // need to clip when here when clipping endLevel or begLevel
5454 double pos = step / dur;
5455 if (fabs(curve) < 0.0001) {
5456 yLevel = pos * (endLevel - begLevel) + begLevel;
5457 } else {
5458 double denom = 1. - exp(curve);
5459 double numer = 1. - exp(pos * curve);
5460 yLevel = begLevel + (endLevel - begLevel) * (numer/denom);
5463 CGContextAddLineToPoint(cgc, linlinNoClip((i*stepsize), 0.f, dur, startPointX, endPointX), linlinNoClip(yLevel, begLevel, endLevel, startPointY, endPointY));
5465 CGContextAddLineToPoint(cgc, endPointX, endPointY);
5468 break;
5470 case shape_Squared:
5471 CGContextMoveToPoint(cgc, gcox, gcoy);
5472 if( gcoy < gcy ) {
5473 CGContextAddCurveToPoint(cgc, gcox * 0.9f + gcx * 0.1f, gcoy, gcox * 0.5f + gcx * 0.5f, gcoy, gcx, gcy );
5474 } else {
5475 CGContextAddCurveToPoint(cgc, gcx * 0.5f + gcox * 0.5f, gcy, gcx * 0.9f + gcox * 0.1f, gcy, gcx, gcy );
5477 break;
5478 case shape_Cubed:
5479 CGContextMoveToPoint(cgc, gcox, gcoy);
5480 if( gcoy < gcy ) {
5481 CGContextAddCurveToPoint(cgc, gcox * 0.6667f + gcx * 0.3333f, gcoy, gcox * 0.3333f + gcx * 0.6667f, gcoy, gcx, gcy );
5482 } else {
5483 CGContextAddCurveToPoint(cgc, gcx * 0.3333f + gcox * 0.6667f, gcy, gcx * 0.6667f + gcox * 0.3333f, gcy, gcx, gcy );
5485 break;
5495 CGContextStrokePath(cgc);
5497 ///////////////////////////draw rects
5498 if(mDrawRectsActive)
5500 for(int i = xstart; i < xpixels; i++){
5501 envobj = &mEnvObj[drawOrder[i]];
5502 drawRect = SCtoCGRect(envobj->mRect);
5503 setEnvRect(envobj->x, envobj->y, envobj);
5505 fillcolor = envobj->mColor;
5506 CGContextSetRGBFillColor(cgc, fillcolor.red, fillcolor.green, fillcolor.blue, fillcolor.alpha);
5507 CGContextFillRect (cgc, drawRect);
5508 if(envobj->mRect.width > 1.0 || envobj->mRect.height > 1.0)
5509 CGContextStrokeRect(cgc,drawRect);
5510 if(envobj->mString)
5511 stringDrawCenteredInRect(envobj->mString, envobj->mRect, mFontName, mFontSize, mStrokeColor);
5512 //draw outputs
5513 CGContextSetRGBFillColor(cgc, mStrokeColor.red, mStrokeColor.green, mStrokeColor.blue, mStrokeColor.alpha);
5518 //draw selection:
5519 CGContextRestoreGState(cgc);
5523 bool SCEnvelopeView::setValue(SCEnvObject * envob, double xIn, double yIn, bool send)
5525 bool changed = true;
5526 // SCEnvObject * envob;
5527 //indx = sc_clip(indx, 0, mTabSize - 1);
5528 xIn = sc_clip(xIn, 0., 1.);
5529 yIn = sc_clip(yIn, 0., 1.);
5531 if(!envob->mEditable) return false;
5532 if (mStepSize > 0.) {
5533 xIn = floor(xIn * mStepScale + 0.5) * mStepSize;
5534 yIn = floor(yIn * mStepScale + 0.5) * mStepSize;
5536 //mCurrentIndex = indx;
5537 // if (changed) {
5538 //envob = &mEnvObj[indx];
5539 //changed = valXIn != envob->x || valYIn != envob->y;
5540 setEnvRect(xIn, yIn, envob);
5541 mCurrentY = yIn;
5542 mCurrentX = xIn;
5543 if (send) sendMessage(s_doaction, 0, 0, 0);
5544 //refresh();
5545 return changed;
5546 // }
5548 void SCEnvelopeView::setValueFromPoint(SCPoint where)
5550 int indx = mSelectedIndex;
5551 float width, height;
5552 SCRect bounds = getDrawBounds();
5554 width = (mEnvObj+ mSelectedIndex)->mRect.width;
5555 height = (mEnvObj+ mSelectedIndex)->mRect.height;
5556 double x = (double) (where.x - bounds.x - 1 - width/2) / (bounds.width - width - 2);
5557 double y = (double) 1.0 - (where.y - bounds.y - 1 - height/2) / (bounds.height - height - 2);
5558 if(indx >= 0){
5559 setValue(mEnvObj+ mSelectedIndex, x, y, true);
5560 refresh();
5565 bool SCEnvelopeView::setEnvRect(double valXIn, double valYIn, SCEnvObject * envobIn)
5567 double x,y, thumbx, thumby;
5568 SCEnvObject * envob = envobIn;
5569 envob->x = valXIn;
5570 envob->y = valYIn;
5571 thumby = envob->mRect.height;
5572 thumbx = envob->mRect.width;
5573 SCRect bounds = getDrawBounds();
5575 x = valXIn * (bounds.width - thumbx - 2);
5576 y = valYIn * (bounds.height - thumby - 2);
5577 y = bounds.y + bounds.height - y - 1 - thumby;
5578 x = bounds.x + x + 1;
5580 envob->mRect = SCMakeRect( x, y, thumbx, thumby);
5581 envob->mDrawPoint.x = x + (envob->mRect.width * 0.5);
5582 envob->mDrawPoint.y = y + (envob->mRect.height * 0.5);
5583 //envob->mIsVisible = true;
5584 // if(! envob->mObjectColor == NULL) envob->mObjectColor = mFillColor;
5585 // envob->mColor = envob->mObjectColor;
5587 // return SCMakeRect( x, y, thumbx, thumby);
5588 return true;
5590 void SCEnvelopeView::setSelection(SCPoint where, bool fixed, bool checkForConnection)
5592 SCEnvObject * envo;
5593 bool sel = false;
5594 //single selection
5595 mMousePoint = where;
5596 if(mSelectedIndex >= 0 && !mIsFixedSelection){
5597 (mEnvObj + mSelectedIndex)->mIsSelected = false;
5598 (mEnvObj + mSelectedIndex)->mColor =(&mEnvObj[mSelectedIndex])->mObjectColor;
5599 mSelectedIndex = -1;
5600 if(fixed) mIsFixedSelection = false;
5605 for(int count=mActiveSize - 1; count>=0; count--) {
5606 int i = drawOrder[count];
5607 envo = &mEnvObj[i]; // check in reverse drawOrder so that 'on top' gets selected first
5608 sel = SCPointInRect(where, envo->mRect);
5609 // post("in SCEnvelopeView::setSelection: where.x %f, where.y %f, sel %i\n", where.x, where.y, (int) sel);
5610 if(sel){
5611 // toggle fixed selection
5612 if(envo->mIsSelected && mIsFixedSelection){
5613 // post("toggle\n");
5615 envo->mIsSelected = false;
5616 envo->mColor = envo->mObjectColor;
5617 mSelectedIndex = -1;
5618 mIsFixedSelection = false;
5619 return;
5620 } else {
5621 envo->mIsSelected = true;
5622 envo->mColor = mSelectedColor;
5623 mSelectedIndex = i;
5624 mLastIndex = i;
5625 if(fixed) mIsFixedSelection = true;
5626 int newdrawOrder[mActiveSize];
5627 // iterate over
5628 newdrawOrder[mActiveSize - 1] = i;
5629 int j = 0, k = 0;
5630 while (j < mActiveSize) {
5631 if(drawOrder[j] != i) {
5632 newdrawOrder[k] = drawOrder[j];
5633 k++;
5635 j++;
5637 memcpy(drawOrder, newdrawOrder, mActiveSize * sizeof(int));
5638 return;
5643 multiple selection
5644 if(!sel) {
5645 (&mEnvObj[mSelectedIndex])->mIsSelected = false;
5646 (&mEnvObj[mSelectedIndex])->mColor = mFillColor;
5647 mSelectedIndex = -1;
5650 refresh();
5653 void SCEnvelopeView::mouseDownAction(SCPoint where, int modifiers, NSEvent *theEvent)
5655 mouseTrack(where, modifiers,theEvent);
5656 SCView::mouseDownAction(where, modifiers, theEvent);
5659 void SCEnvelopeView::mouseEndTrack(SCPoint where, int modifiers, NSEvent *theEvent){
5660 // sendMessage(getsym("mouseEndTrack"), 0, 0, 0);
5661 // if (modifiers & NSShiftKeyMask) {
5662 // mouseTrack(where, modifiers,theEvent);
5663 // }
5664 if(!mIsFixedSelection){
5665 if(mSelectedIndex >= 0){
5666 (&mEnvObj[mSelectedIndex])->mIsSelected = false;
5667 (&mEnvObj[mSelectedIndex])->mColor = (&mEnvObj[mSelectedIndex])->mObjectColor;
5668 mSelectedIndex = -1;
5669 refresh();
5673 if(mSelectedIndex >= 0)
5674 setValueFromPoint(where);
5676 mIsTracking = false;
5677 // mouseTrack(where, modifiers);
5679 void SCEnvelopeView::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
5681 //mPrevPoint = where;
5682 //mouseTrack(where, modifiers,theEvent);
5683 // NSLog(@"foo");
5686 void SCEnvelopeView::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
5688 if (modifiers & NSCommandKeyMask) {
5689 beginDrag(where);
5690 } else if (modifiers & NSShiftKeyMask) {
5692 setSelection(where, true, false);
5693 /* mActiveSize++;
5694 if(mActiveSize < mTabSize) {
5695 mSelectedIndex = mActiveSize - 1;
5696 mEnvObj[mSelectedIndex].mIsSelected = true;
5697 mEnvObj[mSelectedIndex].mIsStatic = false;
5698 }else {
5699 mActiveSize = mTabSize;
5702 refresh();
5703 //setVisibleSize();
5704 // setValueFromPoint(where);
5705 sendMessage(getsym("doAction"), 0, 0, 0);
5706 } else if (modifiers & NSControlKeyMask) {
5707 mAbsoluteX = where.x; //absolute y mouse position
5708 setSelection(where, false, true);
5709 sendMessage(getsym("doMetaAction"), 0, 0, 0);
5710 refresh();
5711 } else {
5712 if(!mIsFixedSelection && mSelectedIndex < 0)
5713 setSelection(where, false, false);
5715 if(mSelectedIndex >= 0) {
5716 if(!mIsTracking){
5717 mIsTracking = true;
5718 SCEnvObject selected = mEnvObj[mSelectedIndex];
5719 trackOffset = SCMakePoint(selected.mDrawPoint.x - where.x, selected.mDrawPoint.y - where.y);
5721 SCPoint location = SCMakePoint(trackOffset.x + where.x, trackOffset.y + where.y);
5722 setValueFromPoint(location);
5729 void SCEnvelopeView::setVisibleSize()
5733 float offset;
5734 float scaledsize;
5735 if(mThumbSize > 0.0) {
5736 if(mXOffset < 1.0) offset = 0;
5737 else offset = mXOffset;
5738 scaledsize = (float) (mTabSize - mStartIndex) * mThumbSize;
5739 if (scaledsize <= mBounds.width) mVisibleSize = mTabSize;
5740 else mVisibleSize = (int) mBounds.width / mThumbSize;
5741 } else {
5742 mVisibleSize = 0;
5745 mVisibleSize = mActiveSize;
5749 int SCEnvelopeView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
5751 int err;
5752 char *name = symbol->name;
5753 if (strcmp(name, "step")==0) {
5754 err = slotDoubleVal(slot, &mStepSize);
5755 if (!err) {
5756 mStepScale = 1. / mStepSize;
5757 bool changed = false;
5758 bool changedout = false;
5760 SCEnvObject * envob;
5761 for(int i=0; i<mTabSize; ++i){
5762 envob = mEnvObj+i;
5763 changed = setValue(envob,envob->x,envob->y, false);
5764 if(changed) changedout = changed;
5766 if(changedout) refresh();
5767 SetBool(slot, changedout);
5769 return errNone;
5772 if (strcmp(name, "thumbSize")==0) {
5773 if (!isKindOfSlot(slot, class_array)) return errWrongType;
5774 PyrSlot *slots = slotRawObject(slot)->slots;
5775 int err, idx;
5776 err = slotIntVal(slots+0, &idx);
5777 if (err) return err;
5778 err = slotIntVal(slots+1, &mThumbSize);
5779 mThumbSizeY = mThumbSize;
5780 if (err) return err;
5781 if(idx >= mTabSize) return errNone;
5782 if(idx < 0) {
5783 for(int i=0; i<mTabSize; i++){
5784 (mEnvObj+i)->mRect.width = mThumbSize;
5785 (mEnvObj+i)->mRect.height = mThumbSize;
5787 } else {
5788 (mEnvObj+idx)->mRect.width = mThumbSize;
5789 (mEnvObj+idx)->mRect.height = mThumbSize;
5791 refresh();
5792 return errNone;
5795 if (strcmp(name, "thumbWidth")==0) {
5796 if (!isKindOfSlot(slot, class_array)) return errWrongType;
5797 PyrSlot *slots = slotRawObject(slot)->slots;
5798 int err, idx;
5799 err = slotIntVal(slots+0, &idx);
5800 if (err) return err;
5801 err = slotIntVal(slots+1, &mThumbSize);
5802 if (err) return err;
5803 if(idx >= mTabSize) return errNone;
5804 if(idx < 0) {
5805 for(int i=0; i<mTabSize; i++){
5806 (mEnvObj+i)->mRect.width = mThumbSize;
5809 else
5810 (&mEnvObj[idx])->mRect.width = mThumbSize;
5811 refresh();
5812 return errNone;
5815 if (strcmp(name, "thumbHeight")==0) {
5816 if (!isKindOfSlot(slot, class_array)) return errWrongType;
5817 PyrSlot *slots = slotRawObject(slot)->slots;
5818 int err, idx;
5819 err = slotIntVal(slots+0, &idx);
5820 if (err) return err;
5821 err = slotIntVal(slots+1, &mThumbSizeY);
5822 if (err) return err;
5823 if(idx >= mTabSize) return errNone;
5824 if(idx < 0) {
5825 for(int i=0; i<mTabSize; i++){
5826 (mEnvObj+i)->mRect.height = mThumbSizeY;
5829 else
5830 (&mEnvObj[idx])->mRect.height = mThumbSizeY;
5831 refresh();
5832 return errNone;
5835 if (strcmp(name, "selectedIndex")==0) {
5836 int newSelection;
5837 SCEnvObject *obj;
5838 obj = mEnvObj+mSelectedIndex;
5839 err = slotIntVal(slot, &newSelection);
5840 if(err) return err;
5841 if(mSelectedIndex == newSelection) return errNone;
5843 if(mSelectedIndex >= 0) obj->mColor = obj->mObjectColor;
5844 mSelectedIndex = sc_clip(newSelection, -1, mTabSize-1);
5845 if(mSelectedIndex >= 0)
5847 obj = mEnvObj+mSelectedIndex;
5848 obj->mColor = mSelectedColor;
5849 mCurrentX = obj->x;
5850 mCurrentY = obj->y;
5853 refresh();
5854 return errNone;
5857 if (strcmp(name, "setFixedSelection")==0) {
5858 mIsFixedSelection = IsTrue(slot);
5859 return errNone;
5862 if (strcmp(name, "setIndex")==0) { //index selection without refresh() and color change.
5863 err = slotIntVal(slot, &mSelectedIndex);
5864 if(mSelectedIndex >= 0)
5865 mSelectedIndex = sc_clip(mSelectedIndex, 0, mTabSize-1);
5866 return errNone;
5868 if (strcmp(name, "connect")==0) { //if this is set all connection start in the middle of the rect
5870 if (!isKindOfSlot(slot, class_array)) return errWrongType;
5871 PyrSlot *slots = slotRawObject(slot)->slots;
5873 int err, idx;
5874 err = slotIntVal(slots+0, &idx);
5875 if (err) return err;
5876 if(idx >= mTabSize || idx < 0) return errIndexOutOfRange;
5877 SCEnvObject * envobj;
5878 PyrSlot *connections;
5879 connections = slots+1;
5880 if (!isKindOfSlot(connections, class_array)) return errWrongType;
5882 envobj = (mEnvObj + idx);
5883 err = allocSlotDoubleArrayVal(connections, &envobj->mConnections);
5884 //err = allocSlotIntArrayVal(slot, &(&mEnvObj[mSelectedIndex])->mConnections); //int array crashes sc
5885 envobj->mNumConnection = slotRawObject(connections)->size;
5886 // envobj->deltax = 0;
5887 // envobj->mConnectionInputs = 0;
5888 // envobj->mConnectionOutputs = 0;
5889 mDrawCenteredConnection = true;
5890 mIsEnvView = false;
5891 refresh();
5892 return errNone;
5895 if (strcmp(name, "fillColor")==0) {
5896 if (!isKindOfSlot(slot, class_array)) return errWrongType;
5897 PyrSlot *slots = slotRawObject(slot)->slots;
5899 int err, idx;
5900 err = slotIntVal(slots+0, &idx);
5901 if (err) return err;
5902 if(idx >= mTabSize) return errIndexOutOfRange;
5903 err = slotColorVal(slot+1, &mFillColor);
5904 if (err) return err;
5906 if(idx < 0) {
5907 for(int i=0; i<mTabSize; i++){
5908 (mEnvObj+i)->mColor = (mEnvObj+i)->mObjectColor = mFillColor;
5911 else
5912 (mEnvObj+idx)->mColor = (mEnvObj+idx)->mObjectColor = mFillColor;
5914 refresh();
5915 return errNone;
5917 if (strcmp(name, "strokeColor")==0) {
5918 err = slotColorVal(slot, &mStrokeColor);
5919 refresh();
5920 return errNone;
5922 if (strcmp(name, "selectionColor")==0) {
5923 err = slotColorVal(slot, &mSelectedColor);
5924 refresh();
5925 return errNone;
5928 if (strcmp(name, "startIndex")==0) {
5929 err = slotIntVal(slot, &mStartIndex);
5930 refresh();
5931 return errNone;
5933 if (strcmp(name, "editable")==0) {
5934 if (!isKindOfSlot(slot, class_array)) return errWrongType;
5935 PyrSlot *slots = slotRawObject(slot)->slots;
5937 int err, idx, editable;
5938 err = slotIntVal(slots+0, &idx);
5939 if (err) return err;
5940 if(idx >= mTabSize) return errIndexOutOfRange;
5941 editable = IsTrue(slots+1);
5942 if(idx < 0) {
5943 for(int i=0; i<mTabSize; i++){
5944 (mEnvObj + i)->mEditable = editable;
5947 else
5948 (mEnvObj + idx)->mEditable = editable;
5949 return errNone;
5951 if (strcmp(name, "drawLines")==0) {
5952 mDrawLinesActive = IsTrue(slot);
5953 refresh();
5954 return errNone;
5956 if (strcmp(name, "drawRects")==0) {
5957 mDrawRectsActive = IsTrue(slot);
5958 refresh();
5959 return errNone;
5961 if (strcmp(name, "string")==0) {
5962 if (!isKindOfSlot(slot, class_array)) return errWrongType;
5963 PyrSlot *slots = slotRawObject(slot)->slots;
5965 int err, idx;
5966 err = slotIntVal(slots+0, &idx);
5967 if (err) return err;
5968 if(idx >= mTabSize || idx < 0) return errIndexOutOfRange;
5969 PyrSlot *string = slots+1;
5971 err = allocSlotStrVal(string, &(&mEnvObj[idx])->mString);
5972 if (err) return err;
5973 refresh();
5974 return errNone;
5977 if (symbol == s_x) {
5978 double y;
5979 slotDoubleVal(slot, &mCurrentX);
5980 mCurrentX = sc_clip(mCurrentX, 0.0, 1.0);
5981 if(mSelectedIndex >= 0){
5982 y = (&mEnvObj[mSelectedIndex])->y;
5983 setEnvRect(mCurrentX, y,&mEnvObj[mSelectedIndex]);
5984 refresh();
5986 return errNone;
5988 if (symbol == s_y) {
5989 double x;
5990 slotDoubleVal(slot, &mCurrentY);
5991 mCurrentY = sc_clip(mCurrentY, 0.0, 1.0);
5992 if(mSelectedIndex >= 0){
5993 x = (&mEnvObj[mSelectedIndex])->x;
5994 setEnvRect(x, mCurrentY, &mEnvObj[mSelectedIndex]);
5995 refresh();
5997 return errNone;
5999 if (symbol == s_value) {
6000 if (!isKindOfSlot(slot, class_array)) return errWrongType;
6001 if (!isKindOfSlot(slotRawObject(slot)->slots+0, class_array)) return errWrongType;
6002 if (!isKindOfSlot(slotRawObject(slot)->slots+1, class_array)) return errWrongType;
6004 int size = slotRawObject(&(slotRawObject(slot)->slots[0]))->size;
6005 if(size != mTabSize) {
6006 // initialise drawing order
6007 if(drawOrder) {
6008 delete [] drawOrder;
6009 drawOrder = 0;
6011 if(size > 0){
6012 drawOrder = new int[size];
6013 for(int i=0; i<size; i++){
6014 drawOrder[i] = i;
6017 //this should keep the settings of the old ones ... maybe make a separate add action ...
6018 err = allocSlotEnvObjArray(slot, &mEnvObj);
6019 if(err) return err;
6020 mTabSize = size;
6022 //move this to allocslotEnvobjArray:
6023 double x, y;
6024 PyrDoubleArray * xarr;
6025 PyrDoubleArray * yarr;
6026 xarr = (PyrDoubleArray*)(slotRawObject(&slotRawObject(slot)->slots[0]));
6027 yarr = (PyrDoubleArray*)(slotRawObject(&slotRawObject(slot)->slots[1]));
6028 SCEnvObject * envob;
6029 for(int i=0; i<size; i++){
6030 envob = mEnvObj+i;
6031 x = xarr->d[i];
6032 y = yarr->d[i];
6033 setValue(envob,x,y, false);
6034 //post("set x: %f ,y: %f \n", x, y);
6036 mActiveSize = size;
6037 //setVisibleSize();
6040 refresh();
6042 return errNone;
6045 if (strcmp(name, "connectFrom")==0) {
6046 err = slotIntVal(slot, &mConnectFrom);
6047 return errNone;
6049 if (strcmp(name, "connectTo")==0) {
6050 err = slotIntVal(slot, &mConnectTo);
6051 return errNone;
6054 if (strcmp(name, "setGraphView")==0) {
6055 mDrawCenteredConnection = false;
6056 mIsEnvView = false;
6057 return errNone;
6059 // set curve for one segment or one curve type for all segments
6060 if (strcmp(name, "setCurve")==0) {
6061 if (!isKindOfSlot(slot, class_array)) return errWrongType;
6062 PyrSlot *slots = slotRawObject(slot)->slots;
6063 int err, idx, curve, shape;
6065 err = slotIntVal(slots+0, &idx);
6066 if (err) return err;
6068 err = slotIntVal(slots+1, &shape);
6069 if (err) return err;
6071 err = slotIntVal(slots+2, &curve);
6072 if (err) return err;
6074 if(idx >= mTabSize) return errNone;
6075 if(idx < 0) {
6076 for(int i=0; i<mTabSize; i++){
6077 (mEnvObj+i)->shape = shape;
6078 (mEnvObj+i)->curve = curve;
6080 } else {
6081 (mEnvObj+idx)->shape = shape;
6082 (mEnvObj+idx)->curve = curve;
6085 refresh();
6086 return errNone;
6088 // set curves for all segments
6089 if (strcmp(name, "setCurves")==0) {
6090 if (!isKindOfSlot(slot, class_array)) return errWrongType;
6091 int size = slotRawObject(slot)->size;
6092 size = sc_clip(size, 0, mTabSize);
6093 for(int i=0; i<size; i++)
6095 PyrSlot * shapeCurveSlot = slotRawObject(slot)->slots+i;
6096 int shape;
6097 float curve;
6098 if(isKindOfSlot(shapeCurveSlot, class_array))
6100 int err = slotIntVal(slotRawObject(shapeCurveSlot)->slots+0, &shape);
6101 if (err) return err;
6102 err = slotFloatVal(slotRawObject(shapeCurveSlot)->slots+1, &curve);
6103 if (err) return err;
6104 (mEnvObj+i)->shape = shape;
6105 (mEnvObj+i)->curve = curve;
6108 refresh();
6109 return errNone;
6112 if (strcmp(name, "showGrid")==0) {
6113 mGridOn = IsTrue(slot);
6114 refresh();
6115 return errNone;
6118 if (strcmp(name, "setGrid")==0) {
6119 if (!isKindOfSlot(slot, class_array)) return errWrongType;
6120 err = slotFloatVal(slotRawObject(slot)->slots+0, &mGrid.x);
6121 if (err) return err;
6122 err = slotFloatVal(slotRawObject(slot)->slots+1, &mGrid.y);
6123 if(mGridOn) refresh();
6124 return errNone;
6127 if (strcmp(name, "setGridColor")==0) {
6128 err = slotColorVal(slot, &mGridColor);
6129 if(mGridOn) refresh();
6130 return errNone;
6133 if (strcmp(name, "selectionSize")==0) {
6134 slotIntVal(slot, &mSelectionSize);
6135 refresh();
6136 return errNone;
6140 return SCView::setProperty(symbol, slot);
6143 int SCEnvelopeView::getProperty(PyrSymbol *symbol, PyrSlot *slot)
6146 char *name = symbol->name;
6147 if (strcmp(name, "step")==0) {
6148 SetFloat(slot, mStepSize);
6149 return errNone;
6152 if (symbol == s_x) {
6153 if(mSelectedIndex >= 0){
6154 SetFloat(slot, mCurrentX);
6155 } else {
6156 SetNil(slot);
6158 return errNone;
6160 if (symbol == s_y) {
6161 if(mSelectedIndex >= 0){
6162 SetFloat(slot, mCurrentY);
6163 } else {
6164 SetNil(slot);
6166 return errNone;
6168 if (strcmp(name, "selectedIndex")==0) {
6169 SetInt(slot, (int) mSelectedIndex);
6170 return errNone;
6172 if (strcmp(name, "lastIndex")==0) {
6173 SetInt(slot, (int) mLastIndex);
6174 return errNone;
6177 if (symbol == s_value) {
6178 if (!isKindOfSlot(slot, class_array)) return errWrongType;
6179 int size = slotRawObject(&(slotRawObject(slot)->slots[0]))->size;
6180 SCEnvObject * envo;
6181 if(size > mTabSize) size = mTabSize;
6183 PyrDoubleArray * xarr;
6184 PyrDoubleArray * yarr;
6185 xarr = (PyrDoubleArray*)(slotRawObject(&slotRawObject(slot)->slots[0]));
6186 yarr = (PyrDoubleArray*)(slotRawObject(&slotRawObject(slot)->slots[1]));
6188 for(int i=0; i<size; i++){
6189 envo = &mEnvObj[i];
6190 xarr->d[i] = envo->x;
6191 yarr->d[i] = envo->y;
6193 return errNone;
6196 if (strcmp(name, "selectionSize")==0) {
6197 SetInt(slot, mSelectionSize);
6198 return errNone;
6201 if (strcmp(name, "absoluteX")==0) {
6202 SetInt(slot, (int) mAbsoluteX);
6203 return errNone;
6206 if (strcmp(name, "connectFrom")==0) {
6207 SetInt(slot, (int) mConnectFrom);
6208 return errNone;
6210 if (strcmp(name, "connectTo")==0) {
6211 SetInt(slot, (int) mConnectTo);
6212 return errNone;
6215 return SCView::getProperty(symbol, slot);
6218 bool SCEnvelopeView::canReceiveDrag()
6220 PyrSlot result;
6221 sendMessage(s_canReceiveDrag, 0, 0, &result);
6222 return IsTrue(&result);
6225 void SCEnvelopeView::receiveDrag()
6227 sendMessage(s_receiveDrag, 0, 0, 0);
6231 ////////////////////////////////////////////////
6233 SCView* NewSCNumberBoxOld(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
6235 return new SCNumberBoxOld(inParent, inObj, inBounds);
6238 SCNumberBoxOld::SCNumberBoxOld(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
6239 : SCStaticText(inParent, inObj, inBounds)
6241 mBackground = new SolidColorBackground(SCMakeColor(1.0,1.0,1.0, 1.0)); // default is white
6242 mEnabled = true;
6243 mCanFocus = true;
6246 SCNumberBoxOld::~SCNumberBoxOld()
6250 bool SCNumberBoxOld::shouldDim()
6252 return true;
6255 void SCNumberBoxOld::draw(SCRect inDamage)
6257 SCView::draw(inDamage);
6258 SCRect bounds = getDrawBounds();
6260 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
6261 CGContextSaveGState(cgc);
6262 CGRect rect = SCtoCGRect(bounds);
6263 if (mBackground) mBackground->draw(cgc, rect);
6265 QDDrawBevelRect(cgc, rect, 1, true);
6266 CGContextRestoreGState(cgc);
6268 //drawBevelRect(SCtoQDRect(mBounds), 1, 1, SCtoQDColor(mBackColor), 2);
6269 SCRect sbounds = bounds;
6271 sbounds.x += 2;
6272 sbounds.width -= 4;
6273 drawString(sbounds);
6276 //int SCNumberBoxOld::setProperty(PyrSymbol *symbol, PyrSlot *slot)
6278 // int err;
6279 // char *name = symbol->name;
6280 // if (strcmp(name, "boxColor")==0) {
6281 // err = slotColorVal(slot, &mBoxColor);
6282 // if (err) return err;
6283 // refresh();
6284 // return errNone;
6285 // }
6286 // return SCStaticText::setProperty(symbol, slot);
6289 void SCNumberBoxOld::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
6291 if (modifiers & NSCommandKeyMask) {
6292 beginDrag(where);
6296 //int SCNumberBoxOld::getProperty(PyrSymbol *symbol, PyrSlot *slot)
6298 // char *name = symbol->name;
6299 // if (strcmp(name, "boxColor")==0) {
6300 // return setSlotColor(slot, &mBoxColor);
6301 // }
6302 // return SCStaticText::getProperty(symbol, slot);
6305 bool SCNumberBoxOld::canReceiveDrag()
6307 PyrSlot result;
6308 sendMessage(s_canReceiveDrag, 0, 0, &result);
6309 return IsTrue(&result);
6312 void SCNumberBoxOld::receiveDrag()
6314 sendMessage(s_receiveDrag, 0, 0, 0);
6317 ////////////////////////////////////////////////
6320 SCView* NewSCDragSource(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
6322 return new SCDragSource(inParent, inObj, inBounds);
6325 SCDragSource::SCDragSource(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
6326 : SCStaticText(inParent, inObj, inBounds)
6328 mEnabled = true;
6331 SCDragSource::~SCDragSource()
6335 void SCDragSource::draw(SCRect inDamage)
6337 SCView::draw(inDamage);
6338 SCRect bounds = getDrawBounds();
6340 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
6341 CGContextSaveGState(cgc);
6342 CGRect rect = SCtoCGRect(bounds);
6343 if (mBackground) mBackground->draw(cgc, rect);
6344 QDDrawBevelRect(cgc, rect, 1, false);
6345 CGContextRestoreGState(cgc);
6347 //drawBevelRect(SCtoQDRect(mBounds), 1, 0, SCtoQDColor(mBackColor), 2);
6348 drawString(bounds);
6351 bool SCDragSource::shouldDim()
6353 return true;
6356 int ivxSCDragSource_object;
6358 void SCDragSource::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
6360 beginDrag(where);
6363 ////////////////////////////////////////////////
6366 SCView* NewSCDragSink(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
6368 return new SCDragSink(inParent, inObj, inBounds);
6371 SCDragSink::SCDragSink(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
6372 : SCStaticText(inParent, inObj, inBounds)
6374 mEnabled = true;
6377 SCDragSink::~SCDragSink()
6381 void SCDragSink::draw(SCRect inDamage)
6383 SCView::draw(inDamage);
6384 SCRect bounds = getDrawBounds();
6386 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
6387 CGContextSaveGState(cgc);
6388 CGRect rect = SCtoCGRect(bounds);
6389 if (mBackground) mBackground->draw(cgc, rect);
6390 QDDrawBevelRect(cgc, rect, 1, true);
6391 CGContextRestoreGState(cgc);
6393 //drawBevelRect(SCtoQDRect(mBounds), 1, 1, SCtoQDColor(mBackColor), 2);
6394 drawString(bounds);
6397 bool SCDragSink::shouldDim()
6399 return true;
6402 bool SCDragSink::canReceiveDrag()
6404 PyrSlot result;
6405 sendMessage(s_canReceiveDrag, 0, 0, &result);
6406 return IsTrue(&result);
6409 void SCDragSink::receiveDrag()
6411 sendMessage(s_receiveDrag, 0, 0, 0);
6414 ////////////////////////////////////////////////
6415 ////////////////////////////////////////////////
6418 SCView* NewSCDragBoth(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
6420 return new SCDragBoth(inParent, inObj, inBounds);
6423 SCDragBoth::SCDragBoth(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
6424 : SCDragSink(inParent, inObj, inBounds)
6428 void SCDragBoth::draw(SCRect inDamage)
6430 SCView::draw(inDamage);
6432 CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
6433 CGContextSaveGState(cgc);
6434 SCRect dbounds = getDrawBounds();
6436 CGRect rect = SCtoCGRect(dbounds);
6437 if (mBackground) mBackground->draw(cgc, rect);
6438 QDDrawBevelRect(cgc, rect, 1, true);
6439 SCRect bounds = dbounds;
6440 bounds.x += 2; bounds.y += 2; bounds.width -= 4; bounds.height -= 4;
6441 QDDrawBevelRect(cgc, SCtoCGRect(bounds), 1, false);
6442 CGContextRestoreGState(cgc);
6444 //drawBevelRect(SCtoQDRect(bounds), 1, 1, SCtoQDColor(mBackColor), 2);
6445 //SCRect bounds = bounds;
6446 //bounds.x += 2; bounds.y += 2; bounds.width -= 4; bounds.height -= 4;
6447 //drawBevelRect(SCtoQDRect(bounds), 1, 0, SCtoQDColor(mBackColor), 2);
6448 drawString(bounds);
6451 int ivxSCDragBoth_object;
6453 void SCDragBoth::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
6455 beginDrag(where);
6459 ////////////////////////////////////////////////
6460 #import "TabletEvents.h"
6462 SCView* NewSCTabletView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
6464 return new SCTabletView(inParent, inObj, inBounds);
6467 SCTabletView::SCTabletView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
6468 : SCView(inParent, inObj, inBounds), mClipToBounds(1)
6472 SCTabletView::~SCTabletView()
6476 int SCTabletView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
6478 char *name = symbol->name;
6479 if (strcmp(name, "clipToBounds")==0) {
6480 slotIntVal(slot, &mClipToBounds);
6481 return errNone;
6483 return SCView::setProperty(symbol, slot);
6486 void SCTabletView::mouseBeginTrack(SCPoint where, int modifiers, NSEvent *theEvent)
6488 float x,y;
6489 SCRect bounds = getDrawBounds();
6491 if (modifiers & NSCommandKeyMask) {
6492 beginDrag(where);
6493 } else {
6494 x = where.x - bounds.x;
6495 y = where.y - bounds.y;
6496 if(mClipToBounds) {
6497 x = sc_clip(x,0.,bounds.width);
6498 y = sc_clip(y,0.,bounds.height);
6500 TABLETTRACK(s_mouseDown,x,y)
6504 void SCTabletView::mouseTrack(SCPoint where, int modifiers, NSEvent *theEvent)
6506 float x,y;
6507 SCRect bounds = getDrawBounds();
6509 if (! (modifiers & NSCommandKeyMask)) {
6510 x = where.x - bounds.x;
6511 y = where.y - bounds.y;
6512 if(mClipToBounds) {
6513 x = sc_clip(x,0.,bounds.width);
6514 y = sc_clip(y,0.,bounds.height);
6516 TABLETTRACK(s_doaction,x,y)
6520 void SCTabletView::mouseEndTrack(SCPoint where, int modifiers, NSEvent *theEvent)
6522 float x,y;
6523 if (modifiers & NSCommandKeyMask) {
6524 this->receiveDrag();
6525 } else {
6526 SCRect bounds = getDrawBounds();
6528 x = where.x - bounds.x;
6529 y = where.y - bounds.y;
6530 if(mClipToBounds) {
6531 x = sc_clip(x,0.,bounds.width);
6532 y = sc_clip(y,0.,bounds.height);
6534 TABLETTRACK(s_mouseUp,x,y)
6538 void SCTabletView::mouseDownAction(SCPoint where, int modifiers, NSEvent *theEvent)
6542 void SCTabletView::mouseMoveAction(SCPoint where, int modifiers, NSEvent *theEvent)
6546 void SCTabletView::mouseUpAction(SCPoint where, int modifiers, NSEvent *theEvent)
6551 ////////////////////////////////////////////////
6553 SCViewMaker::SCViewMaker(const char* inName, SCViewCtor inCtor)
6554 : mNext(gSCViewMakers), mCtor(inCtor), mName(inName)
6556 gSCViewMakers = this;
6559 SCView* MakeSCView(PyrObject* inObj, SCContainerView *inParent, SCRect inBounds,const char *classname)
6561 SCViewMaker* maker = gSCViewMakers;
6562 while (maker) {
6563 if (strcmp(classname, maker->mName) == 0) {
6564 return (maker->mCtor)(inParent, inObj, inBounds);
6566 maker = maker->mNext;
6568 return 0;
6571 static bool sRegisteredSCViewClasses = false;
6572 extern SCView* NewSCSoundFileView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds);
6573 extern SCView* NewSCCocoaTextView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds);
6574 extern SCView* NewSCMovieView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds);
6575 extern SCView* NewSCQuartzComposerView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds);
6576 extern SCView* NewSCWebView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds);
6577 extern SCView* NewSCTextField(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds);
6578 extern SCView* NewSCNumberBox(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds);
6579 extern SCView* NewSCLevelIndicator(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds);
6581 void registerSCViewClasses()
6583 if (sRegisteredSCViewClasses) return;
6584 sRegisteredSCViewClasses = true;
6586 new SCViewMaker("SCTopView", NewSCTopView);
6587 new SCViewMaker("SCCompositeView", NewSCCompositeView);
6588 new SCViewMaker("SCHLayoutView", NewSCHLayoutView);
6589 new SCViewMaker("SCVLayoutView", NewSCVLayoutView);
6590 new SCViewMaker("SCSlider", NewSCSlider);
6591 new SCViewMaker("SCRangeSlider", NewSCRangeSlider);
6592 new SCViewMaker("SC2DSlider", NewSC2DSlider);
6593 new SCViewMaker("SC2DTabletSlider", NewSC2DTabletSlider);
6594 new SCViewMaker("SCButton", NewSCButton);
6595 new SCViewMaker("SCStaticText", NewSCStaticText);
6596 new SCViewMaker("SCNumberBoxOld", NewSCNumberBoxOld);
6597 new SCViewMaker("SCDragSource", NewSCDragSource);
6598 new SCViewMaker("SCDragSink", NewSCDragSink);
6599 new SCViewMaker("SCDragBoth", NewSCDragBoth);
6600 new SCViewMaker("SCUserView", NewSCUserView);
6601 new SCViewMaker("SCPopUpMenu", NewSCPopUpMenu);
6602 new SCViewMaker("SCMultiSliderView", NewSCMultiSliderView);
6603 new SCViewMaker("SCEnvelopeView", NewSCEnvelopeView);
6604 new SCViewMaker("SCTabletView", NewSCTabletView);
6605 new SCViewMaker("SCScope", NewSCScope);
6606 new SCViewMaker("SCListView", NewSCListView);
6607 new SCViewMaker("SCSoundFileView", NewSCSoundFileView);
6608 //these can be found in SCCocoaView.M
6609 new SCViewMaker("SCTextView", NewSCCocoaTextView);
6610 new SCViewMaker("SCMovieView", NewSCMovieView);
6611 new SCViewMaker("SCQuartzComposerView", NewSCQuartzComposerView);
6612 new SCViewMaker("SCWebView", NewSCWebView);
6613 new SCViewMaker("SCTextField", NewSCTextField);
6614 new SCViewMaker("SCNumberBox", NewSCNumberBox);
6615 new SCViewMaker("SCScrollTopView", NewSCScrollTopView);
6616 new SCViewMaker("SCScrollView", NewSCScrollView);
6617 new SCViewMaker("SCLevelIndicator", NewSCLevelIndicator);
6622 int prSCView_New(struct VMGlobals *g, int numArgsPushed);
6623 int prSCView_New(struct VMGlobals *g, int numArgsPushed)
6625 if (!g->canCallOS) return errCantCallOS;
6627 PyrSlot *args = g->sp - 3;
6628 // view, parent, bounds, viewclass
6629 PyrSlot parentSlot;
6630 SCContainerView *parent;
6631 if (isKindOfSlot(args, s_sctopview->u.classobj) && !isKindOfSlot(args, s_scscrollview->u.classobj)) {
6632 parent = 0;
6633 } else {
6634 if (!isKindOfSlot(args+1, s_sccontview->u.classobj)) return errWrongType;
6635 // check if it still has a dataptr
6636 parentSlot = slotRawObject(&args[1])->slots[0];
6637 if(IsNil(&parentSlot)) return errFailed;
6638 parent = (SCContainerView*)slotRawPtr(&parentSlot);
6640 if (!(isKindOfSlot(args+2, s_rect->u.classobj))) return errWrongType;
6642 SCRect bounds;
6643 int err = slotGetSCRect(args+2, &bounds);
6644 if (err) return err;
6645 SCView *view = MakeSCView(slotRawObject(&args[0]), parent, bounds, slotRawSymbol(&slotRawClass(&args[3])->name)->name);
6646 if (!view) return errFailed;
6648 return errNone;
6651 int prSCView_SetProperty(struct VMGlobals *g, int numArgsPushed);
6652 int prSCView_SetProperty(struct VMGlobals *g, int numArgsPushed)
6654 if (!g->canCallOS) return errCantCallOS;
6656 PyrSlot *args = g->sp - 2;
6658 if (!IsSym(args+1)) return errWrongType;
6660 SCView *view = (SCView*)slotRawPtr(slotRawObject(&args[0])->slots);
6661 if (!view) return errFailed;
6663 int err = view->setProperty(slotRawSymbol(&args[1]), args+2);
6664 if (err) SetNil(args+2);
6666 slotCopy(&args[0], &args[2]);
6668 return err;
6671 int prSCView_GetProperty(struct VMGlobals *g, int numArgsPushed);
6672 int prSCView_GetProperty(struct VMGlobals *g, int numArgsPushed)
6674 if (!g->canCallOS) return errCantCallOS;
6676 PyrSlot *args = g->sp - 2;
6678 if (!IsSym(args+1)) return errWrongType;
6680 SCView *view = (SCView*)slotRawPtr(slotRawObject(&args[0])->slots);
6681 if (!view) return errFailed;
6683 int err = view->getProperty(slotRawSymbol(&args[1]), args+2);
6684 if (err) SetNil(args+2);
6686 slotCopy(&args[0], &args[2]);
6688 return errNone;
6691 int prSCView_FindByID(struct VMGlobals *g, int numArgsPushed);
6692 int prSCView_FindByID(struct VMGlobals *g, int numArgsPushed)
6694 if (!g->canCallOS) return errCantCallOS;
6696 PyrSlot *a = g->sp - 1;
6697 PyrSlot *b = g->sp;
6699 SCView *view = (SCView*)slotRawPtr(slotRawObject(a)->slots);
6700 if (!view) return errFailed;
6702 int32 tag;
6703 int err = slotIntVal(b, &tag);
6704 if (err) return err;
6706 view = view->findViewByID(tag);
6707 if (!view) {
6708 SetNil(a);
6709 } else {
6710 SetObjectOrNil(a, view->GetSCObj());
6713 return errNone;
6716 int prSCView_Focus(struct VMGlobals *g, int numArgsPushed);
6717 int prSCView_Focus(struct VMGlobals *g, int numArgsPushed)
6719 if (!g->canCallOS) return errCantCallOS;
6721 PyrSlot *viewObjSlot = g->sp - 1;
6722 SCView *view = (SCView*)slotRawPtr(slotRawObject(&viewObjSlot[0])->slots);
6723 PyrSlot *boo = g->sp;
6725 if (!view) return errFailed;
6726 view->makeFocus(IsTrue(boo));
6727 return errNone;
6730 int prSCView_HasFocus(struct VMGlobals *g, int numArgsPushed);
6731 int prSCView_HasFocus(struct VMGlobals *g, int numArgsPushed)
6733 if (!g->canCallOS) return errCantCallOS;
6735 PyrSlot *viewObjSlot = g->sp;
6736 SCView *view = (SCView*)slotRawPtr(slotRawObject(&viewObjSlot[0])->slots);
6738 if (!view) return errFailed;
6739 SetBool(viewObjSlot, view->isFocus());
6740 return errNone;
6743 int prSCView_Refresh(struct VMGlobals *g, int numArgsPushed);
6744 int prSCView_Refresh(struct VMGlobals *g, int numArgsPushed)
6746 if (!g->canCallOS) return errCantCallOS;
6748 if(::IsNil( slotRawObject(g->sp)->slots+0 ))
6749 return errFailed;
6751 SCView *view = (SCView*)slotRawPtr(slotRawObject(g->sp)->slots);
6752 if(!view) return errNone;
6753 view->refresh();
6754 return errNone;
6757 int prSCView_RefreshInRect(struct VMGlobals *g, int numArgsPushed);
6758 int prSCView_RefreshInRect(struct VMGlobals *g, int numArgsPushed)
6760 if (!g->canCallOS) return errCantCallOS;
6762 if(::IsNil( slotRawObject(g->sp - 1)->slots+0 ))
6763 return errFailed;
6765 SCRect r;
6766 SCView *view = (SCView*)slotRawPtr(slotRawObject(g->sp - 1)->slots);
6768 if(slotGetSCRect(g->sp, &r) != noErr)
6769 return errFailed;
6771 view->refreshInRect(r);
6772 return errNone;
6775 int prSCView_Remove(struct VMGlobals *g, int numArgsPushed);
6776 int prSCView_Remove(struct VMGlobals *g, int numArgsPushed)
6778 //if (!g->canCallOS) return errCantCallOS;
6780 PyrSlot *viewObjSlot = g->sp;
6781 SCView *view = (SCView*)slotRawPtr(slotRawObject(viewObjSlot)->slots);
6782 if (!view) return errFailed;
6784 // removes from parent, set mObj to nil
6785 delete view;
6786 return errNone;
6789 void initSCViewPrimitives()
6792 registerSCViewClasses();
6794 int base, index;
6796 s_x = getsym("x");
6797 s_y = getsym("y");
6798 s_lo = getsym("lo");
6799 s_hi = getsym("hi");
6800 s_range = getsym("range");
6801 s_scview = getsym("SCView");
6802 s_sccontview = getsym("SCContainerView");
6803 s_sctopview = getsym("SCTopView");
6804 s_scscrollview = getsym("SCScrollView");
6805 s_beginDrag = getsym("beginDrag");
6806 s_receiveDrag = getsym("receiveDrag");
6807 s_canReceiveDrag = getsym("canReceiveDrag");
6808 s_mouseDown = getsym("mouseDown");
6809 s_mouseUp = getsym("mouseUp");
6810 s_callDrawFunc = getsym("callDrawFunc");
6811 s_toggleEditMode = getsym("toggleEditMode");
6813 base = nextPrimitiveIndex();
6814 index = 0;
6816 definePrimitive(base, index++, "_SCView_New", prSCView_New, 4, 0);
6817 definePrimitive(base, index++, "_SCView_SetProperty", prSCView_SetProperty, 3, 0);
6818 definePrimitive(base, index++, "_SCView_GetProperty", prSCView_GetProperty, 3, 0);
6819 definePrimitive(base, index++, "_SCView_FindByID", prSCView_FindByID, 2, 0);
6820 definePrimitive(base, index++, "_SCView_Focus", prSCView_Focus, 2, 0);
6821 definePrimitive(base, index++, "_SCView_HasFocus", prSCView_HasFocus, 1, 0);
6822 definePrimitive(base, index++, "_SCView_Refresh", prSCView_Refresh, 1, 0);
6823 definePrimitive(base, index++, "_SCView_Remove", prSCView_Remove, 1, 0);
6824 definePrimitive(base, index++, "_SCView_RefreshInRect", prSCView_RefreshInRect, 2, 0);
6827 int ivxSCTextView_linkAction;
6829 void initGUI();
6830 void initGUI()
6832 ivxSCDragSource_object = instVarOffset("SCDragSource", "object");
6833 ivxSCDragBoth_object = instVarOffset("SCDragBoth", "object");
6834 ivxSCTextView_linkAction = instVarOffset("SCTextView", "linkAction");
6840 loose ends
6841 drag/drop views
6842 background color / pic
6844 new views
6845 larger text view
6846 scope view
6847 plot view
6848 graph limits
6849 grid on/off
6850 data 1d, 2d
6851 color
6852 hdivider
6853 vdivider
6854 overlay view