2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <UIKit/UIKit.h>
24 #include "PyrPrimitive.h"
25 #include "PyrObject.h"
26 #include "PyrKernel.h"
27 #include "PyrSymbol.h"
29 #include "VMGlobals.h"
32 #include "SC_BoundsMacros.h"
33 #include "SC_InlineBinaryOp.h"
34 #include "iPhoneSCGraphView.h"
37 #include "iPhoneSCView.h"
40 void QDDrawBevelRect(CGContextRef cgc, CGRect bounds, float width, bool inout);
42 SCViewMaker *gSCViewMakers = 0;
43 SCView *gAnimatedViews = 0;
45 extern PyrSymbol* s_color;
46 extern PyrSymbol* s_doaction;
47 extern PyrSymbol* s_draw;
55 PyrSymbol* s_sccontview;
56 PyrSymbol* s_sctopview;
57 PyrSymbol* s_scscrollview;
58 PyrSymbol* s_beginDrag;
59 PyrSymbol* s_receiveDrag;
60 PyrSymbol* s_canReceiveDrag;
61 PyrSymbol* s_mouseDown;
63 PyrSymbol* s_callDrawFunc;
64 PyrSymbol* s_toggleEditMode;
66 extern pthread_mutex_t gLangMutex;
68 int stringDrawCenteredInRect(char *cString, SCRect screct, char *cFontName, float fontSize, SCColor sccolor);
69 int stringDrawLeftInRect(char *cString, SCRect screct, char *cFontName, float fontSize, SCColor sccolor);
70 int stringDrawRightInRect(char *cString, SCRect screct, char *cFontName, float fontSize, SCColor sccolor);
72 int nsStringDrawInRectAlign(NSString *nsstring, SCRect screct, char *cFontName, float fontSize, SCColor sccolor, int hAlign, int vAlign, CGSize *outSize);
75 // CoreGraphics coords get switched around in an NSQuickDrawView
76 Rect SCtoQDRect(SCRect screct)
80 qdrect.left = (int)screct.x;
81 qdrect.top = (int)screct.y;
82 qdrect.right = (int)(screct.x + screct.width);
83 qdrect.bottom = (int)(screct.y + screct.height);
87 CGRect SCtoCGRect(SCRect screct)
91 cgrect.origin.x = screct.x;
92 cgrect.origin.y = screct.y;
93 cgrect.size.width = screct.width;
94 cgrect.size.height = screct.height;
98 int slotColorVal(PyrSlot *slot, SCColor *sccolor)
100 if (!(isKindOfSlot(slot, s_color->u.classobj))) return errWrongType;
102 PyrSlot *slots = slotRawObject(slot)->slots;
105 err = slotFloatVal(slots+0, &sccolor->red);
107 err = slotFloatVal(slots+1, &sccolor->green);
109 err = slotFloatVal(slots+2, &sccolor->blue);
111 err = slotFloatVal(slots+3, &sccolor->alpha);
115 int setSlotColor(PyrSlot *slot, SCColor *sccolor)
117 if (!(isKindOfSlot(slot, s_color->u.classobj))) return errWrongType;
119 PyrSlot *slots = slotRawObject(slot)->slots;
121 SetFloat(slots+0, sccolor->red);
122 SetFloat(slots+1, sccolor->green);
123 SetFloat(slots+2, sccolor->blue);
124 SetFloat(slots+3, sccolor->alpha);
128 int slotGetSCRect(PyrSlot* a, SCRect *r)
130 if (!isKindOfSlot(a, s_rect->u.classobj)) return errWrongType; // arg check - br
131 PyrSlot *slots = slotRawObject(a)->slots;
133 err = slotFloatVal(slots+0, &r->x);
135 err = slotFloatVal(slots+1, &r->y);
137 err = slotFloatVal(slots+2, &r->width);
139 err = slotFloatVal(slots+3, &r->height);
146 int getBackgroundVal(PyrSlot *slot, DrawBackground *inPtr);
147 int getBackgroundVal(PyrSlot *slot, DrawBackground *inPtr)
150 //inPtr->GetSlot(slot);
154 int slotBackgroundVal(PyrSlot *slot, DrawBackground **ioPtr);
155 int slotBackgroundVal(PyrSlot *slot, DrawBackground **ioPtr)
157 int err, direction, steps;
158 SCColor color1, color2;
159 PyrClass *classobj = classOfSlot(slot);
160 char *classname = slotRawSymbol(&classobj->name)->name;
162 if (strcmp(classname, "Color")==0) {
163 err = slotColorVal(slot, &color1);
167 *ioPtr = new SolidColorBackground(color1);
168 } else if (strcmp(classname, "Gradient") == 0) {
169 PyrObject *obj = slotRawObject(slot);
170 PyrSlot *slots = obj->slots;
172 err = slotColorVal(slots+0, &color1);
174 err = slotColorVal(slots+1, &color2);
177 if (IsSym(slots+2)) {
178 if (strncmp(slotRawSymbol(&slots[2])->name, "h", 1)==0) direction = grad_Horizontal;
179 else if (strncmp(slotRawSymbol(&slots[2])->name, "v", 1)==0) direction = grad_Vertical;
180 else if (strncmp(slotRawSymbol(&slots[2])->name, "n", 1)==0) direction = grad_Narrow;
181 else if (strncmp(slotRawSymbol(&slots[2])->name, "w", 1)==0) direction = grad_Wide;
182 else direction = grad_Vertical;
184 direction = grad_Horizontal;
187 err = slotIntVal(slots+3, &steps);
191 *ioPtr = new GradientBackground(color1, color2, direction, steps);
193 } else if (strcmp(classname, "HiliteGradient") == 0) {
194 PyrObject *obj = slotRawObject(slot);
195 PyrSlot *slots = obj->slots;
197 err = slotColorVal(slots+0, &color1);
199 err = slotColorVal(slots+1, &color2);
202 if (IsSym(slots+2)) {
203 if (strncmp(slotRawSymbol(&slots[2])->name, "h", 1)==0) direction = grad_Horizontal;
204 else if (strncmp(slotRawSymbol(&slots[2])->name, "v", 1)==0) direction = grad_Vertical;
205 else if (strncmp(slotRawSymbol(&slots[2])->name, "n", 1)==0) direction = grad_Narrow;
206 else if (strncmp(slotRawSymbol(&slots[2])->name, "w", 1)==0) direction = grad_Wide;
207 else direction = grad_Vertical;
209 direction = grad_Horizontal;
212 err = slotIntVal(slots+3, &steps);
216 err = slotFloatVal(slots+4, &frac);
220 *ioPtr = new HiliteGradientBackground(color1, color2, direction, steps, frac);
229 : mMinWidth(0.), mMaxWidth(10000.), mMinHeight(0.), mMaxHeight(10000.), mWeight(1.),
230 mShouldResize(true), mHResize(layout_FixedLeft), mVResize(layout_FixedTop) {
233 SCView::SCView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
234 : mNext(0), mNextAnimatedView(0), mPrevAnimatedView(0),
235 mParent(0), mTop(0), mObj(inObj), mBounds(inBounds),
236 mBackground(0), mBackgroundImage(0), mVisible(true), mEnabled(true),
237 mCanFocus(true), mDragHilite(false),
238 mConstructionMode(-1), mDragLabel(0)
240 mFocusColor = SCMakeColor(0.0,0.0,0.0, 0.5);
244 if(inParent->relativeOrigin()){
245 SCRect pbounds = inParent->getLayout().bounds;
246 mLayout.bounds.x = mBounds.x + pbounds.x;
247 mLayout.bounds.y = mBounds.y + pbounds.y;
248 mLayout.bounds.width = mBounds.width;
249 mLayout.bounds.height = mBounds.height;
251 mLayout.bounds = mBounds;
254 // store myself into sc object.
255 if (mObj) SetPtr(mObj->slots+0, this);
262 mTop->forgetView(this);
263 if (mParent) mParent->remove(this);
264 if (mObj) SetNil(mObj->slots+0);
267 delete mBackgroundImage;
273 void SCView::startAnimation()
275 mNextAnimatedView = gAnimatedViews;
276 if (mNextAnimatedView) mNextAnimatedView->mPrevAnimatedView = this;
277 mPrevAnimatedView = 0;
278 gAnimatedViews = this;
281 void SCView::stopAnimation()
283 SCView *nextAnim = mNextAnimatedView;
284 SCView *prevAnim = mPrevAnimatedView;
285 if (nextAnim) nextAnim->mPrevAnimatedView = prevAnim;
286 if (prevAnim) prevAnim->mNextAnimatedView = nextAnim;
287 else if (gAnimatedViews == this) gAnimatedViews = nextAnim;
288 mPrevAnimatedView = mNextAnimatedView = 0;
292 bool SCView::hit(SCPoint where) const
294 SCRect bounds = mLayout.bounds;
295 return SCPointInRect(where, bounds);
298 void SCView::keyDown(int character, int modifiers, unsigned short keycode)
300 pthread_mutex_lock (&gLangMutex);
301 PyrSymbol *method = getsym("keyDown");
303 VMGlobals *g = gMainVMGlobals;
305 ++g->sp; SetObject(g->sp, mObj);
306 ++g->sp; SetChar(g->sp, character);
307 ++g->sp; SetInt(g->sp, modifiers);
308 ++g->sp; SetInt(g->sp, character);
309 ++g->sp; SetInt(g->sp, keycode);
310 runInterpreter(g, method, 5);
311 g->canCallOS = false;
313 pthread_mutex_unlock (&gLangMutex);
316 void SCView::keyUp(int character, int modifiers, unsigned short keycode)
318 pthread_mutex_lock (&gLangMutex);
319 PyrSymbol *method = getsym("keyUp");
321 VMGlobals *g = gMainVMGlobals;
323 ++g->sp; SetObject(g->sp, mObj);
324 ++g->sp; SetChar(g->sp, character);
325 ++g->sp; SetInt(g->sp, modifiers);
326 ++g->sp; SetInt(g->sp, character);
327 ++g->sp; SetInt(g->sp, keycode);
328 runInterpreter(g, method, 5);
329 g->canCallOS = false;
331 pthread_mutex_unlock (&gLangMutex);
334 void SCView::keyModifiersChanged(int modifiers)
336 pthread_mutex_lock (&gLangMutex);
337 PyrSymbol *method = getsym("keyModifiersChanged");
339 VMGlobals *g = gMainVMGlobals;
341 ++g->sp; SetObject(g->sp, mObj);
342 ++g->sp; SetInt(g->sp, modifiers);
343 runInterpreter(g, method, 2);
344 g->canCallOS = false;
346 pthread_mutex_unlock (&gLangMutex);
350 void SCView::touchDownAction(SCPoint where, UITouch *touch)
352 pthread_mutex_lock (&gLangMutex);
353 PyrSymbol *method = getsym("mouseDown");
354 int clickCount = [touch tapCount];
357 VMGlobals *g = gMainVMGlobals;
359 if(mParent->relativeOrigin()){
360 SCRect tbounds = mParent->getDrawBounds();
361 where.x = where.x - tbounds.x;
362 where.y = where.y - tbounds.y;
364 ++g->sp; SetObject(g->sp, mObj);
365 ++g->sp; SetFloat(g->sp, where.x);
366 ++g->sp; SetFloat(g->sp, where.y);
367 ++g->sp; SetInt(g->sp, 0);
368 ++g->sp; SetInt(g->sp,0);
369 ++g->sp; SetInt(g->sp,clickCount);
370 runInterpreter(g, method, 6);
371 g->canCallOS = false;
373 pthread_mutex_unlock (&gLangMutex);
376 void SCView::touchMoveAction(SCPoint where, UITouch *touch)
378 pthread_mutex_lock (&gLangMutex);
379 PyrSymbol *method = getsym("mouseMove");
381 VMGlobals *g = gMainVMGlobals;
383 if(mParent->relativeOrigin()){
384 SCRect tbounds = mParent->getDrawBounds();
385 where.x = where.x - tbounds.x;
386 where.y = where.y - tbounds.y;
388 ++g->sp; SetObject(g->sp, mObj);
389 ++g->sp; SetFloat(g->sp, where.x);
390 ++g->sp; SetFloat(g->sp, where.y);
391 ++g->sp; SetInt(g->sp, 0);
392 runInterpreter(g, method, 4);
393 g->canCallOS = false;
395 pthread_mutex_unlock (&gLangMutex);
397 void SCView::touchUpAction(SCPoint where, UITouch *touch)
399 pthread_mutex_lock (&gLangMutex);
400 PyrSymbol *method = getsym("mouseUp");
402 VMGlobals *g = gMainVMGlobals;
404 if(mParent->relativeOrigin()){
405 SCRect tbounds = mParent->getDrawBounds();
406 where.x = where.x - tbounds.x;
407 where.y = where.y - tbounds.y;
409 ++g->sp; SetObject(g->sp, mObj);
410 ++g->sp; SetFloat(g->sp, where.x);
411 ++g->sp; SetFloat(g->sp, where.y);
412 ++g->sp; SetInt(g->sp, 0);
413 runInterpreter(g, method, 4);
414 g->canCallOS = false;
416 pthread_mutex_unlock (&gLangMutex);
420 void SCView::setConstructionModeFromPoint(SCPoint where)
423 bounds = SCMakeRect(mBounds.x, mBounds.y, mBounds.width*0.6, mBounds.height*0.6);
424 // post("point: x: %f, y: %f, bounds: x: %f, y: %f\n", where.x, where.y, mBounds.x, mBounds.y);
425 if( SCPointInRect(where, bounds)){
426 mConstructionMode = view_PositionConstructionMode;
427 // [[NSCursor openHandCursor] set];
430 // [[NSCursor crosshairCursor] set];
431 mConstructionMode = view_ResizeConstructionMode;
435 void SCView::doConstructionMove(SCPoint where)
438 if( mConstructionMode == view_ResizeConstructionMode){
439 mBounds.width = mBounds.width + (where.x - (mBounds.width + mBounds.x));
440 mBounds.height = mBounds.height + (where.y - (mBounds.height + mBounds.y));
441 }else if (mConstructionMode == view_PositionConstructionMode) {
449 void SCView::touchBeginTrack(SCPoint where, UITouch *touch)
451 touchTrack(where, touch);
454 void SCView::touchTrack(SCPoint where, UITouch *touch)
458 void SCView::touchEndTrack(SCPoint where, UITouch *touch)
460 touchTrack(where, touch);
463 void SCView::touchOver(SCPoint where, UITouch *touch)
465 pthread_mutex_lock (&gLangMutex);
466 PyrSymbol *method = getsym("mouseOver");
468 VMGlobals *g = gMainVMGlobals;
470 if(mParent->relativeOrigin()){
471 SCRect tbounds = mParent->getDrawBounds();
472 where.x = where.x - tbounds.x;
473 where.y = where.y - tbounds.y;
475 ++g->sp; SetObject(g->sp, mObj);
476 ++g->sp; SetInt(g->sp, (int) where.x);
477 ++g->sp; SetInt(g->sp, (int) where.y);
478 ++g->sp; SetInt(g->sp, 0);
479 runInterpreter(g, method, 4);
480 g->canCallOS = false;
482 pthread_mutex_unlock (&gLangMutex);
485 bool SCView::canReceiveDrag()
490 void SCView::receiveDrag()
494 void SCView::draggingEntered (SCPoint where)
498 void SCView::draggingUpdated (SCPoint where)
504 void SCView::setDragHilite(bool inFlag)
506 bool prevFlag = mDragHilite;
507 mDragHilite = inFlag;
508 if (mDragHilite != prevFlag) refresh();
511 void hPaintGradient(CGContextRef cgc, CGRect bounds, SCColor startColor, SCColor endColor, int numSteps);
513 void SCView::draw(SCRect inDamage)
517 if ( mBackground || mBackgroundImage ) {
519 bounds = getDrawBounds();
520 cgc = (CGContextRef) UIGraphicsGetCurrentContext();
521 rect = SCtoCGRect(bounds);
525 mBackground->draw(cgc, rect);
527 if (mBackgroundImage)
528 mBackgroundImage->draw(cgc, rect);
531 void SCView::drawDisabled(SCRect inDamage)
533 if (!mEnabled && shouldDim()) {
534 SCRect bounds = getDrawBounds();
535 CGRect rect = SCtoCGRect(bounds);
536 CGContextRef cgc = (CGContextRef) UIGraphicsGetCurrentContext();
537 CGContextSaveGState(cgc);
538 CGContextSetRGBFillColor(cgc, 1., 1., 1., 0.5);
539 CGContextFillRect(cgc, rect);
540 CGContextRestoreGState(cgc);
544 void SCView::drawFocus(SCRect inDamage)
547 SCRect bounds = getDrawBounds();
548 CGRect rect = SCtoCGRect(bounds);
551 rect.size.width += 4;
552 rect.size.height += 4;
553 CGContextRef cgc = (CGContextRef) UIGraphicsGetCurrentContext();
554 CGContextSaveGState(cgc);
555 CGContextSetLineWidth(cgc, 2);
556 // CGContextSetRGBStrokeColor(cgc, 0., 0., 0., 0.5);
557 CGContextSetRGBStrokeColor(cgc, mFocusColor.red, mFocusColor.green, mFocusColor.blue, mFocusColor.alpha);
559 CGContextStrokeRect(cgc, rect);
560 CGContextRestoreGState(cgc);
566 void SCView::drawDragHilite(SCRect inDamage)
569 SCRect bounds = getDrawBounds();
571 CGRect rect = SCtoCGRect(bounds);
574 rect.size.width -= 4;
575 rect.size.height -= 4;
576 CGContextRef cgc = (CGContextRef) UIGraphicsGetCurrentContext();
577 CGContextSaveGState(cgc);
578 CGContextSetLineWidth(cgc, 4);
579 CGContextSetRGBStrokeColor(cgc, 0., 0., 1., 0.4);
580 CGContextStrokeRect(cgc, rect);
581 CGContextRestoreGState(cgc);
585 void SCView::drawIfNecessary(SCRect inDamage)
587 if (SCRectsDoIntersect(inDamage, getDrawBounds()) && mVisible) {
589 drawDisabled(inDamage);
590 drawDragHilite(inDamage);
595 SCView* SCView::findView(SCPoint where)
597 if (hit(where) && mEnabled && mVisible) return this;
601 SCView* SCView::findViewByID(int32 inID)
603 if (inID == mID) return this;
607 bool SCView::shouldDim()
612 bool SCView::canFocus()
614 bool flag = mEnabled && mVisible && mCanFocus;
615 if (mParent) flag = flag && mParent->canFocus();
619 bool SCContainerView::canFocus()
621 bool flag = mEnabled && mVisible;
622 if (mParent) flag = flag && mParent->canFocus();
626 SCRect CGtoSCRect(CGRect nsrect)
629 screct.x = nsrect.origin.x;
630 screct.y = nsrect.origin.y;
631 screct.width = nsrect.size.width;
632 screct.height = nsrect.size.height;
636 void SCView::setBounds(SCRect inBounds)
639 if(mParent->relativeOrigin()){
640 SCRect pbounds = mParent->getLayout().bounds;
641 mLayout.bounds.x = mBounds.x + pbounds.x;
642 mLayout.bounds.y = mBounds.y + pbounds.y;
643 mLayout.bounds.width = mBounds.width;
644 mLayout.bounds.height = mBounds.height;
646 mLayout.bounds = mBounds;
651 SCRect SCView::getBounds()
657 SCRect SCView::getDrawBounds() //relative to ContainerView
659 // if(mParent->relativeOrigin()){
660 // SCRect pbounds = mParent->getBounds();
661 // mLayout.bounds.x = mBounds.x + pbounds.x;
662 // mLayout.bounds.y = mBounds.y + pbounds.y;
663 // mLayout.bounds.width = mBounds.width;
664 // mLayout.bounds.height = mBounds.height;
666 // mLayout.bounds = mBounds;
668 return mLayout.bounds;
671 Layout SCView::getLayout()
676 void SCView::makeFocus(bool focus)
679 if (canFocus() && !isFocus()) {
680 SCView *prevFocus = mTop->focusView();
681 if (prevFocus) prevFocus->makeFocus(false);
684 //NSView* newFirstResponder = focusResponder();
685 //[[newFirstResponder window] makeFirstResponder:newFirstResponder];
695 //NSView* SCView::focusResponder() { return mTop->GetNSView(); }
697 void SCContainerView::makeFocus(bool focus)
701 SCView* SCView::nextFocus(bool *foundFocus, bool canFocus)
707 canFocus = canFocus && mEnabled && mVisible && mCanFocus;
708 if (canFocus && *foundFocus) return this;
712 SCView* SCView::prevFocus(SCView **prevView, bool canFocus)
714 if (isFocus() && *prevView) return *prevView;
715 canFocus = canFocus && mEnabled && mVisible && mCanFocus;
716 if (canFocus) *prevView = this;
721 void SCView::refresh()
723 mTop->addDamage(mLayout.bounds);
726 void SCView::refreshInRect(SCRect b)
728 if(SCRectsDoIntersect(b, mLayout.bounds)) {
731 sect.x = sc_max(b.x, mLayout.bounds.x);
732 sect.y = sc_max(b.y, mLayout.bounds.y);
733 sect.width = sc_min(b.x + b.width, mLayout.bounds.x + mLayout.bounds.width);
734 sect.height = sc_min(b.y + b.height, mLayout.bounds.y + mLayout.bounds.height);
735 sect.width -= sect.x; sect.height -= sect.y;
736 mTop->addDamage(sect);
740 // cannot call from primitives. i.e. new view, or get/set property
741 void SCView::sendMessage(PyrSymbol *method, int numargs, PyrSlot *args, PyrSlot *result)
743 //CGContextRef cgc = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
744 //CGContextSaveGState(cgc);
745 pthread_mutex_lock (&gLangMutex);
747 VMGlobals *g = gMainVMGlobals;
749 ++g->sp; SetObject(g->sp, mObj);
750 for (int i=0; i<numargs; ++i) {
751 ++g->sp; slotCopy(g->sp, &args[i]);
753 runInterpreter(g, method, numargs+1);
754 g->canCallOS = false;
755 if (result) slotCopy(result, &g->result);
757 pthread_mutex_unlock (&gLangMutex);
759 //CGContextRestoreGState(cgc);
762 bool SCView::isDragSource() const
767 int SCView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
770 char *name = symbol->name;
771 if (strcmp(name, "bounds")==0) {
773 err = slotGetSCRect(slot, &screct);
778 if(mTop->isScroller()) {
779 ((SCScrollTopView*)mTop)->setInSetClipViewOrigin(true);
781 [(SCGraphView*)mTop->GetUIView() setFrameSizeToMinimum];
782 ((SCScrollTopView*)mTop)->setInSetClipViewOrigin(false);
783 } else {setBounds(screct);}
787 if (strcmp(name, "visible")==0) {
788 bool visible = IsTrue(slot);
789 if (mVisible != visible) {
791 if (!mVisible) mTop->resetFocus(); //
796 if (strcmp(name, "enabled")==0) {
797 bool enabled = IsTrue(slot);
798 if (mEnabled != enabled) {
800 if (!mEnabled) mTop->resetFocus();
805 if (strcmp(name, "canFocus")==0) {
806 bool canFocus = IsTrue(slot);
807 if (mCanFocus != canFocus) {
808 mCanFocus = canFocus;
809 if (!mCanFocus) mTop->resetFocus();
814 if (strcmp(name, "resize")==0) {
819 err = slotIntVal(slot, &resize);
821 if (resize < 1 || resize > 9) return errIndexOutOfRange;
822 mLayout.mHResize = ((resize - 1) % 3) - 1;
823 mLayout.mVResize = ((resize - 1) / 3) - 1;
827 if(strcmp(name,"id") ==0) {
828 return slotIntVal(slot, &mID);
830 if(strcmp(name,"minWidth") ==0) {
831 err = slotFloatVal(slot, &mLayout.mMinWidth);
835 if(strcmp(name,"maxWidth") ==0) {
836 err = slotFloatVal(slot, &mLayout.mMaxWidth);
840 if(strcmp(name,"minHeight") ==0) {
841 err = slotFloatVal(slot, &mLayout.mMinHeight);
845 if(strcmp(name,"maxHeight") ==0) {
846 err = slotFloatVal(slot, &mLayout.mMaxHeight);
850 if (strcmp(name, "background")==0) {
851 err = slotBackgroundVal(slot, &mBackground);
857 if (strcmp(name, "backgroundImage")==0) {
858 err = slotBackgroundImageVal(slot, &mBackgroundImage);
864 if (strcmp(name, "focusColor")==0) {
865 err = slotColorVal(slot, &mFocusColor);
870 if (strcmp(name, "dragLabel")==0) {
871 if(isKindOfSlot(slot, class_string)) {
872 PyrString* pstring = slotRawString(slot);
873 if(!pstring) return errNone;
874 if(mDragLabel) [mDragLabel release];
875 mDragLabel = [[NSString alloc] initWithCString: pstring->s length: pstring->size];
877 } else if (IsNil(slot)) {
878 if(mDragLabel) [mDragLabel release];
881 } else return errWrongType;
883 return errPropertyNotFound;
886 int SCView::getProperty(PyrSymbol *symbol, PyrSlot *slot)
888 char *name = symbol->name;
889 if (strcmp(name, "bounds")==0) {
890 if (!(isKindOfSlot(slot, s_rect->u.classobj))) {
893 PyrSlot *slots = slotRawObject(slot)->slots;
894 SetFloat(slots+0, mBounds.x);
895 SetFloat(slots+1, mBounds.y);
896 SetFloat(slots+2, mBounds.width);
897 SetFloat(slots+3, mBounds.height);
900 if (strcmp(name, "absoluteBounds")==0) {
902 if (!(isKindOfSlot(slot, s_rect->u.classobj))) {
905 drawBounds = mLayout.bounds;
906 PyrSlot *slots = slotRawObject(slot)->slots;
907 SetFloat(slots+0, drawBounds.x);
908 SetFloat(slots+1, drawBounds.y);
909 SetFloat(slots+2, drawBounds.width);
910 SetFloat(slots+3, drawBounds.height);
913 if (strcmp(name, "visible")==0) {
914 SetBool(slot, mVisible);
917 if (strcmp(name, "enabled")==0) {
918 SetBool(slot, mEnabled);
921 if (strcmp(name, "resize")==0) {
922 int resize = mLayout.mVResize * 3 + mLayout.mHResize + 5;
923 SetInt(slot, resize);
926 if (strcmp(name, "id")==0) {
930 /*if (strcmp(name, "background")==0) {
931 int err = getBackgroundVal(slot, mBackground);
934 /*if (strcmp(name, "backColor")==0) {
935 return setSlotColor(slot, &mBackColor);
938 if (strcmp(name, "focusColor")==0) {
939 return setSlotColor(slot, &mFocusColor);;
941 return errPropertyNotFound;
944 void SCView::beginDrag(SCPoint where)
946 sendMessage(s_beginDrag, 0, 0, 0);
950 NSString *string = 0;
952 pthread_mutex_lock (&gLangMutex);
954 VMGlobals *g = gMainVMGlobals;
955 int classVarIndex = slotRawInt(&getsym("SCView")->u.classobj->classVarIndex);
956 slotCopy(&slot, &g->classvars->slots[classVarIndex]);
957 slotCopy(&stringSlot, &g->classvars->slots[classVarIndex+1]);
958 if (isKindOfSlot(&stringSlot, class_string)) {
959 string = [NSString stringWithCString: slotRawString(&stringSlot)->s length: slotRawString(&stringSlot)->size];
961 if(mDragLabel) label = mDragLabel;
963 pthread_mutex_unlock (&gLangMutex);
965 mTop->beginDragCallback(where, &slot, string, label);
968 ////////////////////////////////////////////////////////////////////////////////////////////////
970 SCContainerView::SCContainerView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
971 : SCView(inParent, inObj, inBounds), mChildren(0), mNumChildren(0), mRelativeOrigin(false)
973 mLayout.bounds = mBounds;
975 if(mParent->relativeOrigin()){
976 SCRect pBounds = mParent->getDrawBounds(); // or jsut absolute frame bounds ?
977 mLayout.bounds.x = inBounds.x + pBounds.x;
978 mLayout.bounds.y = inBounds.y + pBounds.y;
983 SCContainerView::~SCContainerView()
985 SCView *child = mChildren;
987 SCView *next = child->mNext;
995 int SCContainerView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
998 char *name = symbol->name;
1000 if (strcmp(name, "visible")==0) {
1001 bool visible = IsTrue(slot);
1002 if (mVisible != visible) {
1004 // SCView *child = mChildren;
1006 // SCView *next = child->mNext;
1007 // child->setVisibleFromParent(visible && mParent->isVisible()); // needed for Cocoa views
1010 setVisibleFromParent();
1011 if (!mVisible) mTop->resetFocus(); //
1017 if (strcmp(name, "relativeOrigin")==0) {
1018 mRelativeOrigin = IsTrue(slot);
1022 return SCView::setProperty(symbol, slot);
1025 void SCContainerView::setVisibleFromParent()
1027 SCView *child = mChildren;
1029 SCView *next = child->mNext;
1030 child->setVisibleFromParent(); // needed for Cocoa views
1035 void SCContainerView::add(SCView *inChild)
1037 inChild->mNext = mChildren;
1038 mChildren = inChild;
1040 inChild->mParent = this;
1041 inChild->mTop = mTop;
1045 void SCContainerView::remove(SCView *inChild)
1047 SCView *child = mChildren;
1049 inChild->makeFocus(false);
1051 SCView *next = child->mNext;
1052 if (child == inChild) {
1053 if (prev) prev->mNext = child->mNext;
1054 else mChildren = child->mNext;
1065 void SCContainerView::drawIfNecessary(SCRect inDamage)
1068 drawBounds = getDrawBounds();
1069 if (SCRectsDoIntersect(inDamage, drawBounds) && mVisible) {
1071 SCView *child = mChildren;
1072 SCView *children[mNumChildren];
1073 int k = mNumChildren;
1075 // child->drawIfNecessary(inDamage);
1076 children[--k] = child;
1077 child = child->next();
1079 for(int i=0; i < mNumChildren; i++ ) {
1080 child = children[i];
1081 child->drawIfNecessary(inDamage);
1083 drawDisabled(inDamage);
1084 drawDragHilite(inDamage);
1085 drawFocus(inDamage);
1089 SCView* SCContainerView::findView(SCPoint where)
1091 if (mEnabled && mVisible) {
1092 SCView *child = mChildren;
1094 if(!(child->isScroller())) {
1095 SCView *found = child->findView(where);
1096 if (found) return found;
1098 child = child->mNext;
1104 SCView* SCContainerView::findViewByID(int32 inID)
1106 if (inID == mID) return this;
1107 SCView *child = mChildren;
1109 SCView *found = child->findViewByID(inID);
1110 if (found) return found;
1111 child = child->mNext;
1116 SCView* SCContainerView::nextFocus(bool *foundFocus, bool canFocus)
1118 canFocus = canFocus && mEnabled && mVisible;
1119 SCView *child = mChildren;
1121 SCView *view = child->nextFocus(foundFocus, canFocus);
1122 if (view) return view;
1123 child = child->mNext;
1128 SCView* SCContainerView::prevFocus(SCView **prevView, bool canFocus)
1130 canFocus = canFocus && mEnabled && mVisible;
1131 SCView *child = mChildren;
1133 SCView *view = child->prevFocus(prevView, canFocus);
1134 if (view) return view;
1135 child = child->mNext;
1140 SCRect SCContainerView::checkMinimumSize() {
1141 SCView *child = mChildren;
1142 SCRect candidate = mBounds;
1143 // iterate through all the views and see if we need to be bigger (children may exceed the parent's bounds)
1145 SCRect bounds = child->checkMinimumSize();
1146 candidate = SCRectUnion(bounds, candidate);
1147 child = child->next();
1153 SCView* NewSCCompositeView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1155 return new SCCompositeView(inParent, inObj, inBounds);
1158 SCCompositeView::SCCompositeView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1159 : SCContainerView(inParent, inObj, inBounds)
1163 SCCompositeView::~SCCompositeView()
1167 void SCCompositeView::setBounds(SCRect inBounds)
1169 SCView *child = mChildren;
1170 // float right = mBounds.x + mBounds.width;
1171 // float bottom = mBounds.y + mBounds.height;
1172 mLayout.bounds = inBounds;
1173 // if(isTopContainer()){
1174 // post("i'm my own parent ... \t");
1175 // post("in x:%f, y:%f\n", inBounds.x, inBounds.y);
1179 if(mParent->relativeOrigin()){
1180 SCRect pBounds = mParent->getDrawBounds();
1181 mLayout.bounds.x = inBounds.x + pBounds.x;
1182 mLayout.bounds.y = inBounds.y + pBounds.y;
1184 mLayout.bounds.x = inBounds.x;
1185 mLayout.bounds.y = inBounds.y;
1189 SCRect bounds = child->getBounds();
1190 Layout layout = child->getLayout();
1191 // SCRect bounds = layout.bounds;
1194 switch (layout.mHResize) {
1195 case layout_FixedLeft :
1197 case layout_FixedRight :
1198 if(!child->relativeOrigin()){
1199 offset = (mBounds.x + mBounds.width) - (bounds.x + bounds.width);
1200 bounds.x = (inBounds.x + inBounds.width) - (bounds.width + offset); //absolute
1202 if(child->isContainer()){
1203 if(child->parent()->isTopContainer() || (inBounds.width != child->parent()->getBounds().width)){
1204 offset = (mBounds.x + mBounds.width) - (bounds.x + bounds.width);
1205 bounds.x = (inBounds.x + inBounds.width) - (bounds.width + offset); //absolute
1211 case layout_HElastic :
1212 offset = (mBounds.x + mBounds.width) - (bounds.x + bounds.width);
1213 /* bounds.width = sc_clip(
1214 (inBounds.width) - (bounds.x + offset),
1216 sc_min(layout.mMaxWidth,right - bounds.x)
1218 bounds.width = (inBounds.width) - ((bounds.x - mBounds.x) + offset);
1220 switch (layout.mVResize) {
1221 case layout_FixedTop :
1223 case layout_FixedBottom :
1224 if(!child->relativeOrigin()){
1225 offset = (mBounds.y + mBounds.height) - (bounds.y + bounds.height);
1226 bounds.y = (inBounds.y + inBounds.height) - (bounds.height + offset);
1228 if(child->isContainer()){
1229 if(child->parent()->isTopContainer() || (inBounds.height != child->parent()->getBounds().height)){
1230 offset = (mBounds.y + mBounds.height) - (bounds.y + bounds.height);
1231 bounds.y = (inBounds.y + inBounds.height) - (bounds.height + offset);
1236 case layout_VElastic :
1237 offset = (mBounds.y + mBounds.height) - (bounds.y + bounds.height);
1238 /*bounds.height = sc_clip(
1239 (inBounds.height) - (bounds.y + offset),
1241 sc_min(layout.mMaxHeight,bottom - bounds.y)
1243 bounds.height = (inBounds.height) - ((bounds.y - mBounds.y) + offset);
1246 child->setBounds(bounds);
1247 child = child->next();
1249 // should be limited by the limitations of the contents
1253 /////////////////////////////////////////////////////////////////////////////////////
1256 SCView* NewSCLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1258 return new SCLayoutView(inParent, inObj, inBounds);
1261 SCLayoutView::SCLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1262 : SCContainerView(inParent, inObj, inBounds), mSpacing(4.)
1266 SCLayoutView::~SCLayoutView()
1271 int SCLayoutView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
1274 char *name = symbol->name;
1275 if (strcmp(name, "spacing")==0) {
1276 err = slotFloatVal(slot, &mSpacing);
1277 if (err) return err;
1281 if (strcmp(name, "bounds")==0) {
1283 err = slotGetSCRect(slot, &screct);
1284 if (err) return err;
1290 return SCView::setProperty(symbol, slot);
1293 int SCLayoutView::getProperty(PyrSymbol *symbol, PyrSlot *slot)
1295 char *name = symbol->name;
1296 if (strcmp(name, "spacing")==0) {
1297 SetFloat(slot, mSpacing);
1301 return SCView::getProperty(symbol, slot);
1304 void SCLayoutView::add(SCView *inChild)
1306 SCContainerView::add(inChild);
1307 setBounds(mBounds); // re-layout
1310 /////////////////////////////////////////////////////////////////////////////////////
1312 SCView* NewSCHLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1314 return new SCHLayoutView(inParent, inObj, inBounds);
1317 SCHLayoutView::SCHLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1318 : SCLayoutView(inParent, inObj, inBounds)
1322 SCHLayoutView::~SCHLayoutView()
1326 void SCHLayoutView::setBounds(SCRect inBounds)
1328 SCView *child = mChildren;
1329 float totalWeight = 0.0;
1330 //if reativeOrigin is true, the inBounds need to be moved to absolute bounds
1332 if(mParent->relativeOrigin()){
1333 SCRect pbounds = mParent->getLayout().bounds;
1334 mLayout.bounds.x = mBounds.x + pbounds.x;
1335 mLayout.bounds.y = mBounds.y + pbounds.y;
1336 mLayout.bounds.width = mBounds.width;
1337 mLayout.bounds.height = mBounds.height;
1339 mLayout.bounds = mBounds;
1341 SCRect absBounds = mLayout.bounds;
1343 Layout layout = child->getLayout();
1344 // could store this when child added
1345 totalWeight += layout.mWeight;
1346 child = child->next();
1348 // subtract the spacers we will use
1349 float totalWidth = absBounds.width - (mSpacing * (mNumChildren - 1));
1351 // find views who are constrained by a minimum or maximum size
1352 // and remove them from the set of weights.
1353 float scaleWeight = sc_max(totalWidth,0.0) * (1.0 / sc_max(totalWeight,0.01));
1355 float widths[mNumChildren];
1356 SCView *children[mNumChildren];
1357 int ri = mNumChildren;
1361 children[--ri] = child;
1362 Layout layout = child->getLayout();
1363 float weightedWidth = scaleWeight * layout.mWeight;
1364 if(layout.mHResize == 0) {// okay to resize
1365 if (weightedWidth < layout.mMinWidth) {
1366 width = layout.mMinWidth;
1368 totalWidth -= width;
1369 totalWeight -= layout.mWeight;
1371 if (weightedWidth > layout.mMaxWidth) {
1372 width = layout.mMaxWidth;
1374 totalWidth -= width;
1375 totalWeight -= layout.mWeight;
1381 SCRect rect = child->getBounds();
1382 widths[ri] = rect.width;
1384 child = child->next();
1386 //totalWidth is now the remaining flexible width
1388 // now layout the views
1389 float left = absBounds.x;
1390 float top = absBounds.y;
1391 float height = absBounds.height;
1392 scaleWeight = totalWidth * (1.0/totalWeight);
1395 for(; i < mNumChildren; i++ ) {
1396 child = children[i];
1397 Layout layout = child->getLayout();
1399 if(widths[i] == -1.0) {
1400 width = scaleWeight * layout.mWeight;
1401 } else { // was constrained
1404 child->setBounds(SCMakeRect( left, top, width, height));
1405 left += (width + mSpacing);
1406 child = child->next();
1411 /////////////////////////////////////////////////////////////////////////////////////
1413 SCView* NewSCVLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1415 return new SCVLayoutView(inParent, inObj, inBounds);
1418 SCVLayoutView::SCVLayoutView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1419 : SCLayoutView(inParent, inObj, inBounds)
1423 SCVLayoutView::~SCVLayoutView()
1427 void SCVLayoutView::setBounds(SCRect inBounds)
1429 SCView *child = mChildren;
1430 float totalWeight = 0.0;
1432 Layout layout = child->getLayout();
1433 // could store this when child added
1434 totalWeight += layout.mWeight;
1435 child = child->next();
1437 //if reativeOrigin is true, the inBounds need to be moved to absolute bounds
1439 if(mParent->relativeOrigin()){
1440 SCRect pbounds = mParent->getLayout().bounds;
1441 mLayout.bounds.x = mBounds.x + pbounds.x;
1442 mLayout.bounds.y = mBounds.y + pbounds.y;
1443 mLayout.bounds.width = mBounds.width;
1444 mLayout.bounds.height = mBounds.height;
1446 mLayout.bounds = mBounds;
1448 SCRect absBounds = mLayout.bounds;
1449 // subtract the spacers we will use
1450 float totalHeight = absBounds.height - (mSpacing * (mNumChildren - 1));
1452 // find views who are constrained by a minimum or maximum size
1453 // and remove them from the set of weights.
1454 float scaleWeight = sc_max(totalHeight,0.0) * (1.0 / sc_max(totalWeight,0.01));
1456 float heights[mNumChildren];
1457 SCView *children[mNumChildren];
1458 int ri = mNumChildren;
1462 children[--ri] = child;
1463 Layout layout = child->getLayout();
1464 float weightedHeight = scaleWeight * layout.mWeight;
1465 if(layout.mVResize == 0) {// okay to resize
1466 if (weightedHeight < layout.mMinHeight) {
1467 height = layout.mMinHeight;
1468 heights[ri] = height;
1469 totalHeight -= height;
1470 totalWeight -= layout.mWeight;
1472 if (weightedHeight > layout.mMaxHeight) {
1473 height = layout.mMaxHeight;
1474 heights[ri] = height;
1475 totalHeight -= height;
1476 totalWeight -= layout.mWeight;
1482 SCRect rect = child->getBounds();
1483 heights[ri] = rect.height;
1485 child = child->next();
1487 //totalHeight is now the remaining flexible height
1489 // now layout the views
1490 float left = absBounds.x;
1491 float top = absBounds.y;
1492 float width = absBounds.width;
1493 scaleWeight = totalHeight * (1.0/totalWeight);
1496 for(; i < mNumChildren; i++ ) {
1497 child = children[i];
1498 Layout layout = child->getLayout();
1500 if(heights[i] == -1.0) {
1501 height = scaleWeight * layout.mWeight;
1502 } else { // was constrained
1503 height = heights[i];
1505 child->setBounds(SCMakeRect( left, top, width, height));
1506 top += (height + mSpacing);
1507 child = child->next();
1513 /////////////////////////////////////////////////////////////////////////////////////
1516 SCView* NewSCTopView(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1518 return new SCTopView(inObj, inBounds);
1521 SCTopView::SCTopView(PyrObject* inObj, SCRect inBounds)
1522 : SCCompositeView(0, inObj, inBounds), mFocusView(0), mDragView(0), mConstructionMode(false)
1525 //float ltgry = 0.8;
1526 //float dkgry = 0.5;
1527 //mBackground = new SolidColorBackground(
1528 // SCMakeColor(ltgry, ltgry, ltgry, 1.0));
1531 void SCTopView::addDamage(SCRect inRect)
1533 (*mDamageCallback)(inRect, mHostData);
1534 //mDamage = SCRectUnion(mDamage, inRect);
1537 void SCTopView::beginDragCallback(SCPoint where, PyrSlot* slot, NSString* string, NSString* label)
1539 (*mDragCallback)(where, slot, string, label, mHostData);
1542 void SCView::refreshFocus()
1544 SCRect focusBounds = getDrawBounds();
1547 focusBounds.width += 8;
1548 focusBounds.height += 8;
1549 mTop->addDamage(focusBounds);
1552 void SCTopView::resetFocus()
1554 SCView *view = focusView();
1555 if (view && !view->canFocus()) {
1557 view->refreshFocus();
1561 void SCTopView::forgetView(SCView *view)
1563 if (view == mFocusView) mFocusView = 0;
1564 if (view == mDragView) mDragView = 0;
1567 void SCTopView::tabNextFocus()
1569 bool foundFocus = mFocusView ? false : true;
1570 SCView *view = nextFocus(&foundFocus, true);
1571 if (!view && foundFocus) view = nextFocus(&foundFocus, true);
1572 if (view) view->makeFocus(true);
1575 void SCTopView::tabPrevFocus()
1577 SCView *prevView = 0;
1578 SCView *view = prevFocus(&prevView, true);
1579 if (!view && prevView) view = prevView;
1580 if (view) view->makeFocus(true);
1583 void SCTopView::setDragView(SCView *inView)
1585 if (inView != mDragView) {
1586 if (mDragView) mDragView->setDragHilite(false);
1588 if (mDragView) mDragView->setDragHilite(true);
1592 void SCTopView::drawFocus(SCRect inDamage)
1594 if (ConstructionMode()) {
1595 CGRect rect = SCtoCGRect(mBounds);
1598 rect.size.width -= 4;
1599 rect.size.height -= 4;
1600 CGContextRef cgc = (CGContextRef) UIGraphicsGetCurrentContext();
1601 CGContextSaveGState(cgc);
1602 CGContextSetLineWidth(cgc, 4);
1603 CGContextSetRGBStrokeColor(cgc, 1., 1., 0., 1.);
1604 CGContextStrokeRect(cgc, rect);
1605 CGContextRestoreGState(cgc);
1609 bool SCTopView::canReceiveDrag()
1612 sendMessage(s_canReceiveDrag, 0, 0, &result);
1613 return IsTrue(&result);
1616 void SCTopView::receiveDrag()
1618 sendMessage(s_receiveDrag, 0, 0, 0);
1621 void SCTopView::setInternalBounds(SCRect internalBounds)
1623 setBounds(internalBounds);
1626 ///////////////////////////////////////////////////////////////////////////////////////
1628 SCView* NewSCSlider(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1630 return new SCSlider(inParent, inObj, inBounds);
1633 SCSlider::SCSlider(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1634 : SCView(inParent, inObj, inBounds), mStepSize(0.), mStepScale(0.), mKnob(0), mThumbSize(12.)
1637 setValue(0.0, false);
1640 //int drawBevelRect(Rect r, int width, int inout, RGBColor color, int drawop);
1642 void SCSlider::draw(SCRect inDamage)
1644 SCRect bounds = getDrawBounds();
1645 calcThumbRect(bounds);
1647 CGContextRef cgc = (CGContextRef)UIGraphicsGetCurrentContext();;
1648 CGContextSaveGState(cgc);
1649 CGRect rect = SCtoCGRect(bounds);
1650 if (mBackground) mBackground->draw(cgc, rect);
1652 if (mBackgroundImage)
1653 mBackgroundImage->draw(cgc, rect);
1656 QDDrawBevelRect(cgc, rect, 1, true);
1659 CGRect cgThumbRect = SCtoCGRect(mThumbRect);
1660 if (mKnob) mKnob->draw(cgc, cgThumbRect);
1661 QDDrawBevelRect(cgc, cgThumbRect, 2, false);
1662 CGContextRestoreGState(cgc);
1664 //drawBevelRect(SCtoQDRect(mBounds), 1, 1, SCtoQDColor(mBackColor), 2);
1665 //drawBevelRect(SCtoQDRect(mThumbRect), 2, 0, SCtoQDColor(mKnobColor), 2);
1668 bool SCSlider::setValue(double inValue, bool send)
1670 inValue = sc_clip(inValue, 0., 1.);
1671 if (mStepSize > 0.) {
1672 inValue = floor(inValue * mStepScale + 0.5) * mStepSize;
1674 bool changed = inValue != mValue;
1679 if (send) sendMessage(s_doaction, 0, 0, 0);
1684 void SCSlider::setValueFromPoint(SCPoint point)
1686 double moveableRange, value;
1687 SCRect bounds = getDrawBounds();
1688 if (bounds.width > bounds.height) {
1689 moveableRange = bounds.width - mThumbSize - 2;
1690 value = (point.x - bounds.x - 1 - mThumbSize/2) / moveableRange;
1692 moveableRange = bounds.height - mThumbSize - 2;
1693 value = 1. - (point.y - bounds.y - 1 - mThumbSize/2) / moveableRange;
1695 setValue(value, true);
1698 void SCSlider::calcThumbRect(SCRect bounds)
1700 double moveableRange;
1702 moveableRange = (bounds.width > bounds.height)
1703 ? bounds.width : bounds.height;
1704 moveableRange -= mThumbSize + 2;
1706 double offset = mValue * moveableRange;
1708 if (bounds.width > bounds.height) {
1709 mThumbRect = SCMakeRect(bounds.x + offset + 1, bounds.y + 1,
1710 mThumbSize, bounds.height - 2);
1712 mThumbRect = SCMakeRect(bounds.x + 1, bounds.y + bounds.height - offset - 1 - mThumbSize,
1713 bounds.width - 2, mThumbSize);
1717 void SCSlider::touchTrack(SCPoint where, UITouch *touch)
1719 if (/*modifiers & NSCommandKeyMask*/0) {
1722 setValueFromPoint(where);
1726 int SCSlider::setProperty(PyrSymbol *symbol, PyrSlot *slot)
1729 if (symbol == s_value) {
1731 err = slotDoubleVal(slot, &value);
1732 if (err) return err;
1733 bool changed = setValue(value, false);
1734 SetBool(slot, changed);
1737 char *name = symbol->name;
1738 if (strcmp(name, "knobColor")==0) {
1739 err = slotBackgroundVal(slot, &mKnob);
1740 if (err) return err;
1744 if (strcmp(name, "step")==0) {
1745 err = slotDoubleVal(slot, &mStepSize);
1747 mStepScale = 1. / mStepSize;
1748 bool changed = setValue(mValue, false);
1749 SetBool(slot, changed);
1753 if (strcmp(name, "thumbSize")==0) {
1754 err = slotFloatVal(slot, &mThumbSize);
1755 if (err) return err;
1760 return SCView::setProperty(symbol, slot);
1763 int SCSlider::getProperty(PyrSymbol *symbol, PyrSlot *slot)
1765 if (symbol == s_value) {
1766 SetFloat(slot, mValue);
1769 char *name = symbol->name;
1770 if (strcmp(name, "step")==0) {
1771 SetFloat(slot, mStepSize);
1774 if (strcmp(name, "thumbSize")==0) {
1775 SetFloat(slot, mThumbSize);
1779 return SCView::getProperty(symbol, slot);
1784 bool SCSlider::canReceiveDrag()
1787 sendMessage(s_canReceiveDrag, 0, 0, &result);
1788 return IsTrue(&result);
1791 void SCSlider::receiveDrag()
1793 sendMessage(s_receiveDrag, 0, 0, 0);
1797 ///////////////////////////////////////////////////////////////////////////////////////////////
1800 SCView* NewSCButton(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1802 return new SCButton(inParent, inObj, inBounds);
1805 SCButton::SCButton(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1806 : SCView(inParent, inObj, inBounds), mNumStates(0), mStates(0), mPushed(false)
1808 setValue(0, false, 0);
1809 strcpy(mFontName, "Helvetica");
1813 SCButton::~SCButton()
1818 void SCButton::draw(SCRect inDamage)
1820 SCColor buttonColor;
1821 SCRect bounds = getDrawBounds();
1824 SCButtonState *state = mStates + mValue;
1825 buttonColor = state->mButtonColor;
1826 //drawBevelRect(SCtoQDRect(mBounds), 2, mPushed ? 1 : 0, SCtoQDColor(buttonColor), 2);
1828 CGContextRef cgc = (CGContextRef)UIGraphicsGetCurrentContext();
1829 CGContextSaveGState(cgc);
1831 CGRect cgrect = SCtoCGRect(bounds);
1832 if (buttonColor.alpha > 0.0) {
1833 CGContextSetRGBFillColor(cgc, buttonColor.red, buttonColor.green, buttonColor.blue, buttonColor.alpha);
1834 CGContextFillRect(cgc, cgrect);
1836 QDDrawBevelRect(cgc, cgrect, 2, mPushed);
1837 CGContextRestoreGState(cgc);
1839 SCRect innerBounds = bounds;
1841 int pushOffset = mPushed ? 2 : 0;
1842 innerBounds.x += inset + pushOffset;
1843 innerBounds.y += inset + pushOffset;
1844 innerBounds.width -= inset * 2 + pushOffset;
1845 innerBounds.height -= inset * 2 + pushOffset;
1846 stringDrawCenteredInRect(state->mLabel, innerBounds, mFontName, mFontSize, state->mLabelColor);
1850 bool SCButton::setValue(int inValue, bool send, int modifiers)
1852 bool changed = inValue != mValue;
1854 if (inValue < 0 || inValue >= mNumStates) inValue = 0;
1855 if (inValue != mValue || mNumStates < 2) {
1858 SetInt(args, modifiers);
1859 if (send) sendMessage(s_doaction, 1, args, 0);
1865 void SCButton::touchTrack(SCPoint where, UITouch *touch)
1867 if (/*modifiers & NSCommandKeyMask*/0) {
1870 bool inside = hit(where);
1871 if (inside != mPushed) {
1878 void SCButton::touchEndTrack(SCPoint where, UITouch *touch)
1880 bool inside = hit(where);
1881 if (inside) setValue(mValue+1, true, 0);
1885 int SCMakeButtonState(SCButton* view, SCButtonState *inState, PyrSlot *slot)
1888 if (!isKindOfSlot(slot, class_array)) return errWrongType;
1889 PyrSlot *slots = slotRawObject(slot)->slots;
1891 inState->mLabel[0] = 0;
1892 inState->mLabelColor = SCMakeColor(0,0,0,1); // black
1893 inState->mButtonColor = SCMakeColor(0.7,0.7,0.7,1);
1895 if (slotRawObject(slot)->size < 1) return errNone;
1896 err = slotStrVal(slots+0, inState->mLabel, kLabelSize);
1897 if (err) return err;
1899 if (slotRawObject(slot)->size < 2) return errNone;
1900 err = slotColorVal(slots+1, &inState->mLabelColor);
1902 inState->mLabelColor = SCMakeColor(0,0,0,1); // black
1905 if (slotRawObject(slot)->size < 3) return errNone;
1906 err = slotColorVal(slots+2, &inState->mButtonColor);
1908 //inState->mButtonColor = view->getBackColor();
1913 int SCButton::setProperty(PyrSymbol *symbol, PyrSlot *slot)
1916 if (symbol == s_value) {
1918 err = slotIntVal(slot, &value);
1919 if (err) return err;
1920 bool changed = setValue(value, false, 0);
1921 SetBool(slot, changed);
1924 char *name = symbol->name;
1925 if (strcmp(name, "font")==0) {
1926 if (!isKindOfSlot(slot, getsym("SCFont")->u.classobj)) return errWrongType;
1927 PyrSlot *slots = slotRawObject(slot)->slots;
1930 err = slotFloatVal(slots+1, &fontSize);
1931 if (err) return err;
1933 err = slotStrVal(slots+0, mFontName, kFontNameSize);
1934 if (err) return err;
1936 mFontSize = fontSize;
1939 if (strcmp(name, "states")==0) {
1940 if (!isKindOfSlot(slot, class_array)) return errWrongType;
1947 PyrObject *array = slotRawObject(slot);
1948 int numStates = array->size;
1949 SCButtonState* states = new SCButtonState[numStates];
1950 if (!states) return errFailed;
1951 for (int i=0; i<numStates; ++i) {
1952 SCButtonState *state = states + i;
1953 PyrSlot *slot = array->slots + i;
1954 err = SCMakeButtonState(this, state, slot);
1961 mNumStates = numStates;
1965 return SCView::setProperty(symbol, slot);
1968 int SCButton::getProperty(PyrSymbol *symbol, PyrSlot *slot)
1970 if (symbol == s_value) {
1971 SetInt(slot, mValue);
1974 //char *name = symbol->name;
1976 return SCView::getProperty(symbol, slot);
1979 bool SCButton::canReceiveDrag()
1982 sendMessage(s_canReceiveDrag, 0, 0, &result);
1983 return IsTrue(&result);
1986 void SCButton::receiveDrag()
1988 sendMessage(s_receiveDrag, 0, 0, 0);
1991 ///////////////////////////////////////////////////////////////////////////////////////////////
1993 SCView* NewSCStaticText(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1995 return new SCStaticText(inParent, inObj, inBounds);
1998 SCStaticText::SCStaticText(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
1999 : SCView(inParent, inObj, inBounds), mString(0), mAlignment(kSCAlignLeft)
2001 strcpy(mFontName, "Helvetica");
2003 mStringColor = SCMakeColor(0,0,0,1);
2008 SCStaticText::~SCStaticText()
2013 bool SCStaticText::shouldDim()
2018 void SCStaticText::draw(SCRect inDamage)
2020 SCView::draw(inDamage);
2021 SCRect bounds = getDrawBounds();
2026 void SCStaticText::drawString(SCRect bounds)
2029 if (mAlignment < 0) {
2030 stringDrawLeftInRect(mString, bounds, mFontName, mFontSize, mStringColor);
2031 } else if (mAlignment > 0) {
2032 stringDrawRightInRect(mString, bounds, mFontName, mFontSize, mStringColor);
2034 stringDrawCenteredInRect(mString, bounds, mFontName, mFontSize, mStringColor);
2039 int allocSlotStrVal(PyrSlot *slot, char **str)
2047 len = strlen(slotRawSymbol(slot)->name);
2048 *str = new char[len+1];
2049 strcpy(*str, slotRawSymbol(slot)->name);
2051 } else if (isKindOfSlot(slot, class_string)) {
2052 len = slotRawObject(slot)->size;
2053 *str = new char[len+1];
2054 memcpy(*str, slotRawString(slot)->s, len);
2058 return errWrongType;
2061 int SCStaticText::setProperty(PyrSymbol *symbol, PyrSlot *slot)
2064 char *name = symbol->name;
2065 if (strcmp(name, "string")==0) {
2066 err = allocSlotStrVal(slot, &mString);
2067 if (err) return err;
2071 if (strcmp(name, "font")==0) {
2072 if (!isKindOfSlot(slot, getsym("SCFont")->u.classobj)) return errWrongType;
2073 PyrSlot *slots = slotRawObject(slot)->slots;
2076 err = slotFloatVal(slots+1, &fontSize);
2077 if (err) return err;
2079 err = slotStrVal(slots+0, mFontName, kFontNameSize);
2080 if (err) return err;
2082 mFontSize = fontSize;
2086 if (strcmp(name, "stringColor")==0) {
2087 err = slotColorVal(slot, &mStringColor);
2088 if (err) return err;
2092 if (strcmp(name, "align")==0) {
2095 if (slotRawSymbol(slot)->name[0] == 'l') mAlignment = -1;
2096 else if (slotRawSymbol(slot)->name[0] == 'r') mAlignment = 1;
2097 else if (slotRawSymbol(slot)->name[0] == 'c') mAlignment = 0;
2098 else return errFailed;
2100 err = slotIntVal(slot, &align);
2101 if (err) return err;
2107 return SCView::setProperty(symbol, slot);
2110 int SCStaticText::getProperty(PyrSymbol *symbol, PyrSlot *slot)
2112 char *name = symbol->name;
2114 if (strcmp(name, "stringColor")==0) {
2115 return setSlotColor(slot, &mStringColor);
2118 return SCView::getProperty(symbol, slot);
2121 ////////////////////////////////////////////////
2123 SCView* NewSCNumberBox(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
2125 return new SCNumberBox(inParent, inObj, inBounds);
2128 SCNumberBox::SCNumberBox(SCContainerView *inParent, PyrObject* inObj, SCRect inBounds)
2129 : SCStaticText(inParent, inObj, inBounds)
2131 mBackground = new SolidColorBackground(SCMakeColor(1.0,1.0,1.0, 1.0)); // default is white
2136 SCNumberBox::~SCNumberBox()
2140 bool SCNumberBox::shouldDim()
2145 void SCNumberBox::draw(SCRect inDamage)
2147 SCView::draw(inDamage);
2148 SCRect bounds = getDrawBounds();
2150 CGContextRef cgc = (CGContextRef)UIGraphicsGetCurrentContext();
2151 CGContextSaveGState(cgc);
2152 CGRect rect = SCtoCGRect(bounds);
2153 if (mBackground) mBackground->draw(cgc, rect);
2155 QDDrawBevelRect(cgc, rect, 1, true);
2156 CGContextRestoreGState(cgc);
2158 //drawBevelRect(SCtoQDRect(mBounds), 1, 1, SCtoQDColor(mBackColor), 2);
2159 SCRect sbounds = bounds;
2163 drawString(sbounds);
2166 //int SCNumberBox::setProperty(PyrSymbol *symbol, PyrSlot *slot)
2169 // char *name = symbol->name;
2170 // if (strcmp(name, "boxColor")==0) {
2171 // err = slotColorVal(slot, &mBoxColor);
2172 // if (err) return err;
2176 // return SCStaticText::setProperty(symbol, slot);
2179 void SCNumberBox::touchTrack(SCPoint where, UITouch *touch)
2182 if (modifiers & NSCommandKeyMask) {
2188 //int SCNumberBox::getProperty(PyrSymbol *symbol, PyrSlot *slot)
2190 // char *name = symbol->name;
2191 // if (strcmp(name, "boxColor")==0) {
2192 // return setSlotColor(slot, &mBoxColor);
2194 // return SCStaticText::getProperty(symbol, slot);
2197 bool SCNumberBox::canReceiveDrag()
2200 sendMessage(s_canReceiveDrag, 0, 0, &result);
2201 return IsTrue(&result);
2204 void SCNumberBox::receiveDrag()
2206 sendMessage(s_receiveDrag, 0, 0, 0);
2209 ////////////////////////////////////////////////
2211 SCViewMaker::SCViewMaker(const char* inName, SCViewCtor inCtor)
2212 : mNext(gSCViewMakers), mCtor(inCtor), mName(inName)
2214 gSCViewMakers = this;
2217 SCView* MakeSCView(PyrObject* inObj, SCContainerView *inParent, SCRect inBounds,const char *classname)
2219 SCViewMaker* maker = gSCViewMakers;
2221 if (strcmp(classname, maker->mName) == 0) {
2222 return (maker->mCtor)(inParent, inObj, inBounds);
2224 maker = maker->mNext;
2229 static bool sRegisteredSCViewClasses = false;
2231 void registerSCViewClasses()
2233 if (sRegisteredSCViewClasses) return;
2234 sRegisteredSCViewClasses = true;
2236 new SCViewMaker("SCTopView", NewSCTopView);
2237 new SCViewMaker("SCCompositeView", NewSCCompositeView);
2238 new SCViewMaker("SCHLayoutView", NewSCHLayoutView);
2239 new SCViewMaker("SCVLayoutView", NewSCVLayoutView);
2240 new SCViewMaker("SCSlider", NewSCSlider);
2241 new SCViewMaker("SCButton", NewSCButton);
2242 new SCViewMaker("SCStaticText", NewSCStaticText);
2243 new SCViewMaker("SCNumberBox", NewSCNumberBox);
2248 int prSCView_New(struct VMGlobals *g, int numArgsPushed);
2249 int prSCView_New(struct VMGlobals *g, int numArgsPushed)
2251 if (!g->canCallOS) return errCantCallOS;
2253 PyrSlot *args = g->sp - 3;
2254 // view, parent, bounds, viewclass
2256 SCContainerView *parent;
2257 if (isKindOfSlot(args, s_sctopview->u.classobj) && !isKindOfSlot(args, s_scscrollview->u.classobj)) {
2260 if (!isKindOfSlot(args+1, s_sccontview->u.classobj)) return errWrongType;
2261 // check if it still has a dataptr
2262 parentSlot = slotRawObject(&args[1])->slots[0];
2263 if(IsNil(&parentSlot)) return errFailed;
2264 parent = (SCContainerView*)slotRawPtr(&parentSlot);
2266 if (!(isKindOfSlot(args+2, s_rect->u.classobj))) return errWrongType;
2269 int err = slotGetSCRect(args+2, &bounds);
2270 if (err) return err;
2271 SCView *view = MakeSCView(slotRawObject(&args[0]), parent, bounds, slotRawSymbol(&slotRawClass(&args[3])->name)->name);
2272 if (!view) return errFailed;
2277 int prSCView_SetProperty(struct VMGlobals *g, int numArgsPushed);
2278 int prSCView_SetProperty(struct VMGlobals *g, int numArgsPushed)
2280 if (!g->canCallOS) return errCantCallOS;
2282 PyrSlot *args = g->sp - 2;
2284 if (!IsSym(args+1)) return errWrongType;
2286 SCView *view = (SCView*)slotRawPtr(slotRawObject(&args[0])->slots);
2287 if (!view) return errFailed;
2289 int err = view->setProperty(slotRawSymbol(&args[1]), args+2);
2290 if (err) SetNil(args+2);
2292 slotCopy(&args[0], &args[2]);
2297 int prSCView_GetProperty(struct VMGlobals *g, int numArgsPushed);
2298 int prSCView_GetProperty(struct VMGlobals *g, int numArgsPushed)
2300 if (!g->canCallOS) return errCantCallOS;
2302 PyrSlot *args = g->sp - 2;
2304 if (!IsSym(args+1)) return errWrongType;
2306 SCView *view = (SCView*)slotRawPtr(slotRawObject(&args[0])->slots);
2307 if (!view) return errFailed;
2309 int err = view->getProperty(slotRawSymbol(&args[1]), args+2);
2310 if (err) SetNil(args+2);
2312 slotCopy(&args[0], &args[2]);
2317 int prSCView_FindByID(struct VMGlobals *g, int numArgsPushed);
2318 int prSCView_FindByID(struct VMGlobals *g, int numArgsPushed)
2320 if (!g->canCallOS) return errCantCallOS;
2322 PyrSlot *a = g->sp - 1;
2325 SCView *view = (SCView*)slotRawPtr(slotRawObject(a)->slots);
2326 if (!view) return errFailed;
2329 int err = slotIntVal(b, &tag);
2330 if (err) return err;
2332 view = view->findViewByID(tag);
2336 SetObjectOrNil(a, view->GetSCObj());
2342 int prSCView_Focus(struct VMGlobals *g, int numArgsPushed);
2343 int prSCView_Focus(struct VMGlobals *g, int numArgsPushed)
2345 if (!g->canCallOS) return errCantCallOS;
2347 PyrSlot *viewObjSlot = g->sp - 1;
2348 SCView *view = (SCView*)slotRawPtr(slotRawObject(&viewObjSlot[0])->slots);
2349 PyrSlot *boo = g->sp;
2351 if (!view) return errFailed;
2352 view->makeFocus(IsTrue(boo));
2356 int prSCView_HasFocus(struct VMGlobals *g, int numArgsPushed);
2357 int prSCView_HasFocus(struct VMGlobals *g, int numArgsPushed)
2359 if (!g->canCallOS) return errCantCallOS;
2361 PyrSlot *viewObjSlot = g->sp;
2362 SCView *view = (SCView*)slotRawPtr(slotRawObject(&viewObjSlot[0])->slots);
2364 if (!view) return errFailed;
2365 SetBool(viewObjSlot, view->isFocus());
2369 int prSCView_Refresh(struct VMGlobals *g, int numArgsPushed);
2370 int prSCView_Refresh(struct VMGlobals *g, int numArgsPushed)
2372 if (!g->canCallOS) return errCantCallOS;
2374 SCView *view = (SCView*)slotRawPtr(slotRawObject(g->sp)->slots);
2375 if(!view) return errNone;
2380 int prSCView_RefreshInRect(struct VMGlobals *g, int numArgsPushed);
2381 int prSCView_RefreshInRect(struct VMGlobals *g, int numArgsPushed)
2383 if (!g->canCallOS) return errCantCallOS;
2385 SCView *view = (SCView*)slotRawPtr(slotRawObject(&(g->sp - 1)[0])->slots);
2387 if(slotGetSCRect(g->sp, &r) != noErr)
2390 view->refreshInRect(r);
2394 int prSCView_Remove(struct VMGlobals *g, int numArgsPushed);
2395 int prSCView_Remove(struct VMGlobals *g, int numArgsPushed)
2397 //if (!g->canCallOS) return errCantCallOS;
2399 PyrSlot *viewObjSlot = g->sp;
2400 SCView *view = (SCView*)slotRawPtr(slotRawObject(&viewObjSlot[0])->slots);
2401 if (!view) return errFailed;
2403 // removes from parent, set mObj to nil
2408 void initSCViewPrimitives()
2411 registerSCViewClasses();
2417 s_lo = getsym("lo");
2418 s_hi = getsym("hi");
2419 s_range = getsym("range");
2420 s_scview = getsym("SCView");
2421 s_sccontview = getsym("SCContainerView");
2422 s_sctopview = getsym("SCTopView");
2423 s_scscrollview = getsym("SCScrollView");
2424 s_beginDrag = getsym("beginDrag");
2425 s_receiveDrag = getsym("receiveDrag");
2426 s_canReceiveDrag = getsym("canReceiveDrag");
2427 s_mouseDown = getsym("mouseDown");
2428 s_mouseUp = getsym("mouseUp");
2429 s_callDrawFunc = getsym("callDrawFunc");
2430 s_toggleEditMode = getsym("toggleEditMode");
2432 base = nextPrimitiveIndex();
2435 definePrimitive(base, index++, "_SCView_New", prSCView_New, 4, 0);
2436 definePrimitive(base, index++, "_SCView_SetProperty", prSCView_SetProperty, 3, 0);
2437 definePrimitive(base, index++, "_SCView_GetProperty", prSCView_GetProperty, 3, 0);
2438 definePrimitive(base, index++, "_SCView_FindByID", prSCView_FindByID, 2, 0);
2439 definePrimitive(base, index++, "_SCView_Focus", prSCView_Focus, 2, 0);
2440 definePrimitive(base, index++, "_SCView_HasFocus", prSCView_HasFocus, 1, 0);
2441 definePrimitive(base, index++, "_SCView_Refresh", prSCView_Refresh, 1, 0);
2442 definePrimitive(base, index++, "_SCView_Remove", prSCView_Remove, 1, 0);
2443 definePrimitive(base, index++, "_SCView_RefreshInRect", prSCView_RefreshInRect, 2, 0);
2446 int ivxSCTextView_linkAction;
2452 ivxSCDragSource_object = instVarOffset("SCDragSource", "object");
2453 ivxSCDragBoth_object = instVarOffset("SCDragBoth", "object");
2454 ivxSCTextView_linkAction = instVarOffset("SCTextView", "linkAction");
2463 background color / pic