deprecate SCViewHolder-layRight
[supercollider.git] / SCClassLibrary / Common / GUI / osx / scide_scapp / Base / SCView.sc
blob19071847e06229505016a89ad9b6baf277957d04
1 SCView {  // abstract class
2         classvar <>currentDrag, <>currentDragString;
3         classvar <>globalKeyDownAction, <>globalKeyUpAction;
5         var dataptr, <parent, <>action, <background;
6         var <>mouseDownAction, <>mouseUpAction, <>mouseOverAction, <>mouseMoveAction;
7         var <>keyDownAction, <>keyUpAction, <>keyTyped, <> keyModifiersChangedAction;
8         var <>beginDragAction, <>canReceiveDragHandler, <>receiveDragHandler;
9         var <>onClose;
11         *new { arg parent, bounds;
12                 ^super.new.init(parent, bounds);
13         }
15         *viewClass { ^this }
17         *paletteExample { arg parent, bounds;
18                 ^this.new(parent, bounds);
19         }
21         init { arg argParent, argBounds;
22                 parent = argParent.asView; // actual view
23                 background = Color.clear;
24                         // call asView again because parent by this point might be a FlowView
25                 this.prInit(parent.asView, argBounds.asRect, this.class.viewClass);
26                 argParent.add(this);//maybe window or viewadapter
27         }
29         asView { ^this }
31         bounds {
32                 ^this.getProperty(\bounds, Rect.new)
33         }
34         bounds_ { arg rect;
35                 this.setProperty(\bounds, rect)
36         }
38         visible {
39                 ^this.getProperty(\visible)
40         }
41         visible_ { arg bool;
42                 this.setProperty(\visible, bool)
43         }
45         enabled {
46                 ^this.getProperty(\enabled)
47         }
48         enabled_ { arg bool;
49                 this.setProperty(\enabled, bool)
50         }
52         canFocus {
53                 ^this.getProperty(\canFocus)
54         }
55         canFocus_ { arg bool;
56                 this.setProperty(\canFocus, bool)
57         }
59         focus { arg flag=true;
60                 _SCView_Focus
61                 ^this.primitiveFailed
62         }
64         hasFocus {
65                 _SCView_HasFocus
66                 ^this.primitiveFailed
67         }
69         focusColor_ { |color|
70                 this.setProperty(\focusColor, color)
71         }
72         focusColor {
73                 ^this.getProperty(\focusColor, Color.new)
74         }
76         id {
77                 ^this.getProperty(\id)
78         }
79         id_ { arg id;
80                 this.setProperty(\id, id)
81         }
83         dragLabel_ { arg string;
84                 this.setProperty(\dragLabel, string)
85         }
87         refresh {
88                 _SCView_Refresh
89                 ^this.primitiveFailed
90         }
92         findByID { arg id;
93                 _SCView_FindByID
94                 ^this.primitiveFailed
95         }
97         isClosed { ^dataptr.isNil }
98         notClosed { ^dataptr.notNil }
99         remove {
100                 if(dataptr.notNil) {
101                         parent.prRemoveChild(this);
102                         this.prRemove;
103                         this.prClose;
104                 } {
105                         "SCView-remove : this view already removed.".debug(this);
106                 }
107         }
108         /*
109         resize behaviour in an SCCompositeView:
110                 1  2  3
111                 4  5  6
112                 7  8  9
114                 1 - fixed to left, fixed to top
115                 2 - horizontally elastic, fixed to top
116                 3 - fixed to right, fixed to top
118                 4 - fixed to left, vertically elastic
119                 5 - horizontally elastic, vertically elastic
120                 6 - fixed to right, vertically elastic
122                 7 - fixed to left, fixed to bottom
123                 8 - horizontally elastic, fixed to bottom
124                 9 - fixed to right, fixed to bottom
125         */
127         resize {
128                 ^this.getProperty(\resize)
129         }
131         resize_ { arg resize;
132                 this.setProperty(\resize, resize)
133         }
135         background_ { arg color;
136                 background = color;
137                 this.setProperty(\background, color)
138         }
140         addAction { arg func, selector=\action;
141                 this.perform(selector.asSetter, this.perform(selector).addFunc(func));
142         }
144         removeAction { arg func, selector=\action;
145                 this.perform(selector.asSetter, this.perform(selector).removeFunc(func));
146         }
148         mouseDown { arg x, y, modifiers, buttonNumber, clickCount;
149                 mouseDownAction.value(this, x, y, modifiers, buttonNumber, clickCount);
150         }
152         mouseUp { arg x, y, modifiers;
153                 mouseUpAction.value(this, x, y, modifiers)
154         }
156         mouseMove { arg x, y, modifiers;
157                 mouseMoveAction.value(this, x, y, modifiers)
158         }
160         mouseOver { arg x, y;
161                 mouseOverAction.value(this, x, y);
162         }
164         keyDown { arg char, modifiers, unicode, keycode;
165                 globalKeyDownAction.value(this, char, modifiers, unicode, keycode);
166                 this.handleKeyDownBubbling(this, char, modifiers, unicode, keycode);
167         }
169         keyModifiersChanged { arg modifiers;
170                 this.handleKeyModifiersChangedBubbling(this, modifiers)
171         }
173         handleKeyModifiersChangedBubbling { arg view, modifiers;
174                 var result;
175                 // nil from keyDownAction --> pass it on
176                 if (keyModifiersChangedAction.isNil) {
177 //                      this.defaultKeyDownAction(char, modifiers, unicode, keycode);
178                         result = nil;
179                 } {
180                         result = keyModifiersChangedAction.value(view, modifiers);
181                 };
182                 if(result.isNil) {
183                         // call keydown action of parent view
184                         parent.handleKeyModifiersChangedBubbling(view, modifiers);
185                 };
186         }
188         defaultKeyDownAction { ^nil }
190         handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
191                 var result;
192                 // nil from keyDownAction --> pass it on
193                 if (keyDownAction.isNil) {
194                         result = this.defaultKeyDownAction(char, modifiers, unicode, keycode);
195                 } {
196                         result = keyDownAction.value(view, char, modifiers, unicode, keycode);
197                 };
198                 if(result.isNil) {
199                         // call keydown action of parent view
200                         parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode);
201                 };
202         }
204         // sc.solar addition
205         keyUp { arg char, modifiers, unicode, keycode;
206                 this.keyTyped = char;
207                 // always call global keydown action first
208                 globalKeyUpAction.value(this, char, modifiers, unicode, keycode);
209                 this.handleKeyUpBubbling(this, char, modifiers, unicode, keycode);
210         }
212         defaultKeyUpAction { ^nil }
214         handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
215                 var result;
216                 // nil from keyDownAction --> pass it on
217                 if (keyUpAction.isNil) {
218                         result = this.defaultKeyUpAction(char, modifiers, unicode, keycode);
219                 } {
220                         result = keyUpAction.value(view, char, modifiers, unicode, keycode);
221                 };
222                 if(result.isNil) {
223                         // call keydown action of parent view
224                         parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode);
225                 };
226         }
228         beginDrag {
229                 currentDrag = if (beginDragAction.notNil)
230                  {
231                         beginDragAction.value(this)
232                 } {
233                         this.defaultGetDrag
234                 };
235                 currentDragString = currentDrag.asCompileString;
236         }
238         defaultGetDrag { ^nil }
240         canReceiveDrag {
241                 ^if(canReceiveDragHandler.notNil) {
242                         canReceiveDragHandler.value(this)
243                 } {
244                         this.defaultCanReceiveDrag
245                 }
246         }
247         defaultCanReceiveDrag { ^false }
248         receiveDrag { |x, y|
249                 if(receiveDragHandler.notNil) {
250                         receiveDragHandler.value(this, x, y)
251                 } {
252                         this.defaultReceiveDrag(x, y)
253                 };
254                 currentDrag = currentDragString = nil;
255         }
257         // get the view parent tree up to the SCTopView
258         getParents {
259                 var parents, view;
260                 view = this;
261                 parents = List.new;
262                 while( {(view = view.asView.parent).notNil}, { parents.add(view)});
263                 ^parents
264         }
266         doAction {
267                 action.value(this);
268         }
270         properties {
271                 ^#[\bounds, \visible, \enabled, \canFocus, \resize, \background,
272                                 \minWidth, \maxWidth, \minHeight, \maxHeight, \focusColor]
273         }
275         getPropertyList {
276                 ^this.properties.collect( { arg name;
277                         [name, this.perform(name)]
278                 });
279         }
281         setPropertyList { arg list;
282                 list.do( { arg item;
283                         var name, value;
284                         #name, value = item;
285                         this.perform(name.asSetter, value);
286                 });
287         }
289         // private
290         prInit { arg argParent, argBounds, argViewClass;
291                 _SCView_New
292                 ^this.primitiveFailed
293         }
295         prClose { dataptr = nil; onClose.value(this); }
296         prRemove {
297                 _SCView_Remove
298                 ^this.primitiveFailed
299         }
300         setProperty { arg key, value;
301                 _SCView_SetProperty
302                 ^this.primitiveFailed
303         }
304         getProperty { arg key, value;
305                 _SCView_GetProperty
306                 ^this.primitiveFailed
307         }
308         setPropertyWithAction { arg symbol, obj;
309                 // setting some properties may need to have the action called.
310                 if (this.setProperty(symbol, obj), {
311                         // setProperty returns true if action needs to be called.
312                         this.doAction;
313                 });
314         }
316 //      *importDrag {
317 //              // this is called when an NSString is the drag object
318 //              // from outside of the SC app
319 //              // we compile it to an SCObject.
320 //              currentDragString = currentDrag;
321 //              currentDrag = currentDrag.interpret;
322 //      }
324         absoluteBounds {
325                 ^this.getProperty(\absoluteBounds, Rect.new)
326         }
329 SCContainerView : SCView { // abstract class
331         var <children, <decorator;
333         add { arg child;
334                 children = children.add(child);
335                 if (decorator.notNil, { decorator.place(child); });
336         }
338         init { arg argParent, argBounds;
339                 super.init(argParent, argBounds);
340         }
342         removeAll {
343                 children.copy.do { |child| child.remove };
344         }
346         addFlowLayout { arg margin, gap;
347                 this.decorator_( FlowLayout( this.bounds.moveTo(0, 0), margin, gap ) );
348                 ^this.decorator;
349                 }
351         decorator_ { arg decor;
352                 decor.bounds = decor.bounds.moveTo(0, 0);
353                 decor.reset;
354                 decorator = decor;
355         }
357         prRemoveChild { arg child;
358                 children.remove(child);
359                 // ... decorator should re-place all
360         }
362         //bounds_  ... replace all
364         prClose {
365                 super.prClose;
366                 children.do( { arg item; item.prClose });
367         }
371 SCCompositeView : SCContainerView {
374 SCTopView : SCCompositeView {
376         // created by SCWindow
377         handleKeyModifiersChangedBubbling { arg view, modifiers;
378                 keyModifiersChangedAction.value(view, modifiers);
379         }
380         handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
381                 var currentAppModal, window;
382                 keyDownAction.value(view, char, modifiers, unicode, keycode);
383         }
384         handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
385                 keyUpAction.value(view, char, modifiers, unicode, keycode);
386         }
388         //only in construction mode, handled internally
389         canReceiveDrag { ^currentDrag.isKindOf(Class)}
390 //      remove { this.removeAll }
392         findWindow {
393                 SCWindow.allWindows.do { |win|
394                         if(win.view == this) {
395                                 ^win
396                         }
397                 }
398         }
400         /* construction mode */
402         constructionGrid_ { arg point;
403                 this.setProperty( \constructionGrid, point );
404         }
406         constructionGrid {
407                 ^this.getProperty( \constructionGrid, Point.new );
408         }
410         enableConstructionGrid_ { arg flag;
411                 this.setProperty( \enableConstructionGrid, flag );
412         }
414         enableConstructionGrid {
415                 ^this.getProperty( \enableConstructionGrid );
416         }
418         //private called from lang
419         setConstructionMode { |flag|
420                 this.setProperty( \setConstructionMode, flag )
421         }
423         defaultReceiveDrag { |x, y|
424                 var win, view;
425                 win = this.findWindow;
426                 view = currentDrag.paletteExample(win, Rect(x, y, 140, 24)).enabled_(false);
427                 view.keyDownAction_( { |view, char, modifiers, unicode, keycode|
428                         if(keycode == 51) {
429                                 view.remove;
430                         }
431                 });
432         }
435 SCScrollTopView : SCTopView {
436         var <autohidesScrollers = true, <hasHorizontalScroller = true, <hasVerticalScroller = true;
437         var <autoScrolls = true;
439         autohidesScrollers_ { |bool|
440                 autohidesScrollers = bool;
441                 this.setProperty(\setAutohidesScrollers, bool);
442         }
444         hasHorizontalScroller_ { |bool|
445                 hasHorizontalScroller = bool;
446                 this.setProperty(\setHasHorizontalScroller, bool);
447         }
449         hasVerticalScroller_ { |bool|
450                 hasVerticalScroller = bool;
451                 this.setProperty(\setHasVerticalScroller, bool);
452         }
454         visibleOrigin_ { arg point;
455                 this.setProperty( \clipViewOrigin, point );
456         }
458         visibleOrigin { ^this.getProperty( \clipViewOrigin, Point.new );}
460         autoScrolls_ { |bool|
461                 autoScrolls = bool;
462                 this.setProperty(\setAutoScrolls, bool);
463         }
465         innerBounds {
466                 ^this.getProperty(\innerBounds, Rect.new)
467         }
469         bounds {
470                 var     bounds = this.absoluteBounds;
471                 this.getParents.do( { |parent|
472                         bounds = bounds.moveBy(parent.bounds.left.neg, parent.bounds.top.neg)
473                 });
474                 ^bounds
475         }
477 //      handleKeyModifiersChangedBubbling { arg view, modifiers;
478 //              var result;
479 //              // nil from keyDownAction --> pass it on
480 //              if (keyModifiersChangedAction.isNil) {
481 //                      result = nil;
482 //              } {
483 //                      result = keyModifiersChangedAction.value(view, modifiers);
484 //              };
485 //              if(result.isNil) {
486 //                      // call keydown action of parent view
487 //                      parent.handleKeyModifiersChangedBubbling(view, modifiers);
488 //              };
489 //      }
491 //      handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
492 //              var result;
493 //              // nil from keyDownAction --> pass it on
494 //              if (keyDownAction.isNil) {
495 //                      result = this.defaultKeyDownAction(char, modifiers, unicode, keycode);
496 //              } {
497 //                      result = keyDownAction.value(view, char, modifiers, unicode, keycode);
498 //              };
499 //              if(result.isNil) {
500 //                      // call keydown action of parent view
501 //                      parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode);
502 //              };
503 //      }
505 //      handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
506 //              var result;
507 //              // nil from keyDownAction --> pass it on
508 //              if (keyUpAction.isNil) {
509 //                      result = this.defaultKeyUpAction(char, modifiers, unicode, keycode);
510 //              } {
511 //                      result = keyUpAction.value(view, char, modifiers, unicode, keycode);
512 //              };
513 //              if(result.isNil) {
514 //                      // call keydown action of parent view
515 //                      parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode);
516 //              };
517 //      }
521 SCScrollView : SCScrollTopView {
522         var <hasBorder = false;
524         hasBorder_ { arg bool = true;
525                 this.setProperty(\border, bool);
526         }
528         init { |argParent, argBounds|
529                 super.init(argParent, argBounds);
530         }
532         handleKeyModifiersChangedBubbling { arg view, modifiers;
533                 var result;
534                 // nil from keyDownAction --> pass it on
535                 if (keyModifiersChangedAction.isNil) {
536                         result = nil;
537                 } {
538                         result = keyModifiersChangedAction.value(view, modifiers);
539                 };
540                 if(result.isNil) {
541                         // call keydown action of parent view
542                         parent.handleKeyModifiersChangedBubbling(view, modifiers);
543                 };
544         }
546         handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
547                 var result;
548                 // nil from keyDownAction --> pass it on
549                 if (keyDownAction.isNil) {
550                         result = this.defaultKeyDownAction(char, modifiers, unicode, keycode);
551                 } {
552                         result = keyDownAction.value(view, char, modifiers, unicode, keycode);
553                 };
554                 if(result.isNil) {
555                         // call keydown action of parent view
556                         parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode);
557                 };
558         }
560         handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
561                 var result;
562                 // nil from keyDownAction --> pass it on
563                 if (keyUpAction.isNil) {
564                         result = this.defaultKeyUpAction(char, modifiers, unicode, keycode);
565                 } {
566                         result = keyUpAction.value(view, char, modifiers, unicode, keycode);
567                 };
568                 if(result.isNil) {
569                         // call keydown action of parent view
570                         parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode);
571                 };
572         }
576 SCLayoutView : SCContainerView {
577         properties { ^super.properties ++ #[\spacing] }
579         spacing {
580                 ^this.getProperty(\spacing, 0)
581         }
582         spacing_ { arg distance;
583                 this.setProperty(\spacing, distance)
584         }
585         setProperty { |key, value|
586                 super.setProperty(key, value);
587         }
590 SCHLayoutView : SCLayoutView {}
591 SCVLayoutView : SCLayoutView {}
594 SCControlView : SCView { // abstract class
597 SCSliderBase : SCControlView {
599         var <>shift_scale = 100.0, <>ctrl_scale = 10.0, <>alt_scale = 0.1;
601         getScale { |modifiers|
602                 ^case
603                          { modifiers & 131072 == 131072 } { shift_scale }
604                          { modifiers & 262144 == 262144 } { ctrl_scale }
605                          { modifiers & 524288 == 524288 } { alt_scale }
606                          { 1 };
607         }
609         knobColor {
610                 ^this.getProperty(\knobColor, Color.new)
611         }
612         knobColor_ { arg color;
613                 this.setProperty(\knobColor, color)
614         }
616         step_ { arg stepSize;
617         //      this.setPropertyWithAction(\step, stepSize); // action really needed?
618                 this.setProperty(\step, stepSize);
619         }
621         step {
622                 ^this.getProperty(\step)
623         }
625         properties {
626                 ^super.properties ++ #[\knobColor, \step]
627         }
631 SCSlider : SCSliderBase {
633         value {
634                 ^this.getProperty(\value)
635         }
636         value_ { arg val;
637                 this.setProperty(\value, val);
638         }
639         valueAction_ { arg val;
640                 this.setPropertyWithAction(\value, val);
641         }
643         increment { |zoom=1| ^this.valueAction = this.value + (max(this.step, this.pixelStep) * zoom) }
644         decrement { |zoom=1| ^this.valueAction = this.value - (max(this.step, this.pixelStep) * zoom) }
646         pixelStep {
647                 var bounds = this.bounds;
648                 ^(bounds.width.max(bounds.height) - this.thumbSize).reciprocal
649         }
651         defaultKeyDownAction { arg char, modifiers, unicode, keycode;
652                 var zoom = this.getScale(modifiers);
654                 // standard keydown
655                         // rand could also use zoom factors
656                 if (char == $r, { this.valueAction = 1.0.rand; ^this });
657                 if (char == $n, { this.valueAction = 0.0; ^this });
658                 if (char == $x, { this.valueAction = 1.0; ^this });
659                 if (char == $c, { this.valueAction = 0.5; ^this });
661                 if (char == $], { this.increment(zoom); ^this });
662                 if (char == $[, { this.increment(zoom); ^this });
663                 if (unicode == 16rF700, { this.increment(zoom); ^this });
664                 if (unicode == 16rF703, { this.increment(zoom); ^this });
665                 if (unicode == 16rF701, { this.decrement(zoom); ^this });
666                 if (unicode == 16rF702, { this.decrement(zoom); ^this });
668                 ^nil            // bubble if it's an invalid key
669         }
671         defaultGetDrag {
672                 ^this.value
673         }
674         defaultCanReceiveDrag {
675                 ^currentDrag.isNumber
676         }
677         defaultReceiveDrag {
678                 this.valueAction = currentDrag;
679         }
681         thumbSize {
682                 ^this.getProperty(\thumbSize, 12);
683         }
684         thumbSize_ { arg size;
685                 this.setProperty(\thumbSize, size);
686         }
688         properties {
689                 ^super.properties ++ #[\thumbSize];
690         }
693 SCRangeSlider : SCSliderBase {
695         *paletteExample { arg parent, bounds;
696                 var v;
697                 v = this.new(parent, bounds);
698                 v.lo = 0.2;
699                 v.hi = 0.7;
700                 ^v
701         }
703         lo {
704                 ^this.getProperty(\lo)
705         }
706         lo_ { arg val;
707                 this.setProperty(\lo, val);
708         }
709         activeLo_ { arg val;
710                 this.setPropertyWithAction(\lo, val);
711         }
712         hi {
713                 ^this.getProperty(\hi)
714         }
715         hi_ { arg val;
716                 this.setProperty(\hi, val);
717         }
718         activeHi_ { arg val;
719                 this.setPropertyWithAction(\hi, val);
720         }
721         range {
722                 ^this.getProperty(\range)
723         }
724         range_ { arg val;
725                 this.setProperty(\range, val);
726         }
727         activeRange_ { arg val;
728                 this.setPropertyWithAction(\range, val);
729         }
731         setSpan { arg lo, hi;
732                 this.lo = lo;
733                 this.hi = hi;
734         }
736         setSpanActive { arg lo, hi;
737                 this.setSpan( lo, hi );
738                 this.doAction;
739         }
741         setDeviation { arg deviation, average;
742                         var lo = ( 1 - deviation ) * average;
743                         this.setSpan(lo, lo + deviation);
744         }
746         properties {
747                 ^super.properties ++ #[\lo, \hi]
748         }
750         pixelStep {
751                 var bounds = this.bounds;
752                 ^(bounds.width.max(bounds.height)).reciprocal
753         }
755         increment { |zoom=1|
756                 var inc = (max(this.step, this.pixelStep) * zoom);
757                 var newHi = (this.hi + inc);
758                 if (newHi > 1) {
759                         inc = 1 - this.hi;
760                         newHi = 1;
761                 };
762                 this.lo_(this.lo + inc).activeHi_(newHi);
763         }
765         decrement { |zoom=1|
766                 var inc = (max(this.step, this.pixelStep) * zoom);
767                 var newLo = (this.lo - inc);
768                 if (newLo < 0) {
769                         inc =  this.lo;
770                         newLo = 0;
771                 };
772                 this.lo_(newLo).activeHi_(this.hi - inc);
773         }
775         defaultKeyDownAction { arg char, modifiers, unicode;
776                 var a, b;
777                 var zoom = this.getScale(modifiers);
778                 // standard keydown
779                 if (char == $r, {
780                         a = 1.0.rand;
781                         b = 1.0.rand;
782                         this.activeLo_(min(a, b));
783                         this.activeHi_(max(a, b));
784                         ^this
785                 });
786                 if (char == $n, { this.activeLo_(0.0); this.activeHi_(0.0); ^this });
787                 if (char == $x, { this.activeLo_(1.0); this.activeHi_(1.0); ^this });
788                 if (char == $c, { this.activeLo_(0.5); this.activeHi_(0.5); ^this });
789                 if (char == $a, { this.activeLo_(0.0); this.activeHi_(1.0); ^this });
790                 if (unicode == 16rF700, { this.increment(zoom); ^this });
791                 if (unicode == 16rF703, { this.increment(zoom); ^this });
792                 if (unicode == 16rF701, { this.decrement(zoom); ^this });
793                 if (unicode == 16rF702, { this.decrement(zoom); ^this });
794                 ^nil            // bubble if it's an invalid key
795         }
796         defaultGetDrag { ^Point(this.lo, this.hi) }
797         defaultCanReceiveDrag {
798                 ^currentDrag.isKindOf(Point);
799         }
800         defaultReceiveDrag {
801                 // changed to x, y instead of lo, hi
802                 this.lo = currentDrag.x;
803                 this.hi = currentDrag.y;
804                 this.doAction
805         }
808 SC2DSlider : SCSliderBase {
809         x {
810                 ^this.getProperty(\x)
811         }
812         x_ { arg val;
813                 this.setProperty(\x, val);
814         }
815         activex_ { arg val;
816                 this.setPropertyWithAction(\x, val);
817         }
818         y {
819                 ^this.getProperty(\y)
820         }
821         y_ { arg val;
822                 this.setProperty(\y, val);
823         }
824         activey_ { arg val;
825                 this.setPropertyWithAction(\y, val);
826         }
828         setXY { arg x, y;
829                 this.x = x;
830                 this.y = y;
831         }
833         setXYActive { arg x, y;
834                 this.setXY( x, y );
835                 this.doAction;
836         }
838         properties {
839                 ^super.properties ++ #[\x, \y]
840         }
842         pixelStepX { ^(this.bounds.width).reciprocal }
843         pixelStepY { ^(this.bounds.height).reciprocal }
845         incrementY { |zoom=1| ^this.y = this.y + (this.pixelStepY * zoom) }
846         decrementY { |zoom=1| ^this.y = this.y - (this.pixelStepY * zoom) }
847         incrementX { |zoom=1| ^this.x = this.x + (this.pixelStepX * zoom) }
848         decrementX { |zoom=1| ^this.x = this.x - (this.pixelStepX * zoom) }
850         defaultKeyDownAction { arg char, modifiers, unicode, keycode;
851                 var zoom = this.getScale(modifiers);
852                 // standard keydown
853                 if (char == $r, { this.x = 1.0.rand; this.y = 1.0.rand; ^this });
854                 if (char == $n, { this.x = 0.0; this.y = 0.0; ^this });
855                 if (char == $x, { this.x = 1.0; this.y = 1.0; ^this });
856                 if (char == $c, { this.x = 0.5; this.y = 0.5; ^this });
857                 if (unicode == 16rF700, { this.incrementY(zoom); ^this });
858                 if (unicode == 16rF703, { this.incrementX(zoom); ^this });
859                 if (unicode == 16rF701, { this.decrementY(zoom); ^this });
860                 if (unicode == 16rF702, { this.decrementX(zoom); ^this });
861                 ^nil            // bubble if it's an invalid key
862         }
863         defaultGetDrag {
864                 ^Point(this.x, this.y)
865         }
866         defaultCanReceiveDrag {
867                 ^currentDrag.isKindOf(Point);
868         }
869         defaultReceiveDrag {
870                 this.setXYActive(currentDrag.x, currentDrag.y);
871         }
874 SC2DTabletSlider : SC2DSlider {
876 //      var <>mouseDownAction, <>mouseUpAction;
878         mouseDown { arg x, y, pressure, tiltx, tilty, deviceID,
879                          buttonNumber, clickCount, absoluteZ, rotation;
880                 mouseDownAction.value(this, x, y, pressure, tiltx, tilty, deviceID,
881                         buttonNumber, clickCount, absoluteZ, rotation);
882         }
883         mouseUp { arg x, y, pressure, tiltx, tilty, deviceID,
884                         buttonNumber, clickCount, absoluteZ, rotation;
885                 mouseUpAction.value(this, x, y, pressure, tiltx, tilty, deviceID,
886                         buttonNumber, clickCount, absoluteZ, rotation);
887         }
888         doAction { arg x, y, pressure, tiltx, tilty, deviceID,
889                         buttonNumber, clickCount, absoluteZ, rotation;
890                 action.value(this, x, y, pressure, tiltx, tilty, deviceID,
891                         buttonNumber, clickCount, absoluteZ, rotation);
892         }
895 SCButton : SCControlView {
896         var <font, <states;
898         *paletteExample { arg parent, bounds;
899                 var v;
900                 v = this.new(parent, bounds);
901                 v.states = [
902                         ["Push", Color.black, Color.red],
903                         ["Pop", Color.white, Color.blue]];
904                 ^v
905         }
907         value {
908                 ^this.getProperty(\value)
909         }
910         value_ { arg val;
911                 this.setProperty(\value, val);
912         }
913         valueAction_ { arg val;
914                 this.setPropertyWithAction(\value, val);
915         }
917         doAction { arg modifiers;
918                 action.value(this, modifiers);
919         }
921         defaultKeyDownAction { arg char, modifiers, unicode;
922                 if (char == $ , { this.valueAction = this.value + 1; ^this });
923                 if (char == $\r, { this.valueAction = this.value + 1; ^this });
924                 if (char == $\n, { this.valueAction = this.value + 1; ^this });
925                 if (char == 3.asAscii, { this.valueAction = this.value + 1; ^this });
926                 ^nil            // bubble if it's an invalid key
927         }
929         font_ { arg argFont;
930                 font = argFont;
931                 this.setProperty(\font, font)
932         }
934         states_ { arg array;
935                 states = array;
936                 this.setProperty(\states, states);
937         }
939         properties {
940                 ^super.properties ++ #[\value, \font, \states]
941         }
943         defaultGetDrag {
944                 ^this.value
945         }
946         defaultCanReceiveDrag {
947                 ^currentDrag.isNumber or: { currentDrag.isKindOf(Function) };
948         }
949         defaultReceiveDrag {
950                 if (currentDrag.isNumber) {
951                         this.valueAction = currentDrag;
952                 } {
953                         this.action = currentDrag;
954                 };
955         }
959 SCPopUpMenu : SCControlView {
960         var <font, <items;
962         *paletteExample { arg parent, bounds;
963                 var v;
964                 v = this.new(parent, bounds);
965                 v.items = #["linear", "exponential", "sine", "welch", "squared", "cubed"];
966                 ^v
967         }
969         value {
970                 ^this.getProperty(\value)
971         }
972         value_ { arg val;
973                 this.setProperty(\value, val);
974         }
975         valueAction_ { arg val;
976                 this.setPropertyWithAction(\value, val);
977         }
979         defaultKeyDownAction { arg char, modifiers, unicode;
980                 if (char == $ , { this.valueAction = this.value + 1; ^this });
981                 if (char == $\r, { this.valueAction = this.value + 1; ^this });
982                 if (char == $\n, { this.valueAction = this.value + 1; ^this });
983                 if (char == 3.asAscii, { this.valueAction = this.value + 1; ^this });
984                 if (unicode == 16rF700, { this.valueAction = this.value - 1; ^this });
985                 if (unicode == 16rF703, { this.valueAction = this.value + 1; ^this });
986                 if (unicode == 16rF701, { this.valueAction = this.value + 1; ^this });
987                 if (unicode == 16rF702, { this.valueAction = this.value - 1; ^this });
988                 ^nil            // bubble if it's an invalid key
989         }
990         font_ { arg argFont;
991                 font = argFont;
992                 this.setProperty(\font, font)
993         }
994         items_ { arg array;
995                 items = array;
996                 this.setProperty(\items, items);
997         }
999         item {
1000                 ^items[this.value]
1001         }
1003         stringColor {
1004                 ^this.getProperty(\stringColor, Color.new)
1005         }
1006         stringColor_ { arg color;
1007                 this.setProperty(\stringColor, color)
1008         }
1010         properties {
1011                 ^super.properties ++ #[\value, \font, \items, \stringColor]
1012         }
1014         defaultGetDrag {
1015                 ^this.value
1016         }
1017         defaultCanReceiveDrag {
1018                 ^currentDrag.isNumber;
1019         }
1020         defaultReceiveDrag {
1021                 this.valueAction = currentDrag;
1022         }
1027 SCStaticTextBase : SCView {
1028         var <string, <font, <object, <>setBoth=true;
1030         font_ { arg argFont;
1031                 font = argFont;
1032                 this.setProperty(\font, font)
1033         }
1035         string_ { arg argString;
1036                 string = argString.asString;
1037                 this.setProperty(\string, string)
1038         }
1039         align_ { arg align;
1040                 this.setProperty(\align, align)
1041         }
1043         stringColor {
1044                 ^this.getProperty(\stringColor, Color.new)
1045         }
1046         stringColor_ { arg color;
1047                 this.setProperty(\stringColor, color)
1048         }
1050         object_ { arg obj;
1051                 object = obj;
1052                 if (setBoth) { this.string = object.asString(80); };
1053         }
1055         properties {
1056                 ^super.properties ++ #[\string, \font, \stringColor]
1057         }
1060 SCStaticText : SCStaticTextBase {
1061         *paletteExample { arg parent, bounds;
1062                 var v;
1063                 v = this.new(parent, bounds);
1064                 v.string = "The lazy brown fox";
1065                 ^v
1066         }
1070 SCNumberBoxOld : SCStaticTextBase {
1071         var <> keyString, <>step=1, <>scroll_step=1;
1072         var <>typingColor, <>normalColor;
1073         var <>clipLo = -inf, <>clipHi = inf, hit, inc=1.0, <>scroll=true;
1074         var <>shift_scale = 100.0, <>ctrl_scale = 10.0, <>alt_scale = 0.1;
1076         getScale { |modifiers|
1077                 ^case
1078                          { modifiers & 131072 == 131072 } { shift_scale }
1079                          { modifiers & 262144 == 262144 } { ctrl_scale }
1080                          { modifiers & 524288 == 524288 } { alt_scale }
1081                          { 1 };
1082         }
1084         *paletteExample { arg parent, bounds;
1085                 var v;
1086                 v = this.new(parent, bounds);
1087                 v.value = 123.456;
1088                 ^v
1089         }
1091         init { arg argParent, argBounds;
1092                 typingColor = Color.red;
1093                 normalColor = Color.black;
1094                 background = Color.white;
1095                 parent = argParent.asView; // actual view
1096                 this.prInit(parent.asView, argBounds.asRect, this.class.viewClass);
1097                 argParent.add(this);//maybe window or viewadapter
1098         }
1100         increment { arg mul=1; this.valueAction = this.value + (step*mul); }
1101         decrement { arg mul=1; this.valueAction = this.value - (step*mul); }
1103         defaultKeyDownAction { arg char, modifiers, unicode;
1104                 var zoom = this.getScale(modifiers);
1106                 // standard chardown
1107                 if (unicode == 16rF700, { this.increment(zoom); ^this });
1108                 if (unicode == 16rF703, { this.increment(zoom); ^this });
1109                 if (unicode == 16rF701, { this.decrement(zoom); ^this });
1110                 if (unicode == 16rF702, { this.decrement(zoom); ^this });
1112                 if ((char == 3.asAscii) || (char == $\r) || (char == $\n), { // enter key
1113                         if (keyString.notNil, { // no error on repeated enter
1114                                 this.valueAction_(keyString.asFloat);
1115                         });
1116                         ^this
1117                 });
1118                 if (char == 127.asAscii, { // delete key
1119                         keyString = nil;
1120                         this.string = object.asString;
1121                         this.stringColor = normalColor;
1122                         ^this
1123                 });
1124                 if (char.isDecDigit || "+-.eE".includes(char), {
1125                         if (keyString.isNil, {
1126                                 keyString = String.new;
1127                                 this.stringColor = typingColor;
1128                         });
1129                         keyString = keyString.add(char);
1130                         this.string = keyString;
1131                         ^this
1132                 });
1136                 ^nil            // bubble if it's an invalid key
1137         }
1139         value { ^object }
1140         value_ { arg val;
1141                 keyString = nil;
1142                 this.stringColor = normalColor;
1143                 object = val !? { val.clip(clipLo, clipHi) };
1144                 this.string = object.asString;
1145         }
1146         valueAction_ { arg val;
1147                 var prev;
1148                 prev = object;
1149                 this.value = val !? { val.clip(clipLo, clipHi) };
1150                 if (object != prev, { this.doAction });
1151         }
1153         boxColor {
1154                 this.deprecated(thisMethod, SCView.findMethod(\background));
1155                 ^this.background;
1156         }
1157         boxColor_ { arg color;
1158                 this.deprecated(thisMethod, SCView.findMethod(\background_));
1159                 this.background_(color)
1160         }
1162         properties {
1163                 ^super.properties ++ #[\boxColor]
1164         }
1165         defaultGetDrag {
1166                 ^object.asFloat
1167         }
1168         defaultCanReceiveDrag {
1169                 ^currentDrag.isNumber;
1170         }
1171         defaultReceiveDrag {
1172                 this.valueAction = currentDrag;
1173         }
1175         mouseDown { arg x, y, modifiers, buttonNumber, clickCount;
1176                 hit = Point(x, y);
1177                 if (scroll == true, { inc = this.getScale(modifiers) });
1178                 mouseDownAction.value(this, x, y, modifiers, buttonNumber, clickCount)
1179         }
1181         mouseMove { arg x, y, modifiers;
1182                 var direction;
1183                 if (scroll == true, {
1184                         direction = 1.0;
1185                                 // horizontal or vertical scrolling:
1186                         if ( (x - hit.x) < 0 or: { (y - hit.y) > 0 }) { direction = -1.0; };
1188                         this.valueAction = (this.value + (inc * this.scroll_step * direction));
1189                         hit = Point(x, y);
1190                 });
1191                 mouseMoveAction.value(this, x, y, modifiers);
1192         }
1193         mouseUp {
1194                 inc=1
1195         }
1198 SCListView : SCControlView {
1199         var <font, <items, <>enterKeyAction;
1201         *paletteExample { arg parent, bounds;
1202                 var v;
1203                 v = this.new(parent, bounds);
1204                 v.items = #["linear", "exponential", "sine", "welch", "squared", "cubed"];
1205                 ^v
1206         }
1208         init { arg argParent, argBounds;
1209                 parent = argParent.asView; // actual view
1210                         // call asView again because parent by this point might be a FlowView
1211                 this.prInit(parent.asView, argBounds.asRect, this.class.viewClass);
1212                 argParent.add(this);//maybe window or viewadapter
1213                 this.items = []; // trick to draw right in scrollviews
1214         }
1216         item {
1217                 ^items[this.value]
1218         }
1219         value {
1220                 ^this.getProperty(\value)
1221         }
1222         value_ { arg val;
1223                 this.setProperty(\value, val);
1224         }
1225         valueAction_ { arg val;
1226                 this.setPropertyWithAction(\value, val);
1227         }
1229         defaultKeyDownAction { arg char, modifiers, unicode;
1230                 var index;
1231                 if (char == $ , { this.valueAction = this.value + 1; ^this });
1232                 if (char == $\r, { this.enterKeyAction.value(this); ^this });
1233                 if (char == $\n, { this.enterKeyAction.value(this); ^this });
1234                 if (char == 3.asAscii, { this.enterKeyAction.value(this); ^this });
1235                 if (unicode == 16rF700, { this.valueAction = this.value - 1; ^this });
1236                 if (unicode == 16rF703, { this.valueAction = this.value + 1; ^this });
1237                 if (unicode == 16rF701, { this.valueAction = this.value + 1; ^this });
1238                 if (unicode == 16rF702, { this.valueAction = this.value - 1; ^this });
1239                 if (char.isAlpha, {
1240                         char = char.toUpper;
1241                         index = items.detectIndex( { |item| item.asString.at(0).toUpper >= char });
1242                         if (index.notNil, {
1243                                 this.valueAction = index
1244                         });
1245                         ^this
1246                 });
1247                 ^nil            // bubble if it's an invalid key
1248         }
1249         font_ { arg argFont;
1250                 font = argFont;
1251                 this.setProperty(\font, font)
1252         }
1253         items_ { arg array;
1254                 items = array;
1255                 this.setProperty(\items, items);
1256         }
1258         colors_ { arg incolors;
1259                 this.setProperty(\itemColors, incolors);
1260         }
1262         colors {
1263                 ^this.getProperty(\itemColors, {Color.new}!items.size);
1264         }
1266         stringColor {
1267                 ^this.getProperty(\stringColor, Color.new)
1268         }
1269         stringColor_ { arg color;
1270                 this.setProperty(\stringColor, color)
1271         }
1273         selectedStringColor {
1274                 ^this.getProperty(\selectedStringColor, Color.new)
1275         }
1276         selectedStringColor_ { arg color;
1277                 this.setProperty(\selectedStringColor, color)
1278         }
1280         hiliteColor {
1281                 ^this.getProperty(\hiliteColor, Color.new)
1282         }
1283         hiliteColor_ { arg color;
1284                 this.setProperty(\hiliteColor, color)
1285         }
1287         properties {
1288                 ^super.properties ++ #[\value, \font, \items, \stringColor, \align, \itemColors]
1289         }
1291         defaultGetDrag {
1292                 ^this.value
1293         }
1294         defaultCanReceiveDrag {
1295                 ^currentDrag.isNumber;
1296         }
1297         defaultReceiveDrag {
1298                 this.valueAction = currentDrag;
1299         }
1303 SCDragView : SCStaticTextBase {
1305         *paletteExample { arg parent, bounds;
1306                 var v;
1307                 v = this.new(parent, bounds);
1308                 v.object = \something;
1309                 ^v
1310         }
1311         defaultGetDrag {
1312                 ^object
1313         }
1316 SCDragSource : SCDragView {
1320 SCDragSink : SCDragView {
1321         defaultCanReceiveDrag { ^true;  }
1322         defaultReceiveDrag {
1323                 this.object = currentDrag;
1324                 this.doAction;
1325         }
1328 SCDragBoth : SCDragSink {
1329         defaultGetDrag { ^object }
1333 SCUserView : SCView {
1334         var <>drawFunc;
1335 //      var <>mouseBeginTrackFunc, <>mouseTrackFunc, <>mouseEndTrackFunc;
1336         var < clearOnRefresh = true;
1337         var < drawingEnabled = true;
1339         init { |argParent, argBounds|
1340                 super.init(argParent, argBounds);
1341         }
1343         draw {
1344                 drawFunc.value(this) ;
1345         }
1347         clearDrawing {
1348                         this.setProperty(\clearDrawing);
1349         }
1351         mousePosition {
1352                 this.deprecated(thisMethod);
1353                 ^this.getProperty(\mousePosition, Point.new)
1354         }
1356         clearOnRefresh_ { |bool|
1357                 clearOnRefresh = bool;
1358                 this.setProperty(\clearOnRefresh, bool);                        }
1360         animate_ { |bool|
1361                 this.setProperty(\animate, bool);
1362         }
1364         frame {
1365                 ^this.getProperty(\frame);
1366         }
1368         frameRate {
1369                 ^this.getProperty(\frameRate);
1370         }
1372         drawingEnabled_ { |bool|
1373                 drawingEnabled = bool;
1374                 this.setProperty(\drawingEnabled, bool);        }
1376         /* backwards compatibility */
1377         keyDownFunc_ { |action|
1378                 "SCUserView:keyDownFunc deprecated, use SCUserView:keyDownAction".warn;
1379                 keyDownAction = action;
1380         }
1382         keyDownFunc {
1383                 "SCUserView:keyDownFunc deprecated, use SCUserView:keyDownAction".warn;
1384                 ^keyDownAction
1385         }
1387         mouseBeginTrackFunc_ { |action|
1388                 "SCUserView:mouseBeginTrackFunc deprecated, use SCUserView:mouseDownAction".warn;
1389                 mouseDownAction = action;
1390         }
1391         mouseBeginTrackFunc {
1392                 "SCUserView:mouseBeginTrackFunc deprecated, use SCUserView:mouseDownAction".warn;
1393                 ^mouseDownAction;
1394         }
1396         mouseTrackFunc_ { |action|
1397                 "SCUserView:mouseTrackFunc deprecated, use SCUserView:mouseMoveAction".warn;
1398                 mouseMoveAction = action;
1399         }
1400         mouseTrackFunc {
1401                 "SCUserView:mouseTrackFunc deprecated, use SCUserView:mouseMoveAction".warn;
1402                 ^mouseMoveAction;
1403         }
1405         mouseEndTrackFunc_ { |action|
1406                 "SCUserView:mouseEndTrackFunc deprecated, use SCUserView:mouseUpAction".warn;
1407                 mouseUpAction = action;
1408         }
1410         mouseEndTrackFunc {
1411                 "SCUserView:mouseEndTrackFunc deprecated, use SCUserView:mouseUpAction".warn;
1412                 ^mouseUpAction;
1413         }
1419 //SCFuncUserView : SCUserView {
1420 //      var <>keyDownFunc, <>drawFunc;
1421 //      var <>mouseBeginTrackFunc, <>mouseTrackFunc, <>mouseEndTrackFunc;
1423 //      draw { drawFunc.value(this) }
1424 //      mouseBeginTrack { arg x, y, modifiers;
1425 //              mouseBeginTrackFunc.value(this, x, y, modifiers);
1426 //      }
1427 //      mouseTrack { arg x, y, modifiers;
1428 //              mouseTrackFunc.value(this, x, y, modifiers);
1429 //      }
1430 //      mouseEndTrack { arg x, y, modifiers;
1431 //              mouseEndTrackFunc.value(this, x, y, modifiers);
1432 //      }
1433 //      keyDown { arg key, modifiers, unicode;
1434 //              keyDownFunc.value(this, key, modifiers, unicode)
1435 //      }
1438 //by jt v.0.22
1439 SCMultiSliderView : SCView {
1441         var <>metaAction;
1442 //      var <>mouseUpAction;
1443         var <>size ;
1444         var <gap;
1445         var <editable = true;
1446         var <elasticMode = 0;
1448         draw {}
1449         mouseBeginTrack { arg x, y, modifiers;}
1450         mouseTrack { arg x, y, modifiers;       }
1451         mouseEndTrack { arg x, y, modifiers;
1452                 mouseUpAction.value(this);
1453         }
1454         properties {
1455                 ^super.properties ++ #[\value, \thumbSize, \fillColor, \strokeColor, \xOffset, \x, \y, \showIndex, \drawLines, \drawRects, \selectionSize, \startIndex, \referenceValues, \thumbWidth, \absoluteX, \isFilled, \step, \elasticResizeMode]
1456         }
1460         elasticMode_ { arg mode;
1461                 elasticMode =mode;
1462                 this.setProperty(\elasticResizeMode, mode);
1463         }
1465         step_ { arg stepSize;
1466                 this.setPropertyWithAction(\step, stepSize);
1467         }
1469         step {
1470                 ^this.getProperty(\step)
1471         }
1473         value { //returns array
1474                 ^this.getProperty(\value, Array.newClear(this.size))
1475         }
1476         value_ { arg val;
1477                 this.size = val.size;
1478                 this.setProperty(\value, val)
1479         }
1481         valueAction_ { arg val;
1482                 this.size = val.size;
1483                 this.setPropertyWithAction(\value, val);
1484         }
1486         reference { //returns array
1487                 ^this.getProperty(\referenceValues, Array.newClear(this.size))
1488         }
1489         reference_ { arg val;
1490                 //this.size = val.size;
1491                 this.setProperty(\referenceValues, val)
1492         }
1493         index { //returns selected index
1494                 ^this.getProperty(\x)
1495         }
1496         index_ { arg inx;
1497                 this.setProperty(\x, inx)
1498         }
1499         isFilled_ { arg abool;
1500                 this.setProperty(\isFilled, abool);
1501         }
1502         xOffset_ { arg aval;
1503                 this.setProperty(\xOffset, aval);
1504         }
1505         gap_ { arg inx;
1506                 gap = inx;
1507                 this.setProperty(\xOffset, inx)
1508         }
1510         startIndex_ { arg val; this.setProperty( \startIndex, val )}
1512         selectionSize {
1513                 ^this.getProperty(\selectionSize)
1514         }
1515         selectionSize_ { arg aval;
1516                 this.setProperty(\selectionSize, aval)
1517         }
1518         currentvalue { //returns value of selected index
1519                 ^this.getProperty(\y)
1520         }
1521         fillColor_ { arg acolor;
1522                 this.setProperty(\fillColor, acolor)
1523         }
1524         strokeColor_ { arg acolor;
1525                 this.setProperty(\strokeColor, acolor)
1526         }
1527         colors_ { arg strokec, fillc;
1528                 this.strokeColor_(strokec);
1529                 this.fillColor_(fillc);
1530         }
1531         currentvalue_ { arg iny;
1532                 this.setProperty(\y, iny)
1533         }
1534         showIndex_ { arg abool;
1535                 this.setProperty(\showIndex, abool)
1536                 }
1537         drawLines { arg abool;
1538                 this.setProperty(\drawLines, abool)
1539         }
1540         drawLines_ { arg abool;
1541                 this.drawLines(abool)
1542         }
1543         drawRects_ { arg abool;
1544                 this.setProperty(\drawRects, abool)
1545         }
1546         readOnly_ { arg val;
1547                 editable = val.not;
1548                 this.setProperty(\readOnly, val);
1549         }
1550         editable_ { arg val;
1551                 editable = val;
1552                 this.setProperty(\readOnly, editable.not);
1553         }
1554         thumbSize_ { arg val;
1555                 this.setProperty(\thumbSize, val)
1556         }
1557         indexThumbSize_ { arg val;
1558                 this.setProperty(\indexThumbSize, val)
1559         }
1560         valueThumbSize_ { arg val;
1561                 this.setProperty(\valueThumbSize, val)
1562         }
1563         indexIsHorizontal_ { arg val;
1564                 this.setProperty(\isHorizontal, val);
1565         }
1566         defaultCanReceiveDrag { ^true; }
1567         defaultReceiveDrag {
1568                 if(currentDrag.at(0).isSequenceableCollection, {
1569                         this.value_(currentDrag.at(0));
1570                         this.reference_(currentDrag.at(1));
1571                 }, {
1572                         this.value_(currentDrag);
1573                 });
1574         }
1575         defaultGetDrag {
1576                 var setsize, vals, rvals, outval;
1577                 rvals = this.reference;
1578                 vals = this.value;
1579                 if(this.selectionSize > 1, {
1580                         vals = vals.copyRange(this.index, this.selectionSize + this.index);});
1581                 if(rvals.isNil, {
1582                         ^vals
1583                 }, {
1584                 if(this.selectionSize > 1, {
1585                         rvals = rvals.copyRange(this.index, this.selectionSize + this.index);});
1586                         outval = outval.add(vals);
1587                         outval = outval.add(rvals);
1588                 });
1589                 ^outval
1590         }
1592         defaultKeyDownAction { arg key, modifiers, unicode;
1593                 //modifiers.postln; 16rF702
1594                 if (unicode == 16rF703, { this.index = this.index + 1; ^this });
1595                 if (unicode == 16rF702, { this.index = this.index - 1; ^this });
1596                 if (unicode == 16rF700, { this.gap = this.gap + 1; ^this });
1597                 if (unicode == 16rF701, { this.gap = this.gap - 1; ^this });
1598                 ^nil            // bubble if it's an invalid key
1599         }
1601         *paletteExample { arg parent, bounds;
1602                 var example;
1603                 example = this.new(parent, bounds).valueThumbSize_(2);
1604                 ^example
1605         }
1607         doMetaAction {
1608                 metaAction.value(this)
1609         } //on ctrl click
1612 SCEnvelopeView : SCView {
1613         var connection, <>allConnections, doOnce;
1614 //      var <>mouseUpAction;
1615         var <>items;
1616         var < fixedSelection = false;
1617         var <>metaAction;
1618         var <>size ;
1619         var <editable = true;
1620         var <curves = \linear;
1621         var <gridOn, <gridColor, <grid;
1623         init { arg argParent, argBounds;
1624                 super.init(argParent, argBounds);
1625                 gridOn = false;
1626                 gridColor = Color(0, 0, 0.8, 0.3);
1627                 grid = Point(0.1, 0.1);
1628         }
1630         draw {}
1631         mouseBeginTrack { arg x, y, modifiers;}
1632         mouseTrack { arg x, y, modifiers;       }
1633         mouseEndTrack { arg x, y, modifiers;
1634                 mouseUpAction.value(this);
1635         }
1637         grid_ { arg point;
1638                 this.setProperty(\setGrid, [point.x, point.y]);
1639                 grid = point;
1640         }
1642         gridOn_ { arg bool;
1643                 this.setProperty(\showGrid, bool);
1644                 gridOn = bool;
1645         }
1647         gridColor_ { arg color;
1648                 this.setProperty(\setGridColor, color);
1649                 gridColor = color;
1650         }
1652         properties {
1653                 ^super.properties ++ #[\value, \thumbSize, \fillColor, \strokeColor, \xOffset, \x, \y, \showIndex, \drawLines, \drawRects, \selectionSize, \startIndex, \thumbWidth, \absoluteX, \isFilled, \step, \setCurve, \setCurves, \showGrid, setGridColor, \setGrid]
1654         }
1656         step_ { arg stepSize;
1657                 this.setPropertyWithAction(\step, stepSize);
1658         }
1660         step {
1661                 ^this.getProperty(\step)
1662         }
1664         valueAction_ { arg val;
1665                 this.value_(val);
1666                 this.doAction;
1667         }
1669         currentvalue { //returns value of selected index
1670                 ^this.getProperty(\y)
1671         }
1672         currentvalue_ { arg iny;
1673                 this.setProperty(\y, iny)
1674         }
1676         strokeColor_ { arg acolor;
1677                 this.setProperty(\strokeColor, acolor)
1678         }
1679         colors_ { arg strokec, fillc;
1680                 this.strokeColor_(strokec);
1681                 this.fillColor_(fillc);
1682         }
1684         drawLines { arg abool;
1685                 this.setProperty(\drawLines, abool)
1686         }
1687         drawLines_ { arg abool;
1688                 this.drawLines(abool)
1689         }
1690         drawRects_ { arg abool;
1691                 this.setProperty(\drawRects, abool)
1692         }
1694         defaultCanReceiveDrag { ^true; }
1696     defaultKeyDownAction { arg key, modifiers, unicode;
1697                 (modifiers==10617090).if { // shift key
1698                         (this.index > 1.neg).if {
1699                         if (unicode == 16rF703, { this.x = this.value[0][this.index] + this.step; ^this });
1700                         if (unicode == 16rF702, { this.x = this.value[0][this.index] - this.step; ^this });
1701                         };
1702                 } {
1703                         if (unicode == 16rF703, { this.selectIndex((this.index+1)%this.size) ^this });
1704                         if (unicode == 16rF702, { this.selectIndex((this.index-1)%this.size) ^this });
1705                 };
1706                 (this.index > 1.neg).if {
1707                    if (unicode == 16rF700, { this.y = this.value[1][this.index] + this.step; ^this });
1708                    if (unicode == 16rF701, { this.y = this.value[1][this.index] - this.step; ^this });
1709                 };
1710         ^nil        // bubble if it's an invalid key
1711     }
1713         doMetaAction {
1714                 metaAction.value(this)
1715         } //on ctrl click
1717         value_ { arg val;
1718                 if(val.at(1).size != val.at(0).size, {
1719                         // otherwise its a fatal crash
1720                         Error("SCEnvelopeView got mismatched times/levels arrays").throw;
1721                 });
1722                 this.size = val.at(0).size;
1723                 this.setProperty(\value, val)
1724         }
1725         setString { arg index, astring;
1726                 //items = items.add(astring);
1727                 this.setProperty(\string, [index, astring])
1728         }
1730         strings_ { arg astrings;
1731                 astrings.do( { arg str, i;
1732                         this.setString(i, str);
1733                 });
1734         }
1735         value {
1736                 var ax, ay, axy;
1737                 ax = Array.newClear(this.size);
1738                 ay = Array.newClear(this.size);
1739                 axy = Array.with(ax, ay);
1740                 ^this.getProperty(\value, axy)
1741         }
1743         setThumbHeight { arg index, height;
1744                 this.setProperty(\thumbHeight, [index, height]);
1745         }
1746         thumbHeight_ { arg height;
1747                 this.setThumbHeight(-1, height);
1748         }
1749         setThumbWidth { arg index, width;
1750                 this.setProperty(\thumbWidth, [index, width]);
1751         }
1752         thumbWidth_ { arg width;
1753                 this.setThumbWidth(-1, width);
1754         }
1755         setThumbSize { arg index, size;
1756                 this.setProperty(\thumbSize, [index, size]);
1757         }
1758         thumbSize_ { arg size;
1759                 this.setThumbSize(-1, size);
1760         }
1761         setFillColor { arg index, color;
1762                 this.setProperty(\fillColor, [index, color]);
1763         }
1764         fillColor_ { arg color;
1765                 this.setFillColor(-1, color);
1766         }
1768         curves_ { arg inCurves;
1769                 var curveNumbers;
1770                 var shapeNum, curveNum=0;
1771                 curves = inCurves;
1772                 if(curves.isKindOf(Array)) {
1773                         curveNumbers = curves.collect { |it|
1774                                 shapeNum = this.shapeNumber(it);
1775                                 if(shapeNum == 5) {
1776                                         curveNum = it;
1777                                 } {
1778                                         curveNum = 0;
1779                                 };
1780                                 [shapeNum, curveNum]
1781                         };
1782 //                      this.debug(curveNumbers);
1783                         this.prSetCurves(curveNumbers);
1784                 } {
1785                         shapeNum = this.shapeNumber(curves);
1786                                 if(shapeNum == 5) {
1787                                         curveNum = curves;
1788                                 } {
1789                                         curveNum = 0;
1790                                 };
1791                         this.prSetCurve([-1, shapeNum, curveNum]);
1792                 }
1793         }
1795         setEnv { arg env, minValue, maxValue, minTime, maxTime;
1796                 var times, levels;
1797                 var spec;
1799                 times = Array.newClear(env.times.size + 1);
1800                 times[0] = 0;
1801                 for(1, env.times.size, { arg i;
1802                         times[i] = times[i-1] + env.times[i-1];
1803                 });
1804                 maxTime = maxTime ? times.last;
1805                 minTime = minTime ? 0;
1806                 levels = env.levels;
1807                 minValue = minValue ? levels.minItem;
1808                 maxValue = maxValue ? levels.maxItem;
1810                 levels = levels.linlin(minValue, maxValue, 0, 1);
1811                 times = times.linlin(minTime, maxTime, 0, 1);
1813                 this.value_([times.asFloat, levels.asFloat]);
1814                 this.curves_(env.curves);
1816         }
1818         editEnv { arg env, minValue, maxValue, duration;
1819                 var vals, levels, times, lastTime = 0;
1820                 vals = this.value;
1821                 levels = vals[0].linlin(0, 1, minValue, maxValue);
1822                 times = vals[1].collect { |it|
1823                         var out;
1824                         out = it - lastTime;
1825                         lastTime = it;
1826                         out
1827                 };
1828                 env.times_(times);
1829                 env.levels_(levels);
1830                 env.curves_(this.curves);
1831         }
1833         asEnv { arg env, minValue, maxValue, duration;
1834                 var vals, levels, times, lastTime = 0;
1835                 vals = this.value;
1836                 levels = vals[0].linlin(0, 1, minValue, maxValue);
1837                 times = vals[1].collect { |it|
1838                         var out;
1839                         out = it - lastTime;
1840                         lastTime = it;
1841                         out
1842                 };
1843                 env.times_(times);
1844                 env.levels_(levels);
1845                 env.curves_(this.curves);
1846                 ^Env(levels, times, this.curves);
1847         }
1849         *paletteExample { arg parent, bounds;
1850                 ^this.new(parent, bounds).setEnv(Env([0.1, 0.3, 0.4, 0.01], [0.3, 1, 3]));
1851         }
1853         prSetCurves { |arr|
1854                 this.setProperty(\setCurves, arr);
1855         }
1857         prSetCurve { |arr|
1858 //              this.debug([\setCurves, arr]);
1859                 this.setProperty(\setCurve, arr);
1860         }
1862         shapeNumber { arg shapeName;
1863                 var shape;
1864                 shape = Env.shapeNames.at(shapeName);
1865                 if (shape.notNil) { ^shape } {^5};
1866         }
1868         connect { arg from, aconnections;
1869                 this.setProperty(\connect, [from, aconnections.asFloat]);
1870         }
1872         select { arg index; //this means no refresh;
1873                 this.setProperty(\setIndex, index);
1874         }
1875         selectIndex { arg index; //this means that the view will be refreshed
1876                 this.setProperty(\selectedIndex, index);
1877         }
1878         x {                                             //returns selected x
1879                 ^this.getProperty(\x);
1880         }
1881         y {
1882                 ^this.getProperty(\y);
1883         }
1884         x_ { arg ax;
1885                 this.setProperty(\x, ax);
1886         }
1887         y_ { arg ay;
1888                 this.setProperty(\y, ay);
1889         }
1890         index {
1891                 ^this.getProperty(\selectedIndex)
1892         }
1893         lastIndex {
1894                 ^this.getProperty(\lastIndex)
1895         }
1897         setEditable { arg index, boolean;
1898                 this.setProperty(\editable, [index, boolean]);
1899         }
1901         editable_ { arg boolean;
1902                 this.setEditable(-1, boolean);
1903         }
1905         selectionColor_ { arg acolor;
1906                 this.setProperty(\selectionColor, acolor)
1907         }
1908         defaultGetDrag {
1909                 ^this.value
1910         }
1911         defaultReceiveDrag {
1912                 if(currentDrag.isString, {
1913                         this.addValue;
1914                         items = items.insert(this.lastIndex + 1, currentDrag);
1915                         this.strings_(items);
1916                 }, {
1917                         this.value_(currentDrag);
1918                 });
1919         }
1921         addValue { arg xval, yval;
1922                 var arr, arrx, arry, aindx;
1923                 arr = this.value;
1924                 arrx = arr@0;
1925                 arry = arr@1;
1926                 arrx.do { |val, i|
1927                         if(val>xval and: aindx.isNil) {
1928                                 aindx = i;
1929                         }
1930                 };
1931 //              this.debug(aindx);
1932                 arrx = arrx.insert(aindx , xval);
1933                 arry = arry.insert(aindx , yval);
1934                 this.value_([arrx, arry]);
1935         }
1937         fixedSelection_ { arg bool;
1938                 fixedSelection =  bool;
1939                 this.setProperty(\setFixedSelection, bool);
1940         }
1943 //including keydown by Heiko:
1944 // bug fixed in SCRangeSlider-receiveDrag
1945 // bug fixed in SCView-getPropertyList
1946 // allowing children in SCContainerView and parent in SCView to be accessed
1947 // globalKeyDownAction as classvar for all Views
1948 // KeyDownAction for all Views
1949 // bug fixed in SCNumberBox-defaultKeyDownAction
1950 // passing keydown up the tree
1951 // consuming keydown in function
1952 // added keyup
1953 // and SCMultiSlider by jan t.
1954 // added customizable drag handlers, cx