deprecate SCViewHolder-layRight
[supercollider.git] / SCClassLibrary / Common / GUI / osx / scide_scapp / Base / SCKnob.sc
blobe0734c4cbf9cdb4eaf49201fb963677393f68d40
1 // blackrain at realizedsound dot net - 05/2006
2 //      fix key modidiers bug by Stephan Wittwer 08/2006 - thanks!
3 //      Knob updates only on value changes - 10/2006
4 //      GUI.cocoa changes - 04/2007
5 //
6 //      03.10.2008 - new implementation:
7 //              - Knob now is a subclass of SCViewHolder
8 //              - Relative origin
9 //
10 //      01.20.2009 - SCKnob
11 //              - a subclass of SCUserView again.
12 //              - isSquare option
15 SCKnob : SCUserView {
16         classvar <>defaultMode, <>isSquare=false, <>compactRatio=0.87;
17         var size, widthDiv2, center, aw8, aw12, aw14, hit;
18         var <>color, <value, prevValue, <>step, <>keystep, <>mode, <centered = false;
19         var <skin;
20         var <>shift_scale = 100.0, <>ctrl_scale = 10.0, <>alt_scale = 0.1;
22         *viewClass { ^SCUserView }
24         *initClass {
25                 var version;
27                 defaultMode='round';
29                 StartUp.add({
31                         GUI.skins.default.put('knob', (
32                                 default: (
33                                         scale:  Color.black.alpha_(0.3),
34                                         center: Color.blue(0.7, 0.5),
35                                         level:  Color.green(0.8, 0.8),
36                                         dial:   Color.black.alpha_(0.7),
37                                         defaultMode: 'round'
38                                 )
39                         ));
41                 });
42         }
44         init { arg argParent, argBounds;
46                 argBounds = this.calcConsts(argBounds);
48                 super.init(argParent, argBounds);
50                 value = 0.0;
51                 keystep = 0.01;
52                 step = 0.01;
53                 mode = defaultMode;
55                 skin = GUI.skins.default.knob.default;
57                 this.oldMethodsCompat(skin);
59                 this.receiveDragHandler = { this.valueAction_(SCView.currentDrag); };
60                 this.beginDragAction = { value.asFloat; };
61                 this.canReceiveDragHandler = { SCView.currentDrag.isNumber };
62         }
64         calcConsts { arg rect;
65                 if ( isSquare ) {
66                         rect = rect.asRect.height_( rect.asRect.width );
67                 }{
68                         rect = rect.asRect.height_( (rect.asRect.width * compactRatio).ceil );
69                 };
70                 size = rect.width;
71                 widthDiv2 = size * 0.5;
72                 aw8  = widthDiv2 - (0.08 * size);
73                 aw12 = widthDiv2 - (0.12 * size);
74                 aw14 = widthDiv2 - (0.14 * size);
75                 center = Point(widthDiv2, widthDiv2);
77                 ^rect
78         }
80         bounds_ { arg rect;
81                 rect = this.calcConsts(rect);
82                 super.bounds_(rect);
83         }
85         draw {
86                 var startAngle, arcAngle;
88                 color[2].set;
89                 SCPen.addAnnularWedge(
90                         center,
91                         aw8,
92                         widthDiv2,
93                         0.25pi,
94                         -1.5pi
95                 );
96                 SCPen.perform(\fill);
98                 if (centered.not, {
99                         startAngle = 0.75pi;
100                         arcAngle = 1.5pi * value;
101                 }, {
102                         startAngle = -0.5pi;
103                         arcAngle = 1.5pi * (value - 0.5);
104                 });
106                 color[1].set;
107                 SCPen.addAnnularWedge(
108                         center,
109                         aw12,
110                         widthDiv2,
111                         startAngle,
112                         arcAngle
113                 );
114                 SCPen.perform(\fill);
116                 color[0].set;
117                 SCPen.addWedge(center, aw14, 0, 2pi);
118                 SCPen.perform(\fill);
120                 color[3].set;
121                 SCPen.width = (0.08 * size);
122                 SCPen.moveTo(center);
123                 SCPen.lineTo(Polar.new(aw14, 0.75pi + (1.5pi * value)).asPoint + center);
124                 SCPen.stroke;
125         }
127         mouseDown { arg x, y, modifiers, buttonNumber, clickCount;
129                 hit =  x @ y;
131                 mouseDownAction.value(this, x, y, modifiers, buttonNumber, clickCount);
133                 this.mouseMove(x, y, modifiers);
135         }
137         mouseMove { arg x, y, modifiers;
138                 var mp, pt, angle, inc = 0;
141                 if (modifiers & 1048576 != 1048576) { // we are not dragging out - apple key
142                         case
143                                 { (mode == \vert) || (modifiers & 262144 == 262144) } { // Control
144                                         if ( hit.y > y, {
145                                                 inc = step;
146                                         }, {
147                                                 if ( hit.y < y, {
148                                                         inc = step.neg;
149                                                 });
150                                         });
151                                         value = (value + inc).clip(0.0, 1.0);
152                                         hit = Point(x,y);
153                                         if (prevValue != value) {
154                                                 action.value(this, x, y, modifiers);
155                                                 prevValue = value;
156                                                 this.refresh;
157                                         }
158                                 }
159                                 { (mode == \horiz) || (modifiers & 524288 == 524288) } { // Option
160                                         if ( hit.x > x, {
161                                                 inc = step.neg;
162                                         }, {
163                                                 if ( hit.x < x, {
164                                                         inc = step;
165                                                 });
166                                         });
167                                         value = (value + inc).clip(0.0, 1.0);
168                                         hit = Point(x,y);
169                                         if (prevValue != value) {
170                                                 action.value(this, x, y, modifiers);
171                                                 prevValue = value;
172                                                 this.refresh;
173                                         }
174                                 }
175                                 { mode == \round } {
176                                         pt = center - Point(x,y);
177                                         angle = Point(pt.y, pt.x.neg).theta;
178                                         if ((angle >= -0.80pi) and: { angle <= 0.80pi} , {
179                                                 value = [-0.75pi, 0.75pi].asSpec.unmap(angle);
180                                                 if (prevValue != value) {
181                                                         action.value(this, x, y, modifiers);
182                                                         prevValue = value;
183                                                         this.refresh;
184                                                 }
185                                         });
187                                 }
188                 };
190                 mouseMoveAction.value(this, x, y, modifiers);
191         }
193         getScale { |modifiers|
194                 ^case
195                         { modifiers & 131072 == 131072 } { shift_scale }
196                         { modifiers & 262144 == 262144 } { ctrl_scale }
197                         { modifiers & 524288 == 524288 } { alt_scale }
198                         { 1 };
199         }
201         defaultKeyDownAction { arg char, modifiers, unicode,keycode;
202                 var zoom = this.getScale(modifiers);
204                 // standard keydown
205                 if (char == $r, { this.valueAction = 1.0.rand; ^this });
206                 if (char == $n, { this.valueAction = 0.0; ^this });
207                 if (char == $x, { this.valueAction = 1.0; ^this });
208                 if (char == $c, { this.valueAction = 0.5; ^this });
210                 if (char == $[, { this.decrement(zoom); ^this });
211                 if (char == $], { this.increment(zoom); ^this });
212                 if (unicode == 16rF700, { this.increment(zoom); ^this });
213                 if (unicode == 16rF703, { this.increment(zoom); ^this });
214                 if (unicode == 16rF701, { this.decrement(zoom); ^this });
215                 if (unicode == 16rF702, { this.decrement(zoom); ^this });
216                 ^nil            // bubble if it's an invalid key
217         }
219         increment { |zoom=1| ^this.valueAction = (this.value + (keystep * zoom)).min(1) }
221         decrement { |zoom=1| ^this.valueAction = (this.value - (keystep * zoom)).max(0) }
223         value_ { arg val;
224                 value = val.clip(0.0, 1.0);
225                 this.refresh;
226         }
228         valueAction_ { arg val;
229                 value = val.clip(0.0, 1.0);
230                 action.value(this);
231                 this.refresh;
232         }
234         centered_ { arg bool;
235                 centered = bool;
236                 this.refresh;
237         }
239         skin_ { arg newskin;
240                 if ( newskin.notNil ) {
241                         skin = newskin;
242                         newskin.proto_( GUI.skins.default.knob.default );
243                         this.oldMethodsCompat;
244                         this.refresh;
245                 }{
246                         format("%: skin not found.", this.class).inform;
247                 };
248         }
249         oldMethodsCompat {
250                 color = [
251                         skin.center,
252                         skin.level,
253                         skin.scale,
254                         skin.dial
255                 ];
256                 defaultMode = skin.defaultMode;
257         }
259         *paletteExample{arg parent, bounds;
260                 ^this.new(parent, bounds.asRect.height@bounds.asRect.height);
261         }