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;
11 *new { arg parent, bounds;
12 ^super.new.init(parent, bounds);
17 *paletteExample { arg parent, bounds;
18 ^this.new(parent, bounds);
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
32 ^this.getProperty(\bounds, Rect.new)
35 this.setProperty(\bounds, rect)
39 ^this.getProperty(\visible)
42 this.setProperty(\visible, bool)
46 ^this.getProperty(\enabled)
49 this.setProperty(\enabled, bool)
53 ^this.getProperty(\canFocus)
56 this.setProperty(\canFocus, bool)
59 focus { arg flag=true;
70 this.setProperty(\focusColor, color)
73 ^this.getProperty(\focusColor, Color.new)
77 ^this.getProperty(\id)
80 this.setProperty(\id, id)
83 dragLabel_ { arg string;
84 this.setProperty(\dragLabel, string)
97 isClosed { ^dataptr.isNil }
98 notClosed { ^dataptr.notNil }
101 parent.prRemoveChild(this);
105 "SCView-remove : this view already removed.".debug(this);
109 resize behaviour in an SCCompositeView:
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
128 ^this.getProperty(\resize)
131 resize_ { arg resize;
132 this.setProperty(\resize, resize)
135 background_ { arg color;
137 this.setProperty(\background, color)
140 addAction { arg func, selector=\action;
141 this.perform(selector.asSetter, this.perform(selector).addFunc(func));
144 removeAction { arg func, selector=\action;
145 this.perform(selector.asSetter, this.perform(selector).removeFunc(func));
148 mouseDown { arg x, y, modifiers, buttonNumber, clickCount;
149 mouseDownAction.value(this, x, y, modifiers, buttonNumber, clickCount);
152 mouseUp { arg x, y, modifiers;
153 mouseUpAction.value(this, x, y, modifiers)
156 mouseMove { arg x, y, modifiers;
157 mouseMoveAction.value(this, x, y, modifiers)
160 mouseOver { arg x, y;
161 mouseOverAction.value(this, x, y);
164 keyDown { arg char, modifiers, unicode, keycode;
165 globalKeyDownAction.value(this, char, modifiers, unicode, keycode);
166 this.handleKeyDownBubbling(this, char, modifiers, unicode, keycode);
169 keyModifiersChanged { arg modifiers;
170 this.handleKeyModifiersChangedBubbling(this, modifiers)
173 handleKeyModifiersChangedBubbling { arg view, modifiers;
175 // nil from keyDownAction --> pass it on
176 if (keyModifiersChangedAction.isNil) {
177 // this.defaultKeyDownAction(char, modifiers, unicode, keycode);
180 result = keyModifiersChangedAction.value(view, modifiers);
183 // call keydown action of parent view
184 parent.handleKeyModifiersChangedBubbling(view, modifiers);
188 defaultKeyDownAction { ^nil }
190 handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
192 // nil from keyDownAction --> pass it on
193 if (keyDownAction.isNil) {
194 result = this.defaultKeyDownAction(char, modifiers, unicode, keycode);
196 result = keyDownAction.value(view, char, modifiers, unicode, keycode);
199 // call keydown action of parent view
200 parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode);
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);
212 defaultKeyUpAction { ^nil }
214 handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
216 // nil from keyDownAction --> pass it on
217 if (keyUpAction.isNil) {
218 result = this.defaultKeyUpAction(char, modifiers, unicode, keycode);
220 result = keyUpAction.value(view, char, modifiers, unicode, keycode);
223 // call keydown action of parent view
224 parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode);
229 currentDrag = if (beginDragAction.notNil)
231 beginDragAction.value(this)
235 currentDragString = currentDrag.asCompileString;
238 defaultGetDrag { ^nil }
241 ^if(canReceiveDragHandler.notNil) {
242 canReceiveDragHandler.value(this)
244 this.defaultCanReceiveDrag
247 defaultCanReceiveDrag { ^false }
249 if(receiveDragHandler.notNil) {
250 receiveDragHandler.value(this, x, y)
252 this.defaultReceiveDrag(x, y)
254 currentDrag = currentDragString = nil;
257 // get the view parent tree up to the SCTopView
262 while( {(view = view.asView.parent).notNil}, { parents.add(view)});
271 ^#[\bounds, \visible, \enabled, \canFocus, \resize, \background,
272 \minWidth, \maxWidth, \minHeight, \maxHeight, \focusColor]
276 ^this.properties.collect( { arg name;
277 [name, this.perform(name)]
281 setPropertyList { arg list;
285 this.perform(name.asSetter, value);
290 prInit { arg argParent, argBounds, argViewClass;
292 ^this.primitiveFailed
295 prClose { dataptr = nil; onClose.value(this); }
298 ^this.primitiveFailed
300 setProperty { arg key, value;
302 ^this.primitiveFailed
304 getProperty { arg key, value;
306 ^this.primitiveFailed
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.
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;
325 ^this.getProperty(\absoluteBounds, Rect.new)
329 SCContainerView : SCView { // abstract class
331 var <children, <decorator;
334 children = children.add(child);
335 if (decorator.notNil, { decorator.place(child); });
338 init { arg argParent, argBounds;
339 super.init(argParent, argBounds);
343 children.copy.do { |child| child.remove };
346 addFlowLayout { arg margin, gap;
347 this.decorator_( FlowLayout( this.bounds.moveTo(0, 0), margin, gap ) );
351 decorator_ { arg decor;
352 decor.bounds = decor.bounds.moveTo(0, 0);
357 prRemoveChild { arg child;
358 children.remove(child);
359 // ... decorator should re-place all
362 //bounds_ ... replace all
366 children.do( { arg item; item.prClose });
371 SCCompositeView : SCContainerView {
374 SCTopView : SCCompositeView {
376 // created by SCWindow
377 handleKeyModifiersChangedBubbling { arg view, modifiers;
378 keyModifiersChangedAction.value(view, modifiers);
380 handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
381 var currentAppModal, window;
382 keyDownAction.value(view, char, modifiers, unicode, keycode);
384 handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
385 keyUpAction.value(view, char, modifiers, unicode, keycode);
388 //only in construction mode, handled internally
389 canReceiveDrag { ^currentDrag.isKindOf(Class)}
390 // remove { this.removeAll }
393 SCWindow.allWindows.do { |win|
394 if(win.view == this) {
400 /* construction mode */
402 constructionGrid_ { arg point;
403 this.setProperty( \constructionGrid, point );
407 ^this.getProperty( \constructionGrid, Point.new );
410 enableConstructionGrid_ { arg flag;
411 this.setProperty( \enableConstructionGrid, flag );
414 enableConstructionGrid {
415 ^this.getProperty( \enableConstructionGrid );
418 //private called from lang
419 setConstructionMode { |flag|
420 this.setProperty( \setConstructionMode, flag )
423 defaultReceiveDrag { |x, y|
425 win = this.findWindow;
426 view = currentDrag.paletteExample(win, Rect(x, y, 140, 24)).enabled_(false);
427 view.keyDownAction_( { |view, char, modifiers, unicode, keycode|
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);
444 hasHorizontalScroller_ { |bool|
445 hasHorizontalScroller = bool;
446 this.setProperty(\setHasHorizontalScroller, bool);
449 hasVerticalScroller_ { |bool|
450 hasVerticalScroller = bool;
451 this.setProperty(\setHasVerticalScroller, bool);
454 visibleOrigin_ { arg point;
455 this.setProperty( \clipViewOrigin, point );
458 visibleOrigin { ^this.getProperty( \clipViewOrigin, Point.new );}
460 autoScrolls_ { |bool|
462 this.setProperty(\setAutoScrolls, bool);
466 ^this.getProperty(\innerBounds, Rect.new)
470 var bounds = this.absoluteBounds;
471 this.getParents.do( { |parent|
472 bounds = bounds.moveBy(parent.bounds.left.neg, parent.bounds.top.neg)
477 // handleKeyModifiersChangedBubbling { arg view, modifiers;
479 // // nil from keyDownAction --> pass it on
480 // if (keyModifiersChangedAction.isNil) {
483 // result = keyModifiersChangedAction.value(view, modifiers);
485 // if(result.isNil) {
486 // // call keydown action of parent view
487 // parent.handleKeyModifiersChangedBubbling(view, modifiers);
491 // handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
493 // // nil from keyDownAction --> pass it on
494 // if (keyDownAction.isNil) {
495 // result = this.defaultKeyDownAction(char, modifiers, unicode, keycode);
497 // result = keyDownAction.value(view, char, modifiers, unicode, keycode);
499 // if(result.isNil) {
500 // // call keydown action of parent view
501 // parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode);
505 // handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
507 // // nil from keyDownAction --> pass it on
508 // if (keyUpAction.isNil) {
509 // result = this.defaultKeyUpAction(char, modifiers, unicode, keycode);
511 // result = keyUpAction.value(view, char, modifiers, unicode, keycode);
513 // if(result.isNil) {
514 // // call keydown action of parent view
515 // parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode);
521 SCScrollView : SCScrollTopView {
522 var <hasBorder = false;
524 hasBorder_ { arg bool = true;
525 this.setProperty(\border, bool);
528 init { |argParent, argBounds|
529 super.init(argParent, argBounds);
532 handleKeyModifiersChangedBubbling { arg view, modifiers;
534 // nil from keyDownAction --> pass it on
535 if (keyModifiersChangedAction.isNil) {
538 result = keyModifiersChangedAction.value(view, modifiers);
541 // call keydown action of parent view
542 parent.handleKeyModifiersChangedBubbling(view, modifiers);
546 handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
548 // nil from keyDownAction --> pass it on
549 if (keyDownAction.isNil) {
550 result = this.defaultKeyDownAction(char, modifiers, unicode, keycode);
552 result = keyDownAction.value(view, char, modifiers, unicode, keycode);
555 // call keydown action of parent view
556 parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode);
560 handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
562 // nil from keyDownAction --> pass it on
563 if (keyUpAction.isNil) {
564 result = this.defaultKeyUpAction(char, modifiers, unicode, keycode);
566 result = keyUpAction.value(view, char, modifiers, unicode, keycode);
569 // call keydown action of parent view
570 parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode);
576 SCLayoutView : SCContainerView {
577 properties { ^super.properties ++ #[\spacing] }
580 ^this.getProperty(\spacing, 0)
582 spacing_ { arg distance;
583 this.setProperty(\spacing, distance)
585 setProperty { |key, value|
586 super.setProperty(key, value);
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|
603 { modifiers & 131072 == 131072 } { shift_scale }
604 { modifiers & 262144 == 262144 } { ctrl_scale }
605 { modifiers & 524288 == 524288 } { alt_scale }
610 ^this.getProperty(\knobColor, Color.new)
612 knobColor_ { arg color;
613 this.setProperty(\knobColor, color)
616 step_ { arg stepSize;
617 // this.setPropertyWithAction(\step, stepSize); // action really needed?
618 this.setProperty(\step, stepSize);
622 ^this.getProperty(\step)
626 ^super.properties ++ #[\knobColor, \step]
631 SCSlider : SCSliderBase {
634 ^this.getProperty(\value)
637 this.setProperty(\value, val);
639 valueAction_ { arg val;
640 this.setPropertyWithAction(\value, val);
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) }
647 var bounds = this.bounds;
648 ^(bounds.width.max(bounds.height) - this.thumbSize).reciprocal
651 defaultKeyDownAction { arg char, modifiers, unicode, keycode;
652 var zoom = this.getScale(modifiers);
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
674 defaultCanReceiveDrag {
675 ^currentDrag.isNumber
678 this.valueAction = currentDrag;
682 ^this.getProperty(\thumbSize, 12);
684 thumbSize_ { arg size;
685 this.setProperty(\thumbSize, size);
689 ^super.properties ++ #[\thumbSize];
693 SCRangeSlider : SCSliderBase {
695 *paletteExample { arg parent, bounds;
697 v = this.new(parent, bounds);
704 ^this.getProperty(\lo)
707 this.setProperty(\lo, val);
710 this.setPropertyWithAction(\lo, val);
713 ^this.getProperty(\hi)
716 this.setProperty(\hi, val);
719 this.setPropertyWithAction(\hi, val);
722 ^this.getProperty(\range)
725 this.setProperty(\range, val);
727 activeRange_ { arg val;
728 this.setPropertyWithAction(\range, val);
731 setSpan { arg lo, hi;
736 setSpanActive { arg lo, hi;
737 this.setSpan( lo, hi );
741 setDeviation { arg deviation, average;
742 var lo = ( 1 - deviation ) * average;
743 this.setSpan(lo, lo + deviation);
747 ^super.properties ++ #[\lo, \hi]
751 var bounds = this.bounds;
752 ^(bounds.width.max(bounds.height)).reciprocal
756 var inc = (max(this.step, this.pixelStep) * zoom);
757 var newHi = (this.hi + inc);
762 this.lo_(this.lo + inc).activeHi_(newHi);
766 var inc = (max(this.step, this.pixelStep) * zoom);
767 var newLo = (this.lo - inc);
772 this.lo_(newLo).activeHi_(this.hi - inc);
775 defaultKeyDownAction { arg char, modifiers, unicode;
777 var zoom = this.getScale(modifiers);
782 this.activeLo_(min(a, b));
783 this.activeHi_(max(a, b));
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
796 defaultGetDrag { ^Point(this.lo, this.hi) }
797 defaultCanReceiveDrag {
798 ^currentDrag.isKindOf(Point);
801 // changed to x, y instead of lo, hi
802 this.lo = currentDrag.x;
803 this.hi = currentDrag.y;
808 SC2DSlider : SCSliderBase {
810 ^this.getProperty(\x)
813 this.setProperty(\x, val);
816 this.setPropertyWithAction(\x, val);
819 ^this.getProperty(\y)
822 this.setProperty(\y, val);
825 this.setPropertyWithAction(\y, val);
833 setXYActive { arg x, y;
839 ^super.properties ++ #[\x, \y]
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);
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
864 ^Point(this.x, this.y)
866 defaultCanReceiveDrag {
867 ^currentDrag.isKindOf(Point);
870 this.setXYActive(currentDrag.x, currentDrag.y);
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);
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);
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);
895 SCButton : SCControlView {
898 *paletteExample { arg parent, bounds;
900 v = this.new(parent, bounds);
902 ["Push", Color.black, Color.red],
903 ["Pop", Color.white, Color.blue]];
908 ^this.getProperty(\value)
911 this.setProperty(\value, val);
913 valueAction_ { arg val;
914 this.setPropertyWithAction(\value, val);
917 doAction { arg modifiers;
918 action.value(this, modifiers);
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
931 this.setProperty(\font, font)
936 this.setProperty(\states, states);
940 ^super.properties ++ #[\value, \font, \states]
946 defaultCanReceiveDrag {
947 ^currentDrag.isNumber or: { currentDrag.isKindOf(Function) };
950 if (currentDrag.isNumber) {
951 this.valueAction = currentDrag;
953 this.action = currentDrag;
959 SCPopUpMenu : SCControlView {
962 *paletteExample { arg parent, bounds;
964 v = this.new(parent, bounds);
965 v.items = #["linear", "exponential", "sine", "welch", "squared", "cubed"];
970 ^this.getProperty(\value)
973 this.setProperty(\value, val);
975 valueAction_ { arg val;
976 this.setPropertyWithAction(\value, val);
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
992 this.setProperty(\font, font)
996 this.setProperty(\items, items);
1004 ^this.getProperty(\stringColor, Color.new)
1006 stringColor_ { arg color;
1007 this.setProperty(\stringColor, color)
1011 ^super.properties ++ #[\value, \font, \items, \stringColor]
1017 defaultCanReceiveDrag {
1018 ^currentDrag.isNumber;
1020 defaultReceiveDrag {
1021 this.valueAction = currentDrag;
1027 SCStaticTextBase : SCView {
1028 var <string, <font, <object, <>setBoth=true;
1030 font_ { arg argFont;
1032 this.setProperty(\font, font)
1035 string_ { arg argString;
1036 string = argString.asString;
1037 this.setProperty(\string, string)
1040 this.setProperty(\align, align)
1044 ^this.getProperty(\stringColor, Color.new)
1046 stringColor_ { arg color;
1047 this.setProperty(\stringColor, color)
1052 if (setBoth) { this.string = object.asString(80); };
1056 ^super.properties ++ #[\string, \font, \stringColor]
1060 SCStaticText : SCStaticTextBase {
1061 *paletteExample { arg parent, bounds;
1063 v = this.new(parent, bounds);
1064 v.string = "The lazy brown fox";
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|
1078 { modifiers & 131072 == 131072 } { shift_scale }
1079 { modifiers & 262144 == 262144 } { ctrl_scale }
1080 { modifiers & 524288 == 524288 } { alt_scale }
1084 *paletteExample { arg parent, bounds;
1086 v = this.new(parent, bounds);
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
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);
1118 if (char == 127.asAscii, { // delete key
1120 this.string = object.asString;
1121 this.stringColor = normalColor;
1124 if (char.isDecDigit || "+-.eE".includes(char), {
1125 if (keyString.isNil, {
1126 keyString = String.new;
1127 this.stringColor = typingColor;
1129 keyString = keyString.add(char);
1130 this.string = keyString;
1136 ^nil // bubble if it's an invalid key
1142 this.stringColor = normalColor;
1143 object = val !? { val.clip(clipLo, clipHi) };
1144 this.string = object.asString;
1146 valueAction_ { arg val;
1149 this.value = val !? { val.clip(clipLo, clipHi) };
1150 if (object != prev, { this.doAction });
1154 this.deprecated(thisMethod, SCView.findMethod(\background));
1157 boxColor_ { arg color;
1158 this.deprecated(thisMethod, SCView.findMethod(\background_));
1159 this.background_(color)
1163 ^super.properties ++ #[\boxColor]
1168 defaultCanReceiveDrag {
1169 ^currentDrag.isNumber;
1171 defaultReceiveDrag {
1172 this.valueAction = currentDrag;
1175 mouseDown { arg x, y, modifiers, buttonNumber, clickCount;
1177 if (scroll == true, { inc = this.getScale(modifiers) });
1178 mouseDownAction.value(this, x, y, modifiers, buttonNumber, clickCount)
1181 mouseMove { arg x, y, modifiers;
1183 if (scroll == true, {
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));
1191 mouseMoveAction.value(this, x, y, modifiers);
1198 SCListView : SCControlView {
1199 var <font, <items, <>enterKeyAction;
1201 *paletteExample { arg parent, bounds;
1203 v = this.new(parent, bounds);
1204 v.items = #["linear", "exponential", "sine", "welch", "squared", "cubed"];
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
1220 ^this.getProperty(\value)
1223 this.setProperty(\value, val);
1225 valueAction_ { arg val;
1226 this.setPropertyWithAction(\value, val);
1229 defaultKeyDownAction { arg char, modifiers, unicode;
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 });
1240 char = char.toUpper;
1241 index = items.detectIndex( { |item| item.asString.at(0).toUpper >= char });
1243 this.valueAction = index
1247 ^nil // bubble if it's an invalid key
1249 font_ { arg argFont;
1251 this.setProperty(\font, font)
1255 this.setProperty(\items, items);
1258 colors_ { arg incolors;
1259 this.setProperty(\itemColors, incolors);
1263 ^this.getProperty(\itemColors, {Color.new}!items.size);
1267 ^this.getProperty(\stringColor, Color.new)
1269 stringColor_ { arg color;
1270 this.setProperty(\stringColor, color)
1273 selectedStringColor {
1274 ^this.getProperty(\selectedStringColor, Color.new)
1276 selectedStringColor_ { arg color;
1277 this.setProperty(\selectedStringColor, color)
1281 ^this.getProperty(\hiliteColor, Color.new)
1283 hiliteColor_ { arg color;
1284 this.setProperty(\hiliteColor, color)
1288 ^super.properties ++ #[\value, \font, \items, \stringColor, \align, \itemColors]
1294 defaultCanReceiveDrag {
1295 ^currentDrag.isNumber;
1297 defaultReceiveDrag {
1298 this.valueAction = currentDrag;
1303 SCDragView : SCStaticTextBase {
1305 *paletteExample { arg parent, bounds;
1307 v = this.new(parent, bounds);
1308 v.object = \something;
1316 SCDragSource : SCDragView {
1320 SCDragSink : SCDragView {
1321 defaultCanReceiveDrag { ^true; }
1322 defaultReceiveDrag {
1323 this.object = currentDrag;
1328 SCDragBoth : SCDragSink {
1329 defaultGetDrag { ^object }
1333 SCUserView : SCView {
1335 // var <>mouseBeginTrackFunc, <>mouseTrackFunc, <>mouseEndTrackFunc;
1336 var < clearOnRefresh = true;
1337 var < drawingEnabled = true;
1339 init { |argParent, argBounds|
1340 super.init(argParent, argBounds);
1344 drawFunc.value(this) ;
1348 this.setProperty(\clearDrawing);
1352 this.deprecated(thisMethod);
1353 ^this.getProperty(\mousePosition, Point.new)
1356 clearOnRefresh_ { |bool|
1357 clearOnRefresh = bool;
1358 this.setProperty(\clearOnRefresh, bool); }
1361 this.setProperty(\animate, bool);
1365 ^this.getProperty(\frame);
1369 ^this.getProperty(\frameRate);
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;
1383 "SCUserView:keyDownFunc deprecated, use SCUserView:keyDownAction".warn;
1387 mouseBeginTrackFunc_ { |action|
1388 "SCUserView:mouseBeginTrackFunc deprecated, use SCUserView:mouseDownAction".warn;
1389 mouseDownAction = action;
1391 mouseBeginTrackFunc {
1392 "SCUserView:mouseBeginTrackFunc deprecated, use SCUserView:mouseDownAction".warn;
1396 mouseTrackFunc_ { |action|
1397 "SCUserView:mouseTrackFunc deprecated, use SCUserView:mouseMoveAction".warn;
1398 mouseMoveAction = action;
1401 "SCUserView:mouseTrackFunc deprecated, use SCUserView:mouseMoveAction".warn;
1405 mouseEndTrackFunc_ { |action|
1406 "SCUserView:mouseEndTrackFunc deprecated, use SCUserView:mouseUpAction".warn;
1407 mouseUpAction = action;
1411 "SCUserView:mouseEndTrackFunc deprecated, use SCUserView:mouseUpAction".warn;
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);
1427 // mouseTrack { arg x, y, modifiers;
1428 // mouseTrackFunc.value(this, x, y, modifiers);
1430 // mouseEndTrack { arg x, y, modifiers;
1431 // mouseEndTrackFunc.value(this, x, y, modifiers);
1433 // keyDown { arg key, modifiers, unicode;
1434 // keyDownFunc.value(this, key, modifiers, unicode)
1439 SCMultiSliderView : SCView {
1442 // var <>mouseUpAction;
1445 var <editable = true;
1446 var <elasticMode = 0;
1449 mouseBeginTrack { arg x, y, modifiers;}
1450 mouseTrack { arg x, y, modifiers; }
1451 mouseEndTrack { arg x, y, modifiers;
1452 mouseUpAction.value(this);
1455 ^super.properties ++ #[\value, \thumbSize, \fillColor, \strokeColor, \xOffset, \x, \y, \showIndex, \drawLines, \drawRects, \selectionSize, \startIndex, \referenceValues, \thumbWidth, \absoluteX, \isFilled, \step, \elasticResizeMode]
1460 elasticMode_ { arg mode;
1462 this.setProperty(\elasticResizeMode, mode);
1465 step_ { arg stepSize;
1466 this.setPropertyWithAction(\step, stepSize);
1470 ^this.getProperty(\step)
1473 value { //returns array
1474 ^this.getProperty(\value, Array.newClear(this.size))
1477 this.size = val.size;
1478 this.setProperty(\value, val)
1481 valueAction_ { arg val;
1482 this.size = val.size;
1483 this.setPropertyWithAction(\value, val);
1486 reference { //returns array
1487 ^this.getProperty(\referenceValues, Array.newClear(this.size))
1489 reference_ { arg val;
1490 //this.size = val.size;
1491 this.setProperty(\referenceValues, val)
1493 index { //returns selected index
1494 ^this.getProperty(\x)
1497 this.setProperty(\x, inx)
1499 isFilled_ { arg abool;
1500 this.setProperty(\isFilled, abool);
1502 xOffset_ { arg aval;
1503 this.setProperty(\xOffset, aval);
1507 this.setProperty(\xOffset, inx)
1510 startIndex_ { arg val; this.setProperty( \startIndex, val )}
1513 ^this.getProperty(\selectionSize)
1515 selectionSize_ { arg aval;
1516 this.setProperty(\selectionSize, aval)
1518 currentvalue { //returns value of selected index
1519 ^this.getProperty(\y)
1521 fillColor_ { arg acolor;
1522 this.setProperty(\fillColor, acolor)
1524 strokeColor_ { arg acolor;
1525 this.setProperty(\strokeColor, acolor)
1527 colors_ { arg strokec, fillc;
1528 this.strokeColor_(strokec);
1529 this.fillColor_(fillc);
1531 currentvalue_ { arg iny;
1532 this.setProperty(\y, iny)
1534 showIndex_ { arg abool;
1535 this.setProperty(\showIndex, abool)
1537 drawLines { arg abool;
1538 this.setProperty(\drawLines, abool)
1540 drawLines_ { arg abool;
1541 this.drawLines(abool)
1543 drawRects_ { arg abool;
1544 this.setProperty(\drawRects, abool)
1546 readOnly_ { arg val;
1548 this.setProperty(\readOnly, val);
1550 editable_ { arg val;
1552 this.setProperty(\readOnly, editable.not);
1554 thumbSize_ { arg val;
1555 this.setProperty(\thumbSize, val)
1557 indexThumbSize_ { arg val;
1558 this.setProperty(\indexThumbSize, val)
1560 valueThumbSize_ { arg val;
1561 this.setProperty(\valueThumbSize, val)
1563 indexIsHorizontal_ { arg val;
1564 this.setProperty(\isHorizontal, val);
1566 defaultCanReceiveDrag { ^true; }
1567 defaultReceiveDrag {
1568 if(currentDrag.at(0).isSequenceableCollection, {
1569 this.value_(currentDrag.at(0));
1570 this.reference_(currentDrag.at(1));
1572 this.value_(currentDrag);
1576 var setsize, vals, rvals, outval;
1577 rvals = this.reference;
1579 if(this.selectionSize > 1, {
1580 vals = vals.copyRange(this.index, this.selectionSize + this.index);});
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);
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
1601 *paletteExample { arg parent, bounds;
1603 example = this.new(parent, bounds).valueThumbSize_(2);
1608 metaAction.value(this)
1612 SCEnvelopeView : SCView {
1613 var connection, <>allConnections, doOnce;
1614 // var <>mouseUpAction;
1616 var < fixedSelection = false;
1619 var <editable = true;
1620 var <curves = \linear;
1621 var <gridOn, <gridColor, <grid;
1623 init { arg argParent, argBounds;
1624 super.init(argParent, argBounds);
1626 gridColor = Color(0, 0, 0.8, 0.3);
1627 grid = Point(0.1, 0.1);
1631 mouseBeginTrack { arg x, y, modifiers;}
1632 mouseTrack { arg x, y, modifiers; }
1633 mouseEndTrack { arg x, y, modifiers;
1634 mouseUpAction.value(this);
1638 this.setProperty(\setGrid, [point.x, point.y]);
1643 this.setProperty(\showGrid, bool);
1647 gridColor_ { arg color;
1648 this.setProperty(\setGridColor, color);
1653 ^super.properties ++ #[\value, \thumbSize, \fillColor, \strokeColor, \xOffset, \x, \y, \showIndex, \drawLines, \drawRects, \selectionSize, \startIndex, \thumbWidth, \absoluteX, \isFilled, \step, \setCurve, \setCurves, \showGrid, setGridColor, \setGrid]
1656 step_ { arg stepSize;
1657 this.setPropertyWithAction(\step, stepSize);
1661 ^this.getProperty(\step)
1664 valueAction_ { arg val;
1669 currentvalue { //returns value of selected index
1670 ^this.getProperty(\y)
1672 currentvalue_ { arg iny;
1673 this.setProperty(\y, iny)
1676 strokeColor_ { arg acolor;
1677 this.setProperty(\strokeColor, acolor)
1679 colors_ { arg strokec, fillc;
1680 this.strokeColor_(strokec);
1681 this.fillColor_(fillc);
1684 drawLines { arg abool;
1685 this.setProperty(\drawLines, abool)
1687 drawLines_ { arg abool;
1688 this.drawLines(abool)
1690 drawRects_ { arg abool;
1691 this.setProperty(\drawRects, abool)
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 });
1703 if (unicode == 16rF703, { this.selectIndex((this.index+1)%this.size) ^this });
1704 if (unicode == 16rF702, { this.selectIndex((this.index-1)%this.size) ^this });
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 });
1710 ^nil // bubble if it's an invalid key
1714 metaAction.value(this)
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;
1722 this.size = val.at(0).size;
1723 this.setProperty(\value, val)
1725 setString { arg index, astring;
1726 //items = items.add(astring);
1727 this.setProperty(\string, [index, astring])
1730 strings_ { arg astrings;
1731 astrings.do( { arg str, i;
1732 this.setString(i, str);
1737 ax = Array.newClear(this.size);
1738 ay = Array.newClear(this.size);
1739 axy = Array.with(ax, ay);
1740 ^this.getProperty(\value, axy)
1743 setThumbHeight { arg index, height;
1744 this.setProperty(\thumbHeight, [index, height]);
1746 thumbHeight_ { arg height;
1747 this.setThumbHeight(-1, height);
1749 setThumbWidth { arg index, width;
1750 this.setProperty(\thumbWidth, [index, width]);
1752 thumbWidth_ { arg width;
1753 this.setThumbWidth(-1, width);
1755 setThumbSize { arg index, size;
1756 this.setProperty(\thumbSize, [index, size]);
1758 thumbSize_ { arg size;
1759 this.setThumbSize(-1, size);
1761 setFillColor { arg index, color;
1762 this.setProperty(\fillColor, [index, color]);
1764 fillColor_ { arg color;
1765 this.setFillColor(-1, color);
1768 curves_ { arg inCurves;
1770 var shapeNum, curveNum=0;
1772 if(curves.isKindOf(Array)) {
1773 curveNumbers = curves.collect { |it|
1774 shapeNum = this.shapeNumber(it);
1780 [shapeNum, curveNum]
1782 // this.debug(curveNumbers);
1783 this.prSetCurves(curveNumbers);
1785 shapeNum = this.shapeNumber(curves);
1791 this.prSetCurve([-1, shapeNum, curveNum]);
1795 setEnv { arg env, minValue, maxValue, minTime, maxTime;
1799 times = Array.newClear(env.times.size + 1);
1801 for(1, env.times.size, { arg i;
1802 times[i] = times[i-1] + env.times[i-1];
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);
1818 editEnv { arg env, minValue, maxValue, duration;
1819 var vals, levels, times, lastTime = 0;
1821 levels = vals[0].linlin(0, 1, minValue, maxValue);
1822 times = vals[1].collect { |it|
1824 out = it - lastTime;
1829 env.levels_(levels);
1830 env.curves_(this.curves);
1833 asEnv { arg env, minValue, maxValue, duration;
1834 var vals, levels, times, lastTime = 0;
1836 levels = vals[0].linlin(0, 1, minValue, maxValue);
1837 times = vals[1].collect { |it|
1839 out = it - lastTime;
1844 env.levels_(levels);
1845 env.curves_(this.curves);
1846 ^Env(levels, times, this.curves);
1849 *paletteExample { arg parent, bounds;
1850 ^this.new(parent, bounds).setEnv(Env([0.1, 0.3, 0.4, 0.01], [0.3, 1, 3]));
1854 this.setProperty(\setCurves, arr);
1858 // this.debug([\setCurves, arr]);
1859 this.setProperty(\setCurve, arr);
1862 shapeNumber { arg shapeName;
1864 shape = Env.shapeNames.at(shapeName);
1865 if (shape.notNil) { ^shape } {^5};
1868 connect { arg from, aconnections;
1869 this.setProperty(\connect, [from, aconnections.asFloat]);
1872 select { arg index; //this means no refresh;
1873 this.setProperty(\setIndex, index);
1875 selectIndex { arg index; //this means that the view will be refreshed
1876 this.setProperty(\selectedIndex, index);
1878 x { //returns selected x
1879 ^this.getProperty(\x);
1882 ^this.getProperty(\y);
1885 this.setProperty(\x, ax);
1888 this.setProperty(\y, ay);
1891 ^this.getProperty(\selectedIndex)
1894 ^this.getProperty(\lastIndex)
1897 setEditable { arg index, boolean;
1898 this.setProperty(\editable, [index, boolean]);
1901 editable_ { arg boolean;
1902 this.setEditable(-1, boolean);
1905 selectionColor_ { arg acolor;
1906 this.setProperty(\selectionColor, acolor)
1911 defaultReceiveDrag {
1912 if(currentDrag.isString, {
1914 items = items.insert(this.lastIndex + 1, currentDrag);
1915 this.strings_(items);
1917 this.value_(currentDrag);
1921 addValue { arg xval, yval;
1922 var arr, arrx, arry, aindx;
1927 if(val>xval and: aindx.isNil) {
1931 // this.debug(aindx);
1932 arrx = arrx.insert(aindx , xval);
1933 arry = arry.insert(aindx , yval);
1934 this.value_([arrx, arry]);
1937 fixedSelection_ { arg bool;
1938 fixedSelection = bool;
1939 this.setProperty(\setFixedSelection, bool);
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
1953 // and SCMultiSlider by jan t.
1954 // added customizable drag handlers, cx