Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / editors / scapp / iPhone / iPhoneSCView.mm
blobfbb4057eac4b49cf558bfc193dd98d13bab265a9
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 #include <UIKit/UIKit.h>
23 #include <pthread.h>
24 #include "PyrPrimitive.h"
25 #include "PyrObject.h"
26 #include "PyrKernel.h"
27 #include "PyrSymbol.h"
28 #include "GC.h"
29 #include "VMGlobals.h"
30 #include "SCBase.h"
31 #include "SC_RGen.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;
49 PyrSymbol* s_x;
50 PyrSymbol* s_y;
51 PyrSymbol* s_lo;
52 PyrSymbol* s_hi;
53 PyrSymbol* s_range;
54 PyrSymbol* s_scview;
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;
62 PyrSymbol* s_mouseUp;
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)
78     Rect qdrect;
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);
84     return qdrect;
87 CGRect SCtoCGRect(SCRect screct)
89     CGRect cgrect;
91     cgrect.origin.x    = screct.x;
92     cgrect.origin.y    = screct.y;
93     cgrect.size.width  = screct.width;
94     cgrect.size.height = screct.height;
95     return cgrect;
98 int slotColorVal(PyrSlot *slot, SCColor *sccolor)
100     if (!(isKindOfSlot(slot, s_color->u.classobj))) return errWrongType;
102     PyrSlot *slots = slotRawObject(slot)->slots;
104     int err;
105     err = slotFloatVal(slots+0, &sccolor->red);
106     if (err) return err;
107     err = slotFloatVal(slots+1, &sccolor->green);
108     if (err) return err;
109     err = slotFloatVal(slots+2, &sccolor->blue);
110     if (err) return err;
111     err = slotFloatVal(slots+3, &sccolor->alpha);
112     return err;
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);
125     return errNone;
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;
132         int err;
133         err = slotFloatVal(slots+0, &r->x);
134         if (err) return err;
135         err = slotFloatVal(slots+1, &r->y);
136         if (err) return err;
137         err = slotFloatVal(slots+2, &r->width);
138         if (err) return err;
139         err = slotFloatVal(slots+3, &r->height);
140         if (err) return err;
142         return errNone;
146 int getBackgroundVal(PyrSlot *slot, DrawBackground *inPtr);
147 int getBackgroundVal(PyrSlot *slot, DrawBackground *inPtr)
149         SetNil(slot);
150         //inPtr->GetSlot(slot);
151         return errNone;
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);
164                 if (err) return err;
166                 delete *ioPtr;
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);
173                 if (err) return err;
174                 err = slotColorVal(slots+1, &color2);
175                 if (err) return err;
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;
183                 } else {
184                         direction = grad_Horizontal;
185                 }
187                 err = slotIntVal(slots+3, &steps);
188                 if (err) return err;
190                 delete *ioPtr;
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);
198                 if (err) return err;
199                 err = slotColorVal(slots+1, &color2);
200                 if (err) return err;
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;
208                 } else {
209                         direction = grad_Horizontal;
210                 }
212                 err = slotIntVal(slots+3, &steps);
213                 if (err) return err;
215                 float frac;
216                 err = slotFloatVal(slots+4, &frac);
217                 if (err) return err;
219                 delete *ioPtr;
220                 *ioPtr = new HiliteGradientBackground(color1, color2, direction, steps, frac);
222         }
223         return errNone;
228 Layout::Layout()
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);
241         mBounds = inBounds;
242         if (inParent){
243                 inParent->add(this);
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;
250                 } else {
251                         mLayout.bounds = mBounds;
252        }
253         }
254         // store myself into sc object.
255         if (mObj) SetPtr(mObj->slots+0, this);
258 SCView::~SCView()
260         stopAnimation();
261         makeFocus(false);
262         mTop->forgetView(this);
263     if (mParent) mParent->remove(this);
264     if (mObj) SetNil(mObj->slots+0);
266     delete mBackground;
267     delete mBackgroundImage;
269         mTop = 0;
270         mParent = 0;
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");
302     if (mObj) {
303         VMGlobals *g = gMainVMGlobals;
304         g->canCallOS = true;
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;
312     }
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");
320     if (mObj) {
321         VMGlobals *g = gMainVMGlobals;
322         g->canCallOS = true;
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;
330     }
331     pthread_mutex_unlock (&gLangMutex);
334 void SCView::keyModifiersChanged(int modifiers)
336     pthread_mutex_lock (&gLangMutex);
337     PyrSymbol *method = getsym("keyModifiersChanged");
338     if (mObj) {
339         VMGlobals *g = gMainVMGlobals;
340         g->canCallOS = true;
341         ++g->sp;  SetObject(g->sp, mObj);
342         ++g->sp;  SetInt(g->sp, modifiers);
343         runInterpreter(g, method, 2);
344         g->canCallOS = false;
345     }
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];
355         int buttonNum = 0;
356     if (mObj) {
357         VMGlobals *g = gMainVMGlobals;
358         g->canCallOS = true;
359                 if(mParent->relativeOrigin()){
360                         SCRect tbounds = mParent->getDrawBounds();
361                         where.x = where.x - tbounds.x;
362                         where.y = where.y - tbounds.y;
363                 }
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;
372     }
373     pthread_mutex_unlock (&gLangMutex);
376 void SCView::touchMoveAction(SCPoint where, UITouch *touch)
378     pthread_mutex_lock (&gLangMutex);
379     PyrSymbol *method = getsym("mouseMove");
380     if (mObj) {
381         VMGlobals *g = gMainVMGlobals;
382         g->canCallOS = true;
383                 if(mParent->relativeOrigin()){
384                         SCRect tbounds = mParent->getDrawBounds();
385                         where.x = where.x - tbounds.x;
386                         where.y = where.y - tbounds.y;
387                 }
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;
394     }
395     pthread_mutex_unlock (&gLangMutex);
397 void SCView::touchUpAction(SCPoint where, UITouch *touch)
399     pthread_mutex_lock (&gLangMutex);
400     PyrSymbol *method = getsym("mouseUp");
401     if (mObj) {
402         VMGlobals *g = gMainVMGlobals;
403         g->canCallOS = true;
404                 if(mParent->relativeOrigin()){
405                         SCRect tbounds = mParent->getDrawBounds();
406                         where.x = where.x - tbounds.x;
407                         where.y = where.y - tbounds.y;
408                 }
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;
415     }
416     pthread_mutex_unlock (&gLangMutex);
420 void SCView::setConstructionModeFromPoint(SCPoint where)
422         SCRect bounds;
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];
429         }else{
430 //              [[NSCursor crosshairCursor] set];
431                 mConstructionMode = view_ResizeConstructionMode;
432         }
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) {
442                 mBounds.x = where.x;
443                 mBounds.y = where.y;
444         }
445         refresh();
446         mTop->refresh();
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");
467     if (mObj) {
468         VMGlobals *g = gMainVMGlobals;
469         g->canCallOS = true;
470                 if(mParent->relativeOrigin()){
471                         SCRect tbounds = mParent->getDrawBounds();
472                         where.x = where.x - tbounds.x;
473                         where.y = where.y - tbounds.y;
474                 }
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;
481     }
482     pthread_mutex_unlock (&gLangMutex);
485 bool SCView::canReceiveDrag()
487     return false;
490 void SCView::receiveDrag()
494 void SCView::draggingEntered (SCPoint where)
496         touchOver(where, 0);
498 void SCView::draggingUpdated (SCPoint where)
500         touchOver(where, 0);
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)
515         CGContextRef cgc;
516         CGRect rect;
517         if ( mBackground || mBackgroundImage ) {
518                 SCRect bounds;
519                 bounds = getDrawBounds();
520         cgc = (CGContextRef) UIGraphicsGetCurrentContext();
521        rect = SCtoCGRect(bounds);
522         }
524     if (mBackground)
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);
541     }
544 void SCView::drawFocus(SCRect inDamage)
546     if (isFocus()) {
547                 SCRect bounds = getDrawBounds();
548         CGRect rect = SCtoCGRect(bounds);
549         rect.origin.x -= 2;
550         rect.origin.y -= 2;
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);
561     }
566 void SCView::drawDragHilite(SCRect inDamage)
568     if (mDragHilite) {
569                 SCRect bounds = getDrawBounds();
571         CGRect rect = SCtoCGRect(bounds);
572         rect.origin.x += 2;
573         rect.origin.y += 2;
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);
582     }
585 void SCView::drawIfNecessary(SCRect inDamage)
587         if (SCRectsDoIntersect(inDamage, getDrawBounds()) && mVisible) {
588                 draw(inDamage);
589                 drawDisabled(inDamage);
590                 drawDragHilite(inDamage);
591                 drawFocus(inDamage);
592         }
595 SCView* SCView::findView(SCPoint where)
597         if (hit(where) && mEnabled && mVisible) return this;
598         else return 0;
601 SCView* SCView::findViewByID(int32 inID)
603         if (inID == mID) return this;
604         else return 0;
607 bool SCView::shouldDim()
609     return true;
612 bool SCView::canFocus()
614     bool flag = mEnabled && mVisible && mCanFocus;
615     if (mParent) flag = flag && mParent->canFocus();
616     return flag;
619 bool SCContainerView::canFocus()
621     bool flag = mEnabled && mVisible;
622     if (mParent) flag = flag && mParent->canFocus();
623     return flag;
626 SCRect CGtoSCRect(CGRect nsrect)
628         SCRect screct;
629     screct.x = nsrect.origin.x;
630     screct.y = nsrect.origin.y;
631     screct.width = nsrect.size.width;
632     screct.height = nsrect.size.height;
633     return screct;
636 void SCView::setBounds(SCRect inBounds)
638     mBounds = 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;
645         } else {
646                 mLayout.bounds = mBounds;
647         }
651 SCRect SCView::getBounds()
653         return mBounds;
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;
665 //      } else {
666 //              mLayout.bounds = mBounds;
667 //      }
668         return mLayout.bounds;
671 Layout SCView::getLayout()
673     return mLayout;
676 void SCView::makeFocus(bool focus)
678     if (focus) {
679         if (canFocus() && !isFocus()) {
680             SCView *prevFocus = mTop->focusView();
681             if (prevFocus) prevFocus->makeFocus(false);
682             mTop->focusIs(this);
683             refreshFocus();
684                         //NSView* newFirstResponder = focusResponder();
685                         //[[newFirstResponder window] makeFirstResponder:newFirstResponder];
686         }
687     } else {
688         if (isFocus()) {
689             mTop->focusIs(0);
690             refreshFocus();
691         }
692     }
695 //NSView* SCView::focusResponder() { return mTop->GetNSView(); }
697 void SCContainerView::makeFocus(bool focus)
701 SCView* SCView::nextFocus(bool *foundFocus, bool canFocus)
703     if (isFocus()) {
704         *foundFocus = true;
705         return 0;
706     }
707     canFocus = canFocus && mEnabled && mVisible && mCanFocus;
708     if (canFocus && *foundFocus) return this;
709     return 0;
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;
717     return 0;
721 void SCView::refresh()
723     mTop->addDamage(mLayout.bounds);
726 void SCView::refreshInRect(SCRect b)
728         if(SCRectsDoIntersect(b, mLayout.bounds)) {
729                 SCRect sect;
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);
737         }
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);
746     if (mObj) {
747         VMGlobals *g = gMainVMGlobals;
748         g->canCallOS = true;
749         ++g->sp;  SetObject(g->sp, mObj);
750         for (int i=0; i<numargs; ++i) {
751             ++g->sp;  slotCopy(g->sp, &args[i]);
752         }
753         runInterpreter(g, method, numargs+1);
754         g->canCallOS = false;
755         if (result) slotCopy(result, &g->result);
756     }
757     pthread_mutex_unlock (&gLangMutex);
759     //CGContextRestoreGState(cgc);
762 bool SCView::isDragSource() const
764         return false;
767 int SCView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
769     int err;
770         char *name = symbol->name;
771         if (strcmp(name, "bounds")==0) {
772                 SCRect screct;
773                 err = slotGetSCRect(slot, &screct);
774                 if (err) return err;
775                 refreshFocus();
776                 //mBounds = screct;
778                                 if(mTop->isScroller()) {
779                                         ((SCScrollTopView*)mTop)->setInSetClipViewOrigin(true);
780                                         setBounds(screct);
781                                         [(SCGraphView*)mTop->GetUIView() setFrameSizeToMinimum];
782                                         ((SCScrollTopView*)mTop)->setInSetClipViewOrigin(false);
783                                 } else {setBounds(screct);}
784                 refreshFocus();
785                 return errNone;
786         }
787         if (strcmp(name, "visible")==0) {
788                 bool visible = IsTrue(slot);
789                 if (mVisible != visible) {
790                     mVisible = visible;
791                     if (!mVisible) mTop->resetFocus(); //
792                     refresh();
793                 }
794                 return errNone;
795         }
796         if (strcmp(name, "enabled")==0) {
797                 bool enabled = IsTrue(slot);
798                 if (mEnabled != enabled) {
799                     mEnabled = enabled;
800                     if (!mEnabled) mTop->resetFocus();
801                     refresh();
802                 }
803                 return errNone;
804         }
805         if (strcmp(name, "canFocus")==0) {
806                 bool canFocus = IsTrue(slot);
807                 if (mCanFocus != canFocus) {
808                     mCanFocus = canFocus;
809                     if (!mCanFocus) mTop->resetFocus();
810                     refresh();
811                 }
812                 return errNone;
813         }
814         if (strcmp(name, "resize")==0) {
815 //  1  2  3
816 //  4  5  6
817 //  7  8  9
818             int32 resize;
819                         err = slotIntVal(slot, &resize);
820                         if (err) return err;
821             if (resize < 1 || resize > 9) return errIndexOutOfRange;
822             mLayout.mHResize = ((resize - 1) % 3) - 1;
823             mLayout.mVResize = ((resize - 1) / 3) - 1;
824             mTop->refresh();
825             return errNone;
826         }
827     if(strcmp(name,"id") ==0) {
828                 return slotIntVal(slot, &mID);
829     }
830     if(strcmp(name,"minWidth") ==0) {
831                 err = slotFloatVal(slot, &mLayout.mMinWidth);
832         mTop->refresh();
833         return err;
834     }
835     if(strcmp(name,"maxWidth") ==0) {
836                 err = slotFloatVal(slot, &mLayout.mMaxWidth);
837         mTop->refresh();
838         return err;
839     }
840     if(strcmp(name,"minHeight") ==0) {
841                 err = slotFloatVal(slot, &mLayout.mMinHeight);
842        mTop->refresh();
843         return err;
844     }
845     if(strcmp(name,"maxHeight") ==0) {
846                 err = slotFloatVal(slot, &mLayout.mMaxHeight);
847         mTop->refresh();
848         return err;
849     }
850         if (strcmp(name, "background")==0) {
851             err = slotBackgroundVal(slot, &mBackground);
852             if (err) return err;
853             refresh();
854             return errNone;
855         }
857         if (strcmp(name, "backgroundImage")==0) {
858             err = slotBackgroundImageVal(slot, &mBackgroundImage);
859             if (err) return err;
860             refresh();
861             return errNone;
862         }
864         if (strcmp(name, "focusColor")==0) {
865                         err = slotColorVal(slot, &mFocusColor);
866             if (err) return err;
867             refresh();
868                 return errNone;
869         }
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];
876                         return errNone;
877                 } else if (IsNil(slot)) {
878                         if(mDragLabel) [mDragLabel release];
879                         mDragLabel = 0;
880                         return errNone;
881                 } else return errWrongType;
882         }
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))) {
891                 return errWrongType;
892             }
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);
898             return errNone;
899         }
900         if (strcmp(name, "absoluteBounds")==0) {
901                         SCRect drawBounds;
902             if (!(isKindOfSlot(slot, s_rect->u.classobj))) {
903                 return errWrongType;
904             }
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);
911                         return errNone;
912         }
913         if (strcmp(name, "visible")==0) {
914                 SetBool(slot, mVisible);
915                 return errNone;
916         }
917         if (strcmp(name, "enabled")==0) {
918                 SetBool(slot, mEnabled);
919                 return errNone;
920         }
921         if (strcmp(name, "resize")==0) {
922             int resize = mLayout.mVResize * 3 + mLayout.mHResize + 5;
923             SetInt(slot, resize);
924             return errNone;
925         }
926         if (strcmp(name, "id")==0) {
927                 SetInt(slot, mID);
928                 return errNone;
929         }
930         /*if (strcmp(name, "background")==0) {
931             int err = getBackgroundVal(slot, mBackground);
932             return err;
933         }*/
934         /*if (strcmp(name, "backColor")==0) {
935             return setSlotColor(slot, &mBackColor);
936         }*/
938         if (strcmp(name, "focusColor")==0) {
939                 return setSlotColor(slot, &mFocusColor);;
940         }
941         return errPropertyNotFound;
944 void SCView::beginDrag(SCPoint where)
946         sendMessage(s_beginDrag, 0, 0, 0);
948         PyrSlot slot;
949         PyrSlot stringSlot;
950         NSString *string = 0;
951         NSString *label = 0;
952         pthread_mutex_lock (&gLangMutex);
953         if (mObj) {
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];
960                 }
961                 if(mDragLabel) label = mDragLabel;
962         }
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;
974         if(mParent ){
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;
979                 }
980         }
983 SCContainerView::~SCContainerView()
985     SCView *child = mChildren;
986     while (child) {
987         SCView *next = child->mNext;
988         child->mParent = 0;
989         delete child;
990         child = next;
991     }
995 int SCContainerView::setProperty(PyrSymbol *symbol, PyrSlot *slot)
997     int err;
998         char *name = symbol->name;
1000         if (strcmp(name, "visible")==0) {
1001                 bool visible = IsTrue(slot);
1002                 if (mVisible != visible) {
1003                         mVisible = visible;
1004 //                      SCView *child = mChildren;
1005 //                      while (child) {
1006 //                              SCView *next = child->mNext;
1007 //                              child->setVisibleFromParent(visible && mParent->isVisible()); // needed for Cocoa views
1008 //                              child = next;
1009 //                      }
1010                         setVisibleFromParent();
1011                         if (!mVisible) mTop->resetFocus(); //
1012                         refresh();
1013                 }
1014                 return errNone;
1015         }
1017         if (strcmp(name, "relativeOrigin")==0) {
1018                 mRelativeOrigin = IsTrue(slot);
1019                 return errNone;
1020     }
1022         return SCView::setProperty(symbol, slot);
1025 void SCContainerView::setVisibleFromParent()
1027         SCView *child = mChildren;
1028         while (child) {
1029                 SCView *next = child->mNext;
1030                 child->setVisibleFromParent(); // needed for Cocoa views
1031                 child = next;
1032         }
1035 void SCContainerView::add(SCView *inChild)
1037         inChild->mNext = mChildren;
1038         mChildren = inChild;
1039         mNumChildren++;
1040         inChild->mParent = this;
1041         inChild->mTop = mTop;
1042         inChild->refresh();
1045 void SCContainerView::remove(SCView *inChild)
1047         SCView *child = mChildren;
1048         SCView *prev = 0;
1049     inChild->makeFocus(false);
1050         while (child) {
1051                 SCView *next = child->mNext;
1052                 if (child == inChild) {
1053                         if (prev) prev->mNext = child->mNext;
1054                         else mChildren = child->mNext;
1055                         child->mParent = 0;
1056                         mNumChildren--;
1057                         return;
1058                 }
1059                 prev = child;
1060                 child = next;
1061         }
1065 void SCContainerView::drawIfNecessary(SCRect inDamage)
1067         SCRect drawBounds;
1068         drawBounds = getDrawBounds();
1069     if (SCRectsDoIntersect(inDamage, drawBounds) && mVisible) {
1070             draw(inDamage);
1071             SCView *child = mChildren;
1072                         SCView *children[mNumChildren];
1073                         int k = mNumChildren;
1074             while (child) {
1075 //              child->drawIfNecessary(inDamage);
1076                                 children[--k] = child;
1077                                 child = child->next();
1078             }
1079                         for(int i=0; i < mNumChildren; i++ ) {
1080                                 child = children[i];
1081                                 child->drawIfNecessary(inDamage);
1082                         };
1083             drawDisabled(inDamage);
1084             drawDragHilite(inDamage);
1085             drawFocus(inDamage);
1086     }
1089 SCView* SCContainerView::findView(SCPoint where)
1091         if (mEnabled && mVisible) {
1092             SCView *child = mChildren;
1093             while (child) {
1094                                 if(!(child->isScroller())) {
1095                     SCView *found = child->findView(where);
1096                     if (found) return found;
1097                                 }
1098                                 child = child->mNext;
1099             }
1100         }
1101         return 0;
1104 SCView* SCContainerView::findViewByID(int32 inID)
1106         if (inID == mID) return this;
1107         SCView *child = mChildren;
1108         while (child) {
1109                 SCView *found = child->findViewByID(inID);
1110                 if (found) return found;
1111                 child = child->mNext;
1112         }
1113         return 0;
1116 SCView* SCContainerView::nextFocus(bool *foundFocus, bool canFocus)
1118     canFocus = canFocus && mEnabled && mVisible;
1119     SCView *child = mChildren;
1120     while (child) {
1121         SCView *view = child->nextFocus(foundFocus, canFocus);
1122         if (view) return view;
1123         child = child->mNext;
1124     }
1125     return 0;
1128 SCView* SCContainerView::prevFocus(SCView **prevView, bool canFocus)
1130     canFocus = canFocus && mEnabled && mVisible;
1131     SCView *child = mChildren;
1132     while (child) {
1133         SCView *view = child->prevFocus(prevView, canFocus);
1134         if (view) return view;
1135         child = child->mNext;
1136     }
1137     return 0;
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)
1144         while (child) {
1145         SCRect bounds = child->checkMinimumSize();
1146                 candidate = SCRectUnion(bounds, candidate);
1147                 child = child->next();
1148         }
1149         return candidate;
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);
1176 //      }
1178         if(mParent ){
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;
1183                 } else {
1184                         mLayout.bounds.x = inBounds.x;
1185                         mLayout.bounds.y = inBounds.y;
1186                 }
1187         }
1188     while (child) {
1189         SCRect bounds = child->getBounds();
1190         Layout layout = child->getLayout();
1191 //        SCRect bounds = layout.bounds;
1193         float offset;
1194         switch (layout.mHResize) {
1195             case layout_FixedLeft :
1196                 break;
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
1201                                         } else {
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
1206                                                         }
1207                                                 }
1208                                         }
1210                 break;
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),
1215                                     layout.mMinWidth ,
1216                                     sc_min(layout.mMaxWidth,right - bounds.x)
1217                                 );*/
1218                 bounds.width = (inBounds.width) - ((bounds.x - mBounds.x) + offset);
1219         }
1220         switch (layout.mVResize) {
1221             case layout_FixedTop :
1222                 break;
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);
1227                                         } else {
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);
1232                                                         }
1233                                                 }
1234                                         }
1235                 break;
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),
1240                                     layout.mMinHeight ,
1241                                     sc_min(layout.mMaxHeight,bottom - bounds.y)
1242                                 );*/
1243                 bounds.height = (inBounds.height) - ((bounds.y - mBounds.y) + offset);
1244         }
1246         child->setBounds(bounds);
1247         child = child->next();
1248     }
1249     // should be limited by the limitations of the contents
1250     mBounds = inBounds;
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)
1273         int err;
1274         char *name = symbol->name;
1275         if (strcmp(name, "spacing")==0) {
1276                 err = slotFloatVal(slot, &mSpacing);
1277                 if (err) return err;
1278                 refresh();
1279                 return errNone;
1280         }
1281         if (strcmp(name, "bounds")==0) {
1282                 SCRect screct;
1283                 err = slotGetSCRect(slot, &screct);
1284                 if (err) return err;
1285                 refreshFocus();
1286                 setBounds(screct);
1287                 refreshFocus();
1288                 return errNone;
1289         }
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);
1298             return errNone;
1299         }
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
1331     mBounds = inBounds;
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;
1338         } else {
1339                 mLayout.bounds = mBounds;
1340         }
1341         SCRect absBounds = mLayout.bounds;
1342     while(child) {
1343         Layout layout = child->getLayout();
1344         // could store this when child added
1345         totalWeight += layout.mWeight;
1346         child = child->next();
1347     }
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));
1354     child = mChildren;
1355     float widths[mNumChildren];
1356     SCView *children[mNumChildren];
1357     int ri = mNumChildren;
1358     while(child) {
1359         float width;
1360         //reverse the array
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;
1367                 widths[ri]  = width;
1368                 totalWidth -= width;
1369                 totalWeight -= layout.mWeight;
1370             } else {
1371                 if (weightedWidth > layout.mMaxWidth) {
1372                     width = layout.mMaxWidth;
1373                     widths[ri]  = width;
1374                     totalWidth -= width;
1375                     totalWeight -= layout.mWeight;
1376                 } else {
1377                     widths[ri] = -1.0;
1378                 }
1379             }
1380         }  else {
1381             SCRect rect = child->getBounds();
1382             widths[ri] = rect.width;
1383         }
1384         child = child->next();
1385     }
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);
1393     child = mChildren;
1394     int i=0;
1395     for(; i < mNumChildren; i++ ) {
1396         child = children[i];
1397         Layout layout = child->getLayout();
1398         float width;
1399         if(widths[i] == -1.0) {
1400             width = scaleWeight * layout.mWeight;
1401         } else { // was constrained
1402             width = widths[i];
1403         }
1404         child->setBounds(SCMakeRect( left, top, width, height));
1405         left += (width + mSpacing);
1406         child = child->next();
1407     }
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;
1431     while(child) {
1432         Layout layout = child->getLayout();
1433         // could store this when child added
1434         totalWeight += layout.mWeight;
1435         child = child->next();
1436     }
1437         //if reativeOrigin is true, the inBounds need to be moved to absolute bounds
1438     mBounds = inBounds;
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;
1445         } else {
1446                 mLayout.bounds = mBounds;
1447         }
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));
1455     child = mChildren;
1456     float heights[mNumChildren];
1457     SCView *children[mNumChildren];
1458     int ri = mNumChildren;
1459     while(child) {
1460         float height;
1461         //reverse the array
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;
1471             } else {
1472                 if (weightedHeight > layout.mMaxHeight) {
1473                     height = layout.mMaxHeight;
1474                     heights[ri]  = height;
1475                     totalHeight -= height;
1476                     totalWeight -= layout.mWeight;
1477                 } else {
1478                     heights[ri] = -1.0;
1479                 }
1480             }
1481         }  else {
1482             SCRect rect = child->getBounds();
1483             heights[ri] = rect.height;
1484         }
1485         child = child->next();
1486     }
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);
1494     child = mChildren;
1495     int i=0;
1496     for(; i < mNumChildren; i++ ) {
1497         child = children[i];
1498         Layout layout = child->getLayout();
1499         float height;
1500         if(heights[i] == -1.0) {
1501             height = scaleWeight * layout.mWeight;
1502         } else { // was constrained
1503             height = heights[i];
1504         }
1505         child->setBounds(SCMakeRect( left, top, width, height));
1506         top += (height + mSpacing);
1507         child = child->next();
1508     }
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)
1524     mTop = this;
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();
1545     focusBounds.x -= 4;
1546     focusBounds.y -= 4;
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()) {
1556         focusIs(0);
1557         view->refreshFocus();
1558     }
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);
1587         mDragView = inView;
1588         if (mDragView) mDragView->setDragHilite(true);
1589     }
1592 void SCTopView::drawFocus(SCRect inDamage)
1594     if (ConstructionMode()) {
1595         CGRect rect = SCtoCGRect(mBounds);
1596         rect.origin.x += 2;
1597         rect.origin.y += 2;
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);
1606     }
1609 bool SCTopView::canReceiveDrag()
1611     PyrSlot result;
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.)
1636         mValue = 1.;
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);
1655 #if 1
1656     QDDrawBevelRect(cgc, rect, 1, true);
1657 #endif
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;
1673     }
1674     bool changed = inValue != mValue;
1675     if (changed) {
1676         mValue = inValue;
1677         refresh();
1679         if (send) sendMessage(s_doaction, 0, 0, 0);
1680     }
1681     return changed;
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;
1691     } else {
1692         moveableRange = bounds.height - mThumbSize - 2;
1693         value = 1. - (point.y - bounds.y - 1 - mThumbSize/2) / moveableRange;
1694     }
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);
1711     } else {
1712         mThumbRect = SCMakeRect(bounds.x + 1, bounds.y + bounds.height - offset - 1 - mThumbSize,
1713                                 bounds.width - 2, mThumbSize);
1714     }
1717 void SCSlider::touchTrack(SCPoint where, UITouch *touch)
1719     if (/*modifiers & NSCommandKeyMask*/0) {
1720         beginDrag(where);
1721     } else {
1722         setValueFromPoint(where);
1723     }
1726 int SCSlider::setProperty(PyrSymbol *symbol, PyrSlot *slot)
1728         int err;
1729         if (symbol == s_value) {
1730                 double value;
1731                 err = slotDoubleVal(slot, &value);
1732                 if (err) return err;
1733                 bool changed = setValue(value, false);
1734                 SetBool(slot, changed);
1735                 return errNone;
1736         }
1737         char *name = symbol->name;
1738         if (strcmp(name, "knobColor")==0) {
1739                 err = slotBackgroundVal(slot, &mKnob);
1740                 if (err) return err;
1741                 refresh();
1742                 return errNone;
1743         }
1744         if (strcmp(name, "step")==0) {
1745                 err = slotDoubleVal(slot, &mStepSize);
1746                 if (!err) {
1747                         mStepScale = 1. / mStepSize;
1748                         bool changed = setValue(mValue, false);
1749                         SetBool(slot, changed);
1750                 }
1751                 return errNone;
1752         }
1753         if (strcmp(name, "thumbSize")==0) {
1754                 err = slotFloatVal(slot, &mThumbSize);
1755                 if (err) return err;
1756                 refresh();
1757                 return errNone;
1758         }
1760         return SCView::setProperty(symbol, slot);
1763 int SCSlider::getProperty(PyrSymbol *symbol, PyrSlot *slot)
1765         if (symbol == s_value) {
1766         SetFloat(slot, mValue);
1767            return errNone;
1768         }
1769         char *name = symbol->name;
1770         if (strcmp(name, "step")==0) {
1771             SetFloat(slot, mStepSize);
1772             return errNone;
1773         }
1774         if (strcmp(name, "thumbSize")==0) {
1775             SetFloat(slot, mThumbSize);
1776             return errNone;
1777         }
1779         return SCView::getProperty(symbol, slot);
1784 bool SCSlider::canReceiveDrag()
1786     PyrSlot result;
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");
1810         mFontSize = 12.;
1813 SCButton::~SCButton()
1815     delete [] mStates;
1818 void SCButton::draw(SCRect inDamage)
1820     SCColor buttonColor;
1821         SCRect bounds = getDrawBounds();
1823     if (mStates) {
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);
1835     }
1836     QDDrawBevelRect(cgc, cgrect, 2, mPushed);
1837     CGContextRestoreGState(cgc);
1839         SCRect innerBounds = bounds;
1840         int inset = 2;
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);
1847     }
1850 bool SCButton::setValue(int inValue, bool send, int modifiers)
1852     bool changed = inValue != mValue;
1853     PyrSlot args[1];
1854     if (inValue < 0 || inValue >= mNumStates) inValue = 0;
1855     if (inValue != mValue || mNumStates < 2) {
1856         mValue = inValue;
1857         refresh();
1858         SetInt(args, modifiers);
1859         if (send) sendMessage(s_doaction, 1, args, 0);
1860     }
1861     return changed;
1865 void SCButton::touchTrack(SCPoint where, UITouch *touch)
1867         if (/*modifiers & NSCommandKeyMask*/0) {
1868         beginDrag(where);
1869     } else {
1870                 bool inside = hit(where);
1871                 if (inside != mPushed) {
1872                         mPushed = inside;
1873                         refresh();
1874                 }
1875         }
1878 void SCButton::touchEndTrack(SCPoint where, UITouch *touch)
1880     bool inside = hit(where);
1881     if (inside) setValue(mValue+1, true, 0);
1882     mPushed = false;
1885 int SCMakeButtonState(SCButton* view, SCButtonState *inState, PyrSlot *slot)
1887     int err;
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);
1901     if (err) {
1902         inState->mLabelColor = SCMakeColor(0,0,0,1); // black
1903     }
1905     if (slotRawObject(slot)->size < 3) return errNone;
1906     err = slotColorVal(slots+2, &inState->mButtonColor);
1907     if (err) {
1908         //inState->mButtonColor = view->getBackColor();
1909     }
1910     return errNone;
1913 int SCButton::setProperty(PyrSymbol *symbol, PyrSlot *slot)
1915         int err;
1916         if (symbol == s_value) {
1917             int value;
1918             err = slotIntVal(slot, &value);
1919             if (err) return err;
1920             bool changed = setValue(value, false, 0);
1921             SetBool(slot, changed);
1922             return errNone;
1923         }
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;
1929             float fontSize;
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;
1937             return errNone;
1938         }
1939         if (strcmp(name, "states")==0) {
1940             if (!isKindOfSlot(slot, class_array)) return errWrongType;
1942             // wipe out old
1943             delete [] mStates;
1944             mStates = 0;
1945             mNumStates = 0;
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);
1955                 if (err) {
1956                     delete [] states;
1957                     return err;
1958                 }
1959             }
1960             mStates = states;
1961             mNumStates = numStates;
1962             return errNone;
1963         }
1965         return SCView::setProperty(symbol, slot);
1968 int SCButton::getProperty(PyrSymbol *symbol, PyrSlot *slot)
1970         if (symbol == s_value) {
1971             SetInt(slot, mValue);
1972             return errNone;
1973         }
1974         //char *name = symbol->name;
1976         return SCView::getProperty(symbol, slot);
1979 bool SCButton::canReceiveDrag()
1981     PyrSlot result;
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");
2002         mFontSize = 12.;
2003         mStringColor = SCMakeColor(0,0,0,1);
2004         mEnabled = false;
2005         mCanFocus = false;
2008 SCStaticText::~SCStaticText()
2010     delete [] mString;
2013 bool SCStaticText::shouldDim()
2015     return false;
2018 void SCStaticText::draw(SCRect inDamage)
2020         SCView::draw(inDamage);
2021         SCRect bounds = getDrawBounds();
2023         drawString(bounds);
2026 void SCStaticText::drawString(SCRect bounds)
2028     if (mString) {
2029         if (mAlignment < 0) {
2030             stringDrawLeftInRect(mString, bounds, mFontName, mFontSize, mStringColor);
2031         } else if (mAlignment > 0) {
2032             stringDrawRightInRect(mString, bounds, mFontName, mFontSize, mStringColor);
2033         } else {
2034             stringDrawCenteredInRect(mString, bounds, mFontName, mFontSize, mStringColor);
2035         }
2036     }
2039 int allocSlotStrVal(PyrSlot *slot, char **str)
2041         int len;
2042         if (*str) {
2043                 delete [] *str;
2044                 *str = 0;
2045         }
2046         if (IsSym(slot)) {
2047                         len = strlen(slotRawSymbol(slot)->name);
2048                         *str = new char[len+1];
2049                         strcpy(*str, slotRawSymbol(slot)->name);
2050                         return errNone;
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);
2055                         (*str)[len] = 0;
2056                         return errNone;
2057         }
2058         return errWrongType;
2061 int SCStaticText::setProperty(PyrSymbol *symbol, PyrSlot *slot)
2063         int err;
2064         char *name = symbol->name;
2065         if (strcmp(name, "string")==0) {
2066                         err = allocSlotStrVal(slot, &mString);
2067                         if (err) return err;
2068                         refresh();
2069                         return errNone;
2070                 }
2071         if (strcmp(name, "font")==0) {
2072                         if (!isKindOfSlot(slot, getsym("SCFont")->u.classobj)) return errWrongType;
2073                         PyrSlot *slots = slotRawObject(slot)->slots;
2075                         float fontSize;
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;
2083                         refresh();
2084                         return errNone;
2085                 }
2086         if (strcmp(name, "stringColor")==0) {
2087                 err = slotColorVal(slot, &mStringColor);
2088                                 if (err) return err;
2089                                 refresh();
2090                 return errNone;
2091         }
2092         if (strcmp(name, "align")==0) {
2093                                 int align;
2094                                 if (IsSym(slot)) {
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;
2099                                 } else {
2100                                         err = slotIntVal(slot, &align);
2101                                         if (err) return err;
2102                                         mAlignment = align;
2103                                 }
2104                                 refresh();
2105                 return errNone;
2106                 }
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);
2116         }
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
2132         mEnabled = true;
2133         mCanFocus = true;
2136 SCNumberBox::~SCNumberBox()
2140 bool SCNumberBox::shouldDim()
2142     return true;
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;
2161         sbounds.x += 2;
2162         sbounds.width -= 4;
2163     drawString(sbounds);
2166 //int SCNumberBox::setProperty(PyrSymbol *symbol, PyrSlot *slot)
2168 //      int err;
2169 //      char *name = symbol->name;
2170 //      if (strcmp(name, "boxColor")==0) {
2171 //              err = slotColorVal(slot, &mBoxColor);
2172 //                if (err) return err;
2173 //                refresh();
2174 //              return errNone;
2175 //      }
2176 //       return SCStaticText::setProperty(symbol, slot);
2179 void SCNumberBox::touchTrack(SCPoint where, UITouch *touch)
2182     if (modifiers & NSCommandKeyMask) {
2183         beginDrag(where);
2184     }
2188 //int SCNumberBox::getProperty(PyrSymbol *symbol, PyrSlot *slot)
2190 //      char *name = symbol->name;
2191 //      if (strcmp(name, "boxColor")==0) {
2192 //             return setSlotColor(slot, &mBoxColor);
2193 //       }
2194 //        return SCStaticText::getProperty(symbol, slot);
2197 bool SCNumberBox::canReceiveDrag()
2199     PyrSlot result;
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;
2220         while (maker) {
2221         if (strcmp(classname, maker->mName) == 0) {
2222             return (maker->mCtor)(inParent, inObj, inBounds);
2223         }
2224         maker = maker->mNext;
2225         }
2226         return 0;
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
2255         PyrSlot parentSlot;
2256         SCContainerView *parent;
2257         if (isKindOfSlot(args, s_sctopview->u.classobj) && !isKindOfSlot(args, s_scscrollview->u.classobj)) {
2258                 parent = 0;
2259         } else {
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);
2265         }
2266         if (!(isKindOfSlot(args+2, s_rect->u.classobj))) return errWrongType;
2268         SCRect bounds;
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;
2274         return errNone;
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]);
2294         return err;
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]);
2314         return errNone;
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;
2323         PyrSlot *b = g->sp;
2325         SCView *view = (SCView*)slotRawPtr(slotRawObject(a)->slots);
2326         if (!view) return errFailed;
2328         int32 tag;
2329         int err = slotIntVal(b, &tag);
2330         if (err) return err;
2332         view = view->findViewByID(tag);
2333         if (!view) {
2334                 SetNil(a);
2335         } else {
2336                 SetObjectOrNil(a, view->GetSCObj());
2337         }
2339         return errNone;
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));
2353         return errNone;
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());
2366         return errNone;
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;
2376         view->refresh();
2377         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;
2384         SCRect r;
2385         SCView *view = (SCView*)slotRawPtr(slotRawObject(&(g->sp - 1)[0])->slots);
2387         if(slotGetSCRect(g->sp, &r) != noErr)
2388                 return errFailed;
2390         view->refreshInRect(r);
2391         return errNone;
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
2404         delete view;
2405         return errNone;
2408 void initSCViewPrimitives()
2411         registerSCViewClasses();
2413         int base, index;
2415         s_x = getsym("x");
2416         s_y = getsym("y");
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();
2433         index = 0;
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;
2448 void initGUI();
2449 void initGUI()
2452         ivxSCDragSource_object = instVarOffset("SCDragSource", "object");
2453         ivxSCDragBoth_object = instVarOffset("SCDragBoth", "object");
2454         ivxSCTextView_linkAction = instVarOffset("SCTextView", "linkAction");
2461 loose ends
2462 drag/drop views
2463 background color / pic
2465 new views
2466     larger text view
2467     scope view
2468     plot view
2469         graph limits
2470         grid on/off
2471         data 1d, 2d
2472             color
2473     hdivider
2474     vdivider
2475     overlay view