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 *implementsClass { ^this.name.asString[2..].asSymbol }
13 *new { arg parent, bounds;
14 ^super.new.init(parent, bounds);
19 *paletteExample { arg parent, bounds;
20 ^this.new(parent, bounds);
23 init { arg argParent, argBounds;
24 parent = argParent.asView; // actual view
25 background = Color.clear;
26 // call asView again because parent by this point might be a FlowView
27 this.prInit(parent.asView, argBounds.asRect, this.class.viewClass);
28 argParent.add(this);//maybe window or viewadapter
34 ^this.getProperty(\bounds, Rect.new)
37 this.setProperty(\bounds, rect)
41 ^this.getProperty(\visible)
44 this.setProperty(\visible, bool)
48 ^this.getProperty(\enabled)
51 this.setProperty(\enabled, bool)
55 ^this.getProperty(\canFocus)
58 this.setProperty(\canFocus, bool)
61 focus { arg flag=true;
72 this.setProperty(\focusColor, color)
75 ^this.getProperty(\focusColor, Color.new)
79 ^this.getProperty(\id)
82 this.setProperty(\id, id)
85 dragLabel_ { arg string;
86 this.setProperty(\dragLabel, string)
99 isClosed { ^dataptr.isNil }
100 notClosed { ^dataptr.notNil }
103 parent.prRemoveChild(this);
107 "SCView-remove : this view already removed.".debug(this);
111 resize behaviour in an SCCompositeView:
116 1 - fixed to left, fixed to top
117 2 - horizontally elastic, fixed to top
118 3 - fixed to right, fixed to top
120 4 - fixed to left, vertically elastic
121 5 - horizontally elastic, vertically elastic
122 6 - fixed to right, vertically elastic
124 7 - fixed to left, fixed to bottom
125 8 - horizontally elastic, fixed to bottom
126 9 - fixed to right, fixed to bottom
130 ^this.getProperty(\resize)
133 resize_ { arg resize;
134 this.setProperty(\resize, resize)
137 background_ { arg color;
139 this.setProperty(\background, color)
142 addAction { arg func, selector=\action;
143 this.perform(selector.asSetter, this.perform(selector).addFunc(func));
146 removeAction { arg func, selector=\action;
147 this.perform(selector.asSetter, this.perform(selector).removeFunc(func));
150 mouseDown { arg x, y, modifiers, buttonNumber, clickCount;
151 mouseDownAction.value(this, x, y, modifiers, buttonNumber, clickCount);
154 mouseUp { arg x, y, modifiers;
155 mouseUpAction.value(this, x, y, modifiers)
158 mouseMove { arg x, y, modifiers;
159 mouseMoveAction.value(this, x, y, modifiers)
162 mouseOver { arg x, y;
163 mouseOverAction.value(this, x, y);
166 keyDown { arg char, modifiers, unicode, keycode;
167 globalKeyDownAction.value(this, char, modifiers, unicode, keycode);
168 this.handleKeyDownBubbling(this, char, modifiers, unicode, keycode);
171 keyModifiersChanged { arg modifiers;
172 this.handleKeyModifiersChangedBubbling(this, modifiers)
175 handleKeyModifiersChangedBubbling { arg view, modifiers;
177 // nil from keyDownAction --> pass it on
178 if (keyModifiersChangedAction.isNil) {
179 // this.defaultKeyDownAction(char, modifiers, unicode, keycode);
182 result = keyModifiersChangedAction.value(view, modifiers);
185 // call keydown action of parent view
186 parent.handleKeyModifiersChangedBubbling(view, modifiers);
190 defaultKeyDownAction { ^nil }
192 handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
194 // nil from keyDownAction --> pass it on
195 if (keyDownAction.isNil) {
196 result = this.defaultKeyDownAction(char, modifiers, unicode, keycode);
198 result = keyDownAction.value(view, char, modifiers, unicode, keycode);
201 // call keydown action of parent view
202 parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode);
207 keyUp { arg char, modifiers, unicode, keycode;
208 this.keyTyped = char;
209 // always call global keydown action first
210 globalKeyUpAction.value(this, char, modifiers, unicode, keycode);
211 this.handleKeyUpBubbling(this, char, modifiers, unicode, keycode);
214 defaultKeyUpAction { ^nil }
216 handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
218 // nil from keyDownAction --> pass it on
219 if (keyUpAction.isNil) {
220 result = this.defaultKeyUpAction(char, modifiers, unicode, keycode);
222 result = keyUpAction.value(view, char, modifiers, unicode, keycode);
225 // call keydown action of parent view
226 parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode);
231 currentDrag = if (beginDragAction.notNil)
233 beginDragAction.value(this)
237 currentDragString = currentDrag.asCompileString;
240 defaultGetDrag { ^nil }
243 ^if(canReceiveDragHandler.notNil) {
244 canReceiveDragHandler.value(this)
246 this.defaultCanReceiveDrag
249 defaultCanReceiveDrag { ^false }
251 if(receiveDragHandler.notNil) {
252 receiveDragHandler.value(this, x, y)
254 this.defaultReceiveDrag(x, y)
256 currentDrag = currentDragString = nil;
259 // get the view parent tree up to the SCTopView
264 while( {(view = view.asView.parent).notNil}, { parents.add(view)});
273 ^#[\bounds, \visible, \enabled, \canFocus, \resize, \background,
274 \minWidth, \maxWidth, \minHeight, \maxHeight, \focusColor]
278 ^this.properties.collect( { arg name;
279 [name, this.perform(name)]
283 setPropertyList { arg list;
287 this.perform(name.asSetter, value);
292 prInit { arg argParent, argBounds, argViewClass;
294 ^this.primitiveFailed
297 prClose { dataptr = nil; onClose.value(this); }
300 ^this.primitiveFailed
302 setProperty { arg key, value;
304 ^this.primitiveFailed
306 getProperty { arg key, value;
308 ^this.primitiveFailed
310 setPropertyWithAction { arg symbol, obj;
311 // setting some properties may need to have the action called.
312 if (this.setProperty(symbol, obj), {
313 // setProperty returns true if action needs to be called.
319 // // this is called when an NSString is the drag object
320 // // from outside of the SC app
321 // // we compile it to an SCObject.
322 // currentDragString = currentDrag;
323 // currentDrag = currentDrag.interpret;
327 ^this.getProperty(\absoluteBounds, Rect.new)
331 SCContainerView : SCView { // abstract class
333 var <children, <decorator;
336 children = children.add(child);
337 if (decorator.notNil, { decorator.place(child); });
340 init { arg argParent, argBounds;
341 super.init(argParent, argBounds);
345 children.copy.do { |child| child.remove };
348 addFlowLayout { arg margin, gap;
349 this.decorator_( FlowLayout( this.bounds.moveTo(0, 0), margin, gap ) );
353 decorator_ { arg decor;
354 decor.bounds = decor.bounds.moveTo(0, 0);
359 prRemoveChild { arg child;
360 children.remove(child);
361 // ... decorator should re-place all
364 //bounds_ ... replace all
368 children.do( { arg item; item.prClose });
373 SCCompositeView : SCContainerView {
376 SCTopView : SCCompositeView {
378 // created by SCWindow
379 handleKeyModifiersChangedBubbling { arg view, modifiers;
380 keyModifiersChangedAction.value(view, modifiers);
382 handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
383 var currentAppModal, window;
384 keyDownAction.value(view, char, modifiers, unicode, keycode);
386 handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
387 keyUpAction.value(view, char, modifiers, unicode, keycode);
390 //only in construction mode, handled internally
391 canReceiveDrag { ^currentDrag.isKindOf(Class)}
392 // remove { this.removeAll }
395 SCWindow.allWindows.do { |win|
396 if(win.view == this) {
402 /* construction mode */
404 constructionGrid_ { arg point;
405 this.setProperty( \constructionGrid, point );
409 ^this.getProperty( \constructionGrid, Point.new );
412 enableConstructionGrid_ { arg flag;
413 this.setProperty( \enableConstructionGrid, flag );
416 enableConstructionGrid {
417 ^this.getProperty( \enableConstructionGrid );
420 //private called from lang
421 setConstructionMode { |flag|
422 this.setProperty( \setConstructionMode, flag )
425 defaultReceiveDrag { |x, y|
427 win = this.findWindow;
428 view = currentDrag.paletteExample(win, Rect(x, y, 140, 24)).enabled_(false);
429 view.keyDownAction_( { |view, char, modifiers, unicode, keycode|
437 SCScrollTopView : SCTopView {
438 var <autohidesScrollers = true, <hasHorizontalScroller = true, <hasVerticalScroller = true;
439 var <autoScrolls = true;
441 autohidesScrollers_ { |bool|
442 autohidesScrollers = bool;
443 this.setProperty(\setAutohidesScrollers, bool);
446 hasHorizontalScroller_ { |bool|
447 hasHorizontalScroller = bool;
448 this.setProperty(\setHasHorizontalScroller, bool);
451 hasVerticalScroller_ { |bool|
452 hasVerticalScroller = bool;
453 this.setProperty(\setHasVerticalScroller, bool);
456 visibleOrigin_ { arg point;
457 this.setProperty( \clipViewOrigin, point );
460 visibleOrigin { ^this.getProperty( \clipViewOrigin, Point.new );}
462 autoScrolls_ { |bool|
464 this.setProperty(\setAutoScrolls, bool);
468 ^this.getProperty(\innerBounds, Rect.new)
472 var bounds = this.absoluteBounds;
473 this.getParents.do( { |parent|
474 bounds = bounds.moveBy(parent.bounds.left.neg, parent.bounds.top.neg)
479 // handleKeyModifiersChangedBubbling { arg view, modifiers;
481 // // nil from keyDownAction --> pass it on
482 // if (keyModifiersChangedAction.isNil) {
485 // result = keyModifiersChangedAction.value(view, modifiers);
487 // if(result.isNil) {
488 // // call keydown action of parent view
489 // parent.handleKeyModifiersChangedBubbling(view, modifiers);
493 // handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
495 // // nil from keyDownAction --> pass it on
496 // if (keyDownAction.isNil) {
497 // result = this.defaultKeyDownAction(char, modifiers, unicode, keycode);
499 // result = keyDownAction.value(view, char, modifiers, unicode, keycode);
501 // if(result.isNil) {
502 // // call keydown action of parent view
503 // parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode);
507 // handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
509 // // nil from keyDownAction --> pass it on
510 // if (keyUpAction.isNil) {
511 // result = this.defaultKeyUpAction(char, modifiers, unicode, keycode);
513 // result = keyUpAction.value(view, char, modifiers, unicode, keycode);
515 // if(result.isNil) {
516 // // call keydown action of parent view
517 // parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode);
523 SCScrollView : SCScrollTopView {
524 var <hasBorder = false;
526 hasBorder_ { arg bool = true;
527 this.setProperty(\border, bool);
530 init { |argParent, argBounds|
531 super.init(argParent, argBounds);
534 handleKeyModifiersChangedBubbling { arg view, modifiers;
536 // nil from keyDownAction --> pass it on
537 if (keyModifiersChangedAction.isNil) {
540 result = keyModifiersChangedAction.value(view, modifiers);
543 // call keydown action of parent view
544 parent.handleKeyModifiersChangedBubbling(view, modifiers);
548 handleKeyDownBubbling { arg view, char, modifiers, unicode, keycode;
550 // nil from keyDownAction --> pass it on
551 if (keyDownAction.isNil) {
552 result = this.defaultKeyDownAction(char, modifiers, unicode, keycode);
554 result = keyDownAction.value(view, char, modifiers, unicode, keycode);
557 // call keydown action of parent view
558 parent.handleKeyDownBubbling(view, char, modifiers, unicode, keycode);
562 handleKeyUpBubbling { arg view, char, modifiers, unicode, keycode;
564 // nil from keyDownAction --> pass it on
565 if (keyUpAction.isNil) {
566 result = this.defaultKeyUpAction(char, modifiers, unicode, keycode);
568 result = keyUpAction.value(view, char, modifiers, unicode, keycode);
571 // call keydown action of parent view
572 parent.handleKeyUpBubbling(view, char, modifiers, unicode, keycode);
578 SCLayoutView : SCContainerView {
579 properties { ^super.properties ++ #[\spacing] }
582 ^this.getProperty(\spacing, 0)
584 spacing_ { arg distance;
585 this.setProperty(\spacing, distance)
587 setProperty { |key, value|
588 super.setProperty(key, value);
592 SCHLayoutView : SCLayoutView {}
593 SCVLayoutView : SCLayoutView {}
596 SCControlView : SCView { // abstract class
599 SCSliderBase : SCControlView {
601 var <>shift_scale = 100.0, <>ctrl_scale = 10.0, <>alt_scale = 0.1;
603 getScale { |modifiers|
605 { modifiers & 131072 == 131072 } { shift_scale }
606 { modifiers & 262144 == 262144 } { ctrl_scale }
607 { modifiers & 524288 == 524288 } { alt_scale }
612 ^this.getProperty(\knobColor, Color.new)
614 knobColor_ { arg color;
615 this.setProperty(\knobColor, color)
618 step_ { arg stepSize;
619 // this.setPropertyWithAction(\step, stepSize); // action really needed?
620 this.setProperty(\step, stepSize);
624 ^this.getProperty(\step)
628 ^super.properties ++ #[\knobColor, \step]
633 SCSlider : SCSliderBase {
636 ^this.getProperty(\value)
639 this.setProperty(\value, val);
641 valueAction_ { arg val;
642 this.setPropertyWithAction(\value, val);
645 increment { |zoom=1| ^this.valueAction = this.value + (max(this.step, this.pixelStep) * zoom) }
646 decrement { |zoom=1| ^this.valueAction = this.value - (max(this.step, this.pixelStep) * zoom) }
649 var bounds = this.bounds;
650 ^(bounds.width.max(bounds.height) - this.thumbSize).reciprocal
653 defaultKeyDownAction { arg char, modifiers, unicode, keycode;
654 var zoom = this.getScale(modifiers);
657 // rand could also use zoom factors
658 if (char == $r, { this.valueAction = 1.0.rand; ^this });
659 if (char == $n, { this.valueAction = 0.0; ^this });
660 if (char == $x, { this.valueAction = 1.0; ^this });
661 if (char == $c, { this.valueAction = 0.5; ^this });
663 if (char == $], { this.increment(zoom); ^this });
664 if (char == $[, { this.increment(zoom); ^this });
665 if (unicode == 16rF700, { this.increment(zoom); ^this });
666 if (unicode == 16rF703, { this.increment(zoom); ^this });
667 if (unicode == 16rF701, { this.decrement(zoom); ^this });
668 if (unicode == 16rF702, { this.decrement(zoom); ^this });
670 ^nil // bubble if it's an invalid key
676 defaultCanReceiveDrag {
677 ^currentDrag.isNumber
680 this.valueAction = currentDrag;
684 ^this.getProperty(\thumbSize, 12);
686 thumbSize_ { arg size;
687 this.setProperty(\thumbSize, size);
691 ^super.properties ++ #[\thumbSize];
695 SCRangeSlider : SCSliderBase {
697 *paletteExample { arg parent, bounds;
699 v = this.new(parent, bounds);
706 ^this.getProperty(\lo)
709 this.setProperty(\lo, val);
712 this.setPropertyWithAction(\lo, val);
715 ^this.getProperty(\hi)
718 this.setProperty(\hi, val);
721 this.setPropertyWithAction(\hi, val);
724 ^this.getProperty(\range)
727 this.setProperty(\range, val);
729 activeRange_ { arg val;
730 this.setPropertyWithAction(\range, val);
733 setSpan { arg lo, hi;
738 setSpanActive { arg lo, hi;
739 this.setSpan( lo, hi );
743 setDeviation { arg deviation, average;
744 var lo = ( 1 - deviation ) * average;
745 this.setSpan(lo, lo + deviation);
749 ^super.properties ++ #[\lo, \hi]
753 var bounds = this.bounds;
754 ^(bounds.width.max(bounds.height)).reciprocal
758 var inc = (max(this.step, this.pixelStep) * zoom);
759 var newHi = (this.hi + inc);
764 this.lo_(this.lo + inc).activeHi_(newHi);
768 var inc = (max(this.step, this.pixelStep) * zoom);
769 var newLo = (this.lo - inc);
774 this.lo_(newLo).activeHi_(this.hi - inc);
777 defaultKeyDownAction { arg char, modifiers, unicode;
779 var zoom = this.getScale(modifiers);
784 this.activeLo_(min(a, b));
785 this.activeHi_(max(a, b));
788 if (char == $n, { this.activeLo_(0.0); this.activeHi_(0.0); ^this });
789 if (char == $x, { this.activeLo_(1.0); this.activeHi_(1.0); ^this });
790 if (char == $c, { this.activeLo_(0.5); this.activeHi_(0.5); ^this });
791 if (char == $a, { this.activeLo_(0.0); this.activeHi_(1.0); ^this });
792 if (unicode == 16rF700, { this.increment(zoom); ^this });
793 if (unicode == 16rF703, { this.increment(zoom); ^this });
794 if (unicode == 16rF701, { this.decrement(zoom); ^this });
795 if (unicode == 16rF702, { this.decrement(zoom); ^this });
796 ^nil // bubble if it's an invalid key
798 defaultGetDrag { ^Point(this.lo, this.hi) }
799 defaultCanReceiveDrag {
800 ^currentDrag.isKindOf(Point);
803 // changed to x, y instead of lo, hi
804 this.lo = currentDrag.x;
805 this.hi = currentDrag.y;
810 SC2DSlider : SCSliderBase {
811 *implementsClass { ^'Slider2D' }
813 ^this.getProperty(\x)
816 this.setProperty(\x, val);
819 this.setPropertyWithAction(\x, val);
822 ^this.getProperty(\y)
825 this.setProperty(\y, val);
828 this.setPropertyWithAction(\y, val);
836 setXYActive { arg x, y;
842 ^super.properties ++ #[\x, \y]
845 pixelStepX { ^(this.bounds.width).reciprocal }
846 pixelStepY { ^(this.bounds.height).reciprocal }
848 incrementY { |zoom=1| ^this.y = this.y + (this.pixelStepY * zoom) }
849 decrementY { |zoom=1| ^this.y = this.y - (this.pixelStepY * zoom) }
850 incrementX { |zoom=1| ^this.x = this.x + (this.pixelStepX * zoom) }
851 decrementX { |zoom=1| ^this.x = this.x - (this.pixelStepX * zoom) }
853 defaultKeyDownAction { arg char, modifiers, unicode, keycode;
854 var zoom = this.getScale(modifiers);
856 if (char == $r, { this.x = 1.0.rand; this.y = 1.0.rand; ^this });
857 if (char == $n, { this.x = 0.0; this.y = 0.0; ^this });
858 if (char == $x, { this.x = 1.0; this.y = 1.0; ^this });
859 if (char == $c, { this.x = 0.5; this.y = 0.5; ^this });
860 if (unicode == 16rF700, { this.incrementY(zoom); ^this });
861 if (unicode == 16rF703, { this.incrementX(zoom); ^this });
862 if (unicode == 16rF701, { this.decrementY(zoom); ^this });
863 if (unicode == 16rF702, { this.decrementX(zoom); ^this });
864 ^nil // bubble if it's an invalid key
867 ^Point(this.x, this.y)
869 defaultCanReceiveDrag {
870 ^currentDrag.isKindOf(Point);
873 this.setXYActive(currentDrag.x, currentDrag.y);
877 SC2DTabletSlider : SC2DSlider {
878 *implementsClass { ^'TabletSlider2D' }
879 // var <>mouseDownAction, <>mouseUpAction;
881 mouseDown { arg x, y, pressure, tiltx, tilty, deviceID,
882 buttonNumber, clickCount, absoluteZ, rotation;
883 mouseDownAction.value(this, x, y, pressure, tiltx, tilty, deviceID,
884 buttonNumber, clickCount, absoluteZ, rotation);
886 mouseUp { arg x, y, pressure, tiltx, tilty, deviceID,
887 buttonNumber, clickCount, absoluteZ, rotation;
888 mouseUpAction.value(this, x, y, pressure, tiltx, tilty, deviceID,
889 buttonNumber, clickCount, absoluteZ, rotation);
891 doAction { arg x, y, pressure, tiltx, tilty, deviceID,
892 buttonNumber, clickCount, absoluteZ, rotation;
893 action.value(this, x, y, pressure, tiltx, tilty, deviceID,
894 buttonNumber, clickCount, absoluteZ, rotation);
898 SCButton : SCControlView {
901 *paletteExample { arg parent, bounds;
903 v = this.new(parent, bounds);
905 ["Push", Color.black, Color.red],
906 ["Pop", Color.white, Color.blue]];
911 ^this.getProperty(\value)
914 this.setProperty(\value, val);
916 valueAction_ { arg val;
917 this.setPropertyWithAction(\value, val);
920 doAction { arg modifiers;
921 action.value(this, modifiers);
924 defaultKeyDownAction { arg char, modifiers, unicode;
925 if (char == $ , { this.valueAction = this.value + 1; ^this });
926 if (char == $\r, { this.valueAction = this.value + 1; ^this });
927 if (char == $\n, { this.valueAction = this.value + 1; ^this });
928 if (char == 3.asAscii, { this.valueAction = this.value + 1; ^this });
929 ^nil // bubble if it's an invalid key
934 this.setProperty(\font, font)
939 this.setProperty(\states, states);
943 ^super.properties ++ #[\value, \font, \states]
949 defaultCanReceiveDrag {
950 ^currentDrag.isNumber or: { currentDrag.isKindOf(Function) };
953 if (currentDrag.isNumber) {
954 this.valueAction = currentDrag;
956 this.action = currentDrag;
962 SCPopUpMenu : SCControlView {
965 *paletteExample { arg parent, bounds;
967 v = this.new(parent, bounds);
968 v.items = #["linear", "exponential", "sine", "welch", "squared", "cubed"];
973 ^this.getProperty(\value)
976 this.setProperty(\value, val);
978 valueAction_ { arg val;
979 this.setPropertyWithAction(\value, val);
982 defaultKeyDownAction { arg char, modifiers, unicode;
983 if (char == $ , { this.valueAction = this.value + 1; ^this });
984 if (char == $\r, { this.valueAction = this.value + 1; ^this });
985 if (char == $\n, { this.valueAction = this.value + 1; ^this });
986 if (char == 3.asAscii, { this.valueAction = this.value + 1; ^this });
987 if (unicode == 16rF700, { this.valueAction = this.value - 1; ^this });
988 if (unicode == 16rF703, { this.valueAction = this.value + 1; ^this });
989 if (unicode == 16rF701, { this.valueAction = this.value + 1; ^this });
990 if (unicode == 16rF702, { this.valueAction = this.value - 1; ^this });
991 ^nil // bubble if it's an invalid key
995 this.setProperty(\font, font)
999 this.setProperty(\items, items);
1007 ^this.getProperty(\stringColor, Color.new)
1009 stringColor_ { arg color;
1010 this.setProperty(\stringColor, color)
1014 ^super.properties ++ #[\value, \font, \items, \stringColor]
1020 defaultCanReceiveDrag {
1021 ^currentDrag.isNumber;
1023 defaultReceiveDrag {
1024 this.valueAction = currentDrag;
1030 SCStaticTextBase : SCView {
1031 var <string, <font, <object, <>setBoth=true;
1033 font_ { arg argFont;
1035 this.setProperty(\font, font)
1038 string_ { arg argString;
1039 string = argString.asString;
1040 this.setProperty(\string, string)
1043 this.setProperty(\align, align)
1047 ^this.getProperty(\stringColor, Color.new)
1049 stringColor_ { arg color;
1050 this.setProperty(\stringColor, color)
1055 if (setBoth) { this.string = object.asString(80); };
1059 ^super.properties ++ #[\string, \font, \stringColor]
1063 SCStaticText : SCStaticTextBase {
1064 *paletteExample { arg parent, bounds;
1066 v = this.new(parent, bounds);
1067 v.string = "The lazy brown fox";
1073 SCNumberBoxOld : SCStaticTextBase {
1074 var <> keyString, <>step=1, <>scroll_step=1;
1075 var <>typingColor, <>normalColor;
1076 var <>clipLo = -inf, <>clipHi = inf, hit, inc=1.0, <>scroll=true;
1077 var <>shift_scale = 100.0, <>ctrl_scale = 10.0, <>alt_scale = 0.1;
1079 getScale { |modifiers|
1081 { modifiers & 131072 == 131072 } { shift_scale }
1082 { modifiers & 262144 == 262144 } { ctrl_scale }
1083 { modifiers & 524288 == 524288 } { alt_scale }
1087 *paletteExample { arg parent, bounds;
1089 v = this.new(parent, bounds);
1094 init { arg argParent, argBounds;
1095 typingColor = Color.red;
1096 normalColor = Color.black;
1097 background = Color.white;
1098 parent = argParent.asView; // actual view
1099 this.prInit(parent.asView, argBounds.asRect, this.class.viewClass);
1100 argParent.add(this);//maybe window or viewadapter
1103 increment { arg mul=1; this.valueAction = this.value + (step*mul); }
1104 decrement { arg mul=1; this.valueAction = this.value - (step*mul); }
1106 defaultKeyDownAction { arg char, modifiers, unicode;
1107 var zoom = this.getScale(modifiers);
1109 // standard chardown
1110 if (unicode == 16rF700, { this.increment(zoom); ^this });
1111 if (unicode == 16rF703, { this.increment(zoom); ^this });
1112 if (unicode == 16rF701, { this.decrement(zoom); ^this });
1113 if (unicode == 16rF702, { this.decrement(zoom); ^this });
1115 if ((char == 3.asAscii) || (char == $\r) || (char == $\n), { // enter key
1116 if (keyString.notNil, { // no error on repeated enter
1117 this.valueAction_(keyString.asFloat);
1121 if (char == 127.asAscii, { // delete key
1123 this.string = object.asString;
1124 this.stringColor = normalColor;
1127 if (char.isDecDigit || "+-.eE".includes(char), {
1128 if (keyString.isNil, {
1129 keyString = String.new;
1130 this.stringColor = typingColor;
1132 keyString = keyString.add(char);
1133 this.string = keyString;
1139 ^nil // bubble if it's an invalid key
1145 this.stringColor = normalColor;
1146 object = val !? { val.clip(clipLo, clipHi) };
1147 this.string = object.asString;
1149 valueAction_ { arg val;
1152 this.value = val !? { val.clip(clipLo, clipHi) };
1153 if (object != prev, { this.doAction });
1157 this.deprecated(thisMethod, SCView.findMethod(\background));
1160 boxColor_ { arg color;
1161 this.deprecated(thisMethod, SCView.findMethod(\background_));
1162 this.background_(color)
1166 ^super.properties ++ #[\boxColor]
1171 defaultCanReceiveDrag {
1172 ^currentDrag.isNumber;
1174 defaultReceiveDrag {
1175 this.valueAction = currentDrag;
1178 mouseDown { arg x, y, modifiers, buttonNumber, clickCount;
1180 if (scroll == true, { inc = this.getScale(modifiers) });
1181 mouseDownAction.value(this, x, y, modifiers, buttonNumber, clickCount)
1184 mouseMove { arg x, y, modifiers;
1186 if (scroll == true, {
1188 // horizontal or vertical scrolling:
1189 if ( (x - hit.x) < 0 or: { (y - hit.y) > 0 }) { direction = -1.0; };
1191 this.valueAction = (this.value + (inc * this.scroll_step * direction));
1194 mouseMoveAction.value(this, x, y, modifiers);
1201 SCListView : SCControlView {
1202 var <font, <items, <>enterKeyAction;
1204 *paletteExample { arg parent, bounds;
1206 v = this.new(parent, bounds);
1207 v.items = #["linear", "exponential", "sine", "welch", "squared", "cubed"];
1211 init { arg argParent, argBounds;
1212 parent = argParent.asView; // actual view
1213 // call asView again because parent by this point might be a FlowView
1214 this.prInit(parent.asView, argBounds.asRect, this.class.viewClass);
1215 argParent.add(this);//maybe window or viewadapter
1216 this.items = []; // trick to draw right in scrollviews
1223 ^this.getProperty(\value)
1226 this.setProperty(\value, val);
1228 valueAction_ { arg val;
1229 this.setPropertyWithAction(\value, val);
1232 defaultKeyDownAction { arg char, modifiers, unicode;
1234 if (char == $ , { this.valueAction = this.value + 1; ^this });
1235 if (char == $\r, { this.enterKeyAction.value(this); ^this });
1236 if (char == $\n, { this.enterKeyAction.value(this); ^this });
1237 if (char == 3.asAscii, { this.enterKeyAction.value(this); ^this });
1238 if (unicode == 16rF700, { this.valueAction = this.value - 1; ^this });
1239 if (unicode == 16rF703, { this.valueAction = this.value + 1; ^this });
1240 if (unicode == 16rF701, { this.valueAction = this.value + 1; ^this });
1241 if (unicode == 16rF702, { this.valueAction = this.value - 1; ^this });
1243 char = char.toUpper;
1244 index = items.detectIndex( { |item| item.asString.at(0).toUpper >= char });
1246 this.valueAction = index
1250 ^nil // bubble if it's an invalid key
1252 font_ { arg argFont;
1254 this.setProperty(\font, font)
1258 this.setProperty(\items, items);
1261 colors_ { arg incolors;
1262 this.setProperty(\itemColors, incolors);
1266 ^this.getProperty(\itemColors, {Color.new}!items.size);
1270 ^this.getProperty(\stringColor, Color.new)
1272 stringColor_ { arg color;
1273 this.setProperty(\stringColor, color)
1276 selectedStringColor {
1277 ^this.getProperty(\selectedStringColor, Color.new)
1279 selectedStringColor_ { arg color;
1280 this.setProperty(\selectedStringColor, color)
1284 ^this.getProperty(\hiliteColor, Color.new)
1286 hiliteColor_ { arg color;
1287 this.setProperty(\hiliteColor, color)
1291 ^super.properties ++ #[\value, \font, \items, \stringColor, \align, \itemColors]
1297 defaultCanReceiveDrag {
1298 ^currentDrag.isNumber;
1300 defaultReceiveDrag {
1301 this.valueAction = currentDrag;
1306 SCDragView : SCStaticTextBase {
1308 *paletteExample { arg parent, bounds;
1310 v = this.new(parent, bounds);
1311 v.object = \something;
1319 SCDragSource : SCDragView {
1323 SCDragSink : SCDragView {
1324 defaultCanReceiveDrag { ^true; }
1325 defaultReceiveDrag {
1326 this.object = currentDrag;
1331 SCDragBoth : SCDragSink {
1332 defaultGetDrag { ^object }
1336 SCUserView : SCView {
1338 // var <>mouseBeginTrackFunc, <>mouseTrackFunc, <>mouseEndTrackFunc;
1339 var < clearOnRefresh = true;
1340 var < drawingEnabled = true;
1342 init { |argParent, argBounds|
1343 super.init(argParent, argBounds);
1347 drawFunc.value(this) ;
1351 this.setProperty(\clearDrawing);
1355 this.deprecated(thisMethod);
1356 ^this.getProperty(\mousePosition, Point.new)
1359 clearOnRefresh_ { |bool|
1360 clearOnRefresh = bool;
1361 this.setProperty(\clearOnRefresh, bool); }
1364 this.setProperty(\animate, bool);
1368 ^this.getProperty(\frame);
1372 ^this.getProperty(\frameRate);
1375 drawingEnabled_ { |bool|
1376 drawingEnabled = bool;
1377 this.setProperty(\drawingEnabled, bool); }
1379 /* backwards compatibility */
1380 keyDownFunc_ { |action|
1381 "SCUserView:keyDownFunc deprecated, use SCUserView:keyDownAction".warn;
1382 keyDownAction = action;
1386 "SCUserView:keyDownFunc deprecated, use SCUserView:keyDownAction".warn;
1390 mouseBeginTrackFunc_ { |action|
1391 "SCUserView:mouseBeginTrackFunc deprecated, use SCUserView:mouseDownAction".warn;
1392 mouseDownAction = action;
1394 mouseBeginTrackFunc {
1395 "SCUserView:mouseBeginTrackFunc deprecated, use SCUserView:mouseDownAction".warn;
1399 mouseTrackFunc_ { |action|
1400 "SCUserView:mouseTrackFunc deprecated, use SCUserView:mouseMoveAction".warn;
1401 mouseMoveAction = action;
1404 "SCUserView:mouseTrackFunc deprecated, use SCUserView:mouseMoveAction".warn;
1408 mouseEndTrackFunc_ { |action|
1409 "SCUserView:mouseEndTrackFunc deprecated, use SCUserView:mouseUpAction".warn;
1410 mouseUpAction = action;
1414 "SCUserView:mouseEndTrackFunc deprecated, use SCUserView:mouseUpAction".warn;
1422 //SCFuncUserView : SCUserView {
1423 // var <>keyDownFunc, <>drawFunc;
1424 // var <>mouseBeginTrackFunc, <>mouseTrackFunc, <>mouseEndTrackFunc;
1426 // draw { drawFunc.value(this) }
1427 // mouseBeginTrack { arg x, y, modifiers;
1428 // mouseBeginTrackFunc.value(this, x, y, modifiers);
1430 // mouseTrack { arg x, y, modifiers;
1431 // mouseTrackFunc.value(this, x, y, modifiers);
1433 // mouseEndTrack { arg x, y, modifiers;
1434 // mouseEndTrackFunc.value(this, x, y, modifiers);
1436 // keyDown { arg key, modifiers, unicode;
1437 // keyDownFunc.value(this, key, modifiers, unicode)
1442 SCMultiSliderView : SCView {
1445 // var <>mouseUpAction;
1448 var <editable = true;
1449 var <elasticMode = 0;
1452 mouseBeginTrack { arg x, y, modifiers;}
1453 mouseTrack { arg x, y, modifiers; }
1454 mouseEndTrack { arg x, y, modifiers;
1455 mouseUpAction.value(this);
1458 ^super.properties ++ #[\value, \thumbSize, \fillColor, \strokeColor, \xOffset, \x, \y, \showIndex, \drawLines, \drawRects, \selectionSize, \startIndex, \referenceValues, \thumbWidth, \absoluteX, \isFilled, \step, \elasticResizeMode]
1463 elasticMode_ { arg mode;
1465 this.setProperty(\elasticResizeMode, mode);
1468 step_ { arg stepSize;
1469 this.setPropertyWithAction(\step, stepSize);
1473 ^this.getProperty(\step)
1476 value { //returns array
1477 ^this.getProperty(\value, Array.newClear(this.size))
1480 this.size = val.size;
1481 this.setProperty(\value, val)
1484 valueAction_ { arg val;
1485 this.size = val.size;
1486 this.setPropertyWithAction(\value, val);
1489 reference { //returns array
1490 ^this.getProperty(\referenceValues, Array.newClear(this.size))
1492 reference_ { arg val;
1493 //this.size = val.size;
1494 this.setProperty(\referenceValues, val)
1496 index { //returns selected index
1497 ^this.getProperty(\x)
1500 this.setProperty(\x, inx)
1502 isFilled_ { arg abool;
1503 this.setProperty(\isFilled, abool);
1505 xOffset_ { arg aval;
1506 this.setProperty(\xOffset, aval);
1510 this.setProperty(\xOffset, inx)
1513 startIndex_ { arg val; this.setProperty( \startIndex, val )}
1516 ^this.getProperty(\selectionSize)
1518 selectionSize_ { arg aval;
1519 this.setProperty(\selectionSize, aval)
1521 currentvalue { //returns value of selected index
1522 ^this.getProperty(\y)
1524 fillColor_ { arg acolor;
1525 this.setProperty(\fillColor, acolor)
1527 strokeColor_ { arg acolor;
1528 this.setProperty(\strokeColor, acolor)
1530 colors_ { arg strokec, fillc;
1531 this.strokeColor_(strokec);
1532 this.fillColor_(fillc);
1534 currentvalue_ { arg iny;
1535 this.setProperty(\y, iny)
1537 showIndex_ { arg abool;
1538 this.setProperty(\showIndex, abool)
1540 drawLines { arg abool;
1541 this.setProperty(\drawLines, abool)
1543 drawLines_ { arg abool;
1544 this.drawLines(abool)
1546 drawRects_ { arg abool;
1547 this.setProperty(\drawRects, abool)
1549 readOnly_ { arg val;
1551 this.setProperty(\readOnly, val);
1553 editable_ { arg val;
1555 this.setProperty(\readOnly, editable.not);
1557 thumbSize_ { arg val;
1558 this.setProperty(\thumbSize, val)
1560 indexThumbSize_ { arg val;
1561 this.setProperty(\indexThumbSize, val)
1563 valueThumbSize_ { arg val;
1564 this.setProperty(\valueThumbSize, val)
1566 indexIsHorizontal_ { arg val;
1567 this.setProperty(\isHorizontal, val);
1569 defaultCanReceiveDrag { ^true; }
1570 defaultReceiveDrag {
1571 if(currentDrag.at(0).isSequenceableCollection, {
1572 this.value_(currentDrag.at(0));
1573 this.reference_(currentDrag.at(1));
1575 this.value_(currentDrag);
1579 var setsize, vals, rvals, outval;
1580 rvals = this.reference;
1582 if(this.selectionSize > 1, {
1583 vals = vals.copyRange(this.index, this.selectionSize + this.index);});
1587 if(this.selectionSize > 1, {
1588 rvals = rvals.copyRange(this.index, this.selectionSize + this.index);});
1589 outval = outval.add(vals);
1590 outval = outval.add(rvals);
1595 defaultKeyDownAction { arg key, modifiers, unicode;
1596 //modifiers.postln; 16rF702
1597 if (unicode == 16rF703, { this.index = this.index + 1; ^this });
1598 if (unicode == 16rF702, { this.index = this.index - 1; ^this });
1599 if (unicode == 16rF700, { this.gap = this.gap + 1; ^this });
1600 if (unicode == 16rF701, { this.gap = this.gap - 1; ^this });
1601 ^nil // bubble if it's an invalid key
1604 *paletteExample { arg parent, bounds;
1606 example = this.new(parent, bounds).valueThumbSize_(2);
1611 metaAction.value(this)
1615 SCEnvelopeView : SCView {
1616 var connection, <>allConnections, doOnce;
1617 // var <>mouseUpAction;
1619 var < fixedSelection = false;
1622 var <editable = true;
1623 var <curves = \linear;
1624 var <gridOn, <gridColor, <grid;
1626 init { arg argParent, argBounds;
1627 super.init(argParent, argBounds);
1629 gridColor = Color(0, 0, 0.8, 0.3);
1630 grid = Point(0.1, 0.1);
1634 mouseBeginTrack { arg x, y, modifiers;}
1635 mouseTrack { arg x, y, modifiers; }
1636 mouseEndTrack { arg x, y, modifiers;
1637 mouseUpAction.value(this);
1641 this.setProperty(\setGrid, [point.x, point.y]);
1646 this.setProperty(\showGrid, bool);
1650 gridColor_ { arg color;
1651 this.setProperty(\setGridColor, color);
1656 ^super.properties ++ #[\value, \thumbSize, \fillColor, \strokeColor, \xOffset, \x, \y, \showIndex, \drawLines, \drawRects, \selectionSize, \startIndex, \thumbWidth, \absoluteX, \isFilled, \step, \setCurve, \setCurves, \showGrid, setGridColor, \setGrid]
1659 step_ { arg stepSize;
1660 this.setPropertyWithAction(\step, stepSize);
1664 ^this.getProperty(\step)
1667 valueAction_ { arg val;
1672 currentvalue { //returns value of selected index
1673 ^this.getProperty(\y)
1675 currentvalue_ { arg iny;
1676 this.setProperty(\y, iny)
1679 strokeColor_ { arg acolor;
1680 this.setProperty(\strokeColor, acolor)
1682 colors_ { arg strokec, fillc;
1683 this.strokeColor_(strokec);
1684 this.fillColor_(fillc);
1687 drawLines { arg abool;
1688 this.setProperty(\drawLines, abool)
1690 drawLines_ { arg abool;
1691 this.drawLines(abool)
1693 drawRects_ { arg abool;
1694 this.setProperty(\drawRects, abool)
1697 defaultCanReceiveDrag { ^true; }
1699 defaultKeyDownAction { arg key, modifiers, unicode;
1700 (modifiers==10617090).if { // shift key
1701 (this.index > 1.neg).if {
1702 if (unicode == 16rF703, { this.x = this.value[0][this.index] + this.step; ^this });
1703 if (unicode == 16rF702, { this.x = this.value[0][this.index] - this.step; ^this });
1706 if (unicode == 16rF703, { this.selectIndex((this.index+1)%this.size) ^this });
1707 if (unicode == 16rF702, { this.selectIndex((this.index-1)%this.size) ^this });
1709 (this.index > 1.neg).if {
1710 if (unicode == 16rF700, { this.y = this.value[1][this.index] + this.step; ^this });
1711 if (unicode == 16rF701, { this.y = this.value[1][this.index] - this.step; ^this });
1713 ^nil // bubble if it's an invalid key
1717 metaAction.value(this)
1721 if(val.at(1).size != val.at(0).size, {
1722 // otherwise its a fatal crash
1723 Error("SCEnvelopeView got mismatched times/levels arrays").throw;
1725 this.size = val.at(0).size;
1726 this.setProperty(\value, val)
1728 setString { arg index, astring;
1729 //items = items.add(astring);
1730 this.setProperty(\string, [index, astring])
1733 strings_ { arg astrings;
1734 astrings.do( { arg str, i;
1735 this.setString(i, str);
1740 ax = Array.newClear(this.size);
1741 ay = Array.newClear(this.size);
1742 axy = Array.with(ax, ay);
1743 ^this.getProperty(\value, axy)
1746 setThumbHeight { arg index, height;
1747 this.setProperty(\thumbHeight, [index, height]);
1749 thumbHeight_ { arg height;
1750 this.setThumbHeight(-1, height);
1752 setThumbWidth { arg index, width;
1753 this.setProperty(\thumbWidth, [index, width]);
1755 thumbWidth_ { arg width;
1756 this.setThumbWidth(-1, width);
1758 setThumbSize { arg index, size;
1759 this.setProperty(\thumbSize, [index, size]);
1761 thumbSize_ { arg size;
1762 this.setThumbSize(-1, size);
1764 setFillColor { arg index, color;
1765 this.setProperty(\fillColor, [index, color]);
1767 fillColor_ { arg color;
1768 this.setFillColor(-1, color);
1771 curves_ { arg inCurves;
1773 var shapeNum, curveNum=0;
1775 if(curves.isKindOf(Array)) {
1776 curveNumbers = curves.collect { |it|
1777 shapeNum = this.shapeNumber(it);
1783 [shapeNum, curveNum]
1785 // this.debug(curveNumbers);
1786 this.prSetCurves(curveNumbers);
1788 shapeNum = this.shapeNumber(curves);
1794 this.prSetCurve([-1, shapeNum, curveNum]);
1798 setEnv { arg env, minValue, maxValue, minTime, maxTime;
1802 times = Array.newClear(env.times.size + 1);
1804 for(1, env.times.size, { arg i;
1805 times[i] = times[i-1] + env.times[i-1];
1807 maxTime = maxTime ? times.last;
1808 minTime = minTime ? 0;
1809 levels = env.levels;
1810 minValue = minValue ? levels.minItem;
1811 maxValue = maxValue ? levels.maxItem;
1813 levels = levels.linlin(minValue, maxValue, 0, 1);
1814 times = times.linlin(minTime, maxTime, 0, 1);
1816 this.value_([times.asFloat, levels.asFloat]);
1817 this.curves_(env.curves);
1821 editEnv { arg env, minValue, maxValue, duration;
1822 var vals, levels, times, lastTime = 0;
1824 levels = vals[0].linlin(0, 1, minValue, maxValue);
1825 times = vals[1].collect { |it|
1827 out = it - lastTime;
1832 env.levels_(levels);
1833 env.curves_(this.curves);
1836 asEnv { arg env, minValue, maxValue, duration;
1837 var vals, levels, times, lastTime = 0;
1839 levels = vals[0].linlin(0, 1, minValue, maxValue);
1840 times = vals[1].collect { |it|
1842 out = it - lastTime;
1847 env.levels_(levels);
1848 env.curves_(this.curves);
1849 ^Env(levels, times, this.curves);
1852 *paletteExample { arg parent, bounds;
1853 ^this.new(parent, bounds).setEnv(Env([0.1, 0.3, 0.4, 0.01], [0.3, 1, 3]));
1857 this.setProperty(\setCurves, arr);
1861 // this.debug([\setCurves, arr]);
1862 this.setProperty(\setCurve, arr);
1865 shapeNumber { arg shapeName;
1867 shape = Env.shapeNames.at(shapeName);
1868 if (shape.notNil) { ^shape } {^5};
1871 connect { arg from, aconnections;
1872 this.setProperty(\connect, [from, aconnections.asFloat]);
1875 select { arg index; //this means no refresh;
1876 this.setProperty(\setIndex, index);
1878 selectIndex { arg index; //this means that the view will be refreshed
1879 this.setProperty(\selectedIndex, index);
1881 x { //returns selected x
1882 ^this.getProperty(\x);
1885 ^this.getProperty(\y);
1888 this.setProperty(\x, ax);
1891 this.setProperty(\y, ay);
1894 ^this.getProperty(\selectedIndex)
1897 ^this.getProperty(\lastIndex)
1900 setEditable { arg index, boolean;
1901 this.setProperty(\editable, [index, boolean]);
1904 editable_ { arg boolean;
1905 this.setEditable(-1, boolean);
1908 selectionColor_ { arg acolor;
1909 this.setProperty(\selectionColor, acolor)
1914 defaultReceiveDrag {
1915 if(currentDrag.isString, {
1917 items = items.insert(this.lastIndex + 1, currentDrag);
1918 this.strings_(items);
1920 this.value_(currentDrag);
1924 addValue { arg xval, yval;
1925 var arr, arrx, arry, aindx;
1930 if(val>xval and: aindx.isNil) {
1934 // this.debug(aindx);
1935 arrx = arrx.insert(aindx , xval);
1936 arry = arry.insert(aindx , yval);
1937 this.value_([arrx, arry]);
1940 fixedSelection_ { arg bool;
1941 fixedSelection = bool;
1942 this.setProperty(\setFixedSelection, bool);
1946 //including keydown by Heiko:
1947 // bug fixed in SCRangeSlider-receiveDrag
1948 // bug fixed in SCView-getPropertyList
1949 // allowing children in SCContainerView and parent in SCView to be accessed
1950 // globalKeyDownAction as classvar for all Views
1951 // KeyDownAction for all Views
1952 // bug fixed in SCNumberBox-defaultKeyDownAction
1953 // passing keydown up the tree
1954 // consuming keydown in function
1956 // and SCMultiSlider by jan t.
1957 // added customizable drag handlers, cx