Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / SCClassLibrary / Common / GUI / Base / EZKnob.sc
blobf17b374080512e021dd28bfb251e9ae2f6c6db11
1 EZKnob : EZGui {
3         classvar <>compactRatio=0.87;
5         var <knobView, <numberView, <unitView, <>controlSpec,
6                   popUp=false, knobSize,unitWidth, gap;
7         var <>round = 0.001;
9         *new { arg parent, bounds, label, controlSpec, action, initVal,
10                         initAction=false, labelWidth=60, knobSize,
11                         unitWidth=0, labelHeight=20,  layout=\vert, gap, margin;
13                 ^super.new.init(parent, bounds, label, controlSpec, action,
14                         initVal, initAction, labelWidth, knobSize,
15                                 unitWidth, labelHeight, layout, gap, margin)
16         }
18         init { arg parentView, bounds, label, argControlSpec, argAction, initVal,
19                         initAction, labelWidth, argKnobSize,argUnitWidth,
20                         labelHeight, argLayout, argGap, argMargin;
22                 var labelBounds, numBounds, unitBounds,knobBounds;
23                 var numberStep;
25                 // Set Margin and Gap
26                 this.prMakeMarginGap(parentView, argMargin, argGap);
28                 unitWidth = argUnitWidth;
29                 layout=argLayout;
30                 bounds.isNil.if{bounds = 50@90};
32                 knobSize = argKnobSize ;
34                 // if no parent, then pop up window
35                 # view,bounds = this.prMakeView( parentView,bounds);
38                 labelSize=labelWidth@labelHeight;
40                 // calculate bounds of all subviews
41                 # labelBounds,numBounds,knobBounds, unitBounds
42                                 = this.prSubViewBounds(innerBounds, label.notNil, unitWidth>0);
44                 // instert the views
45                 label.notNil.if{ //only add a label if desired
46                         labelView = GUI.staticText.new(view, labelBounds);
47                         labelView.string = label;
48                 };
50                 (unitWidth>0).if{ //only add a unitLabel if desired
51                         unitView = GUI.staticText.new(view, unitBounds);
52                 };
54                 knobView = GUI.knob.new(view, knobBounds);
55                 numberView = GUI.numberBox.new(view, numBounds);
57                 // set view parameters and actions
58                 controlSpec = argControlSpec.asSpec;
59                 (unitWidth>0).if{unitView.string = " "++controlSpec.units.asString};
60                 initVal = initVal ? controlSpec.default;
61                 action = argAction;
63                 numberStep = controlSpec.step;
64                 if (numberStep == 0) {
65                         numberStep = controlSpec.guessNumberStep
66                 }{
67                         // controlSpec wants a step, so zooming in with alt is disabled.
68                         numberView.alt_scale = 1.0;
69                         knobView.alt_scale = 1.0;
70                 };
71                 numberView.step = numberStep;
72                 numberView.scroll_step = numberStep;
75                 if((controlSpec.minval + controlSpec.maxval)==0){knobView.centered=true};
77                 knobView.action = {
78                         this.valueAction_(controlSpec.map(knobView.value));
79                 };
81                 if (controlSpec.step != 0) {
82                         knobView.step = (controlSpec.step / (controlSpec.maxval - controlSpec.minval));
83                 };
85                 knobView.receiveDragHandler = { arg slider;
86                         slider.valueAction = controlSpec.unmap(GUI.view.currentDrag);
87                 };
89                 knobView.beginDragAction = { arg slider;
90                         controlSpec.map(slider.value)
91                 };
93                 numberView.action = { this.valueAction_(numberView.value) };
95                 if (initAction) {
96                         this.valueAction_(initVal);
97                 }{
98                         this.value_(initVal);
99                 };
101                 this.prSetViewParams;
102         }
103                 // just set, no action
104         value_ { arg val;
105                 value = controlSpec.constrain(val);
106                 numberView.value = value.round(round);
107                 knobView.value = controlSpec.unmap(value);
108         }
109                 // set and do action
110         valueAction_ { arg val;
111                 this.value_(val);
112                 this.doAction;
113         }
115         doAction { action.value(this) }
117         set { arg label, spec, argAction, initVal, initAction = false;
118                 labelView.notNil.if { labelView.string = label.asString };
119                 spec.notNil.if { controlSpec = spec.asSpec };
120                 argAction.notNil.if { action = argAction };
121                 initVal = initVal ? value ? controlSpec.default;
123                 if (initAction) {
124                         this.valueAction_(initVal);
125                 }{
126                         this.value_(initVal);
127                 };
128         }
130         centered_ { arg bool; knobView.centered_(bool) }
132         centered{ ^knobView.centered }
135         setColors{arg stringBackground,stringColor,numBackground,
136                 numStringColor,numNormalColor,numTypingColor,knobColors,background;
138                         stringBackground.notNil.if{
139                                 labelView.notNil.if{labelView.background_(stringBackground)};
140                                 unitView.notNil.if{unitView.background_(stringBackground)};};
141                         stringColor.notNil.if{
142                                 labelView.notNil.if{labelView.stringColor_(stringColor)};
143                                 unitView.notNil.if{unitView.stringColor_(stringColor)};};
144                         numBackground.notNil.if{
145                                 numberView.background_(numBackground);};
146                         numNormalColor.notNil.if{
147                                 numberView.normalColor_(numNormalColor);};
148                         numTypingColor.notNil.if{
149                                 numberView.typingColor_(numTypingColor);};
150                         numStringColor.notNil.if{
151                                 numberView.stringColor_(numStringColor);};
152                         knobColors.notNil.if{
153                                 knobView.color_(knobColors);};
154                         background.notNil.if{
155                                 view.background=background;};
156                         numberView.refresh;
157                         knobView.refresh;
158         }
160         font_{ arg font;
162                         labelView.notNil.if{labelView.font=font};
163                         unitView.notNil.if{unitView.font=font};
164                         numberView.font=font;
165         }
167         ///////Private methods ///////
169         prSetViewParams{ // sets resize and alignment for different layouts
171                 switch (layout,
172                 \line2, {
173                         labelView.notNil.if{
174                                 labelView.resize_(5);
175                                 unitView.notNil.if{unitView.resize_(9)};
176                                 numberView.resize_(8);
177                                 }{
178                                 unitView.notNil.if{
179                                         unitView.resize_(6);
180                                         numberView.resize_(5);
181                                         }{
182                                         numberView.resize_(5);
183                                         };
184                                 };
185                         knobView.resize_(9);
186                         popUp.if{view.resize_(2)};
187                 },
188                 \vert, {
189                         labelView.notNil.if{labelView.resize_(2)};
190                         unitView.notNil.if{unitView.resize_(6)};
191                         numberView.resize_(5);
192                         popUp.if{view.resize_(2)};
193                 },
194                 \vert2, {
195                         labelView.notNil.if{labelView.resize_(2).align_(\center)};
196                         unitView.notNil.if{unitView.resize_(6)};
197                         numberView.resize_(5);
198                         popUp.if{view.resize_(2)};
199                 },
200                 \horz, {
201                         labelView.notNil.if{labelView.resize_(4).align_(\right)};
202                         unitView.notNil.if{unitView.resize_(6)};
203                         numberView.resize_(5);
204                         knobView.resize_(9);
205                         popUp.if{view.resize_(2)};
206                 });
208         }
210         prSubViewBounds{arg rect, hasLabel, hasUnit;  // calculate subview bounds
211                 var numBounds,labelBounds,knobBounds, unitBounds,knobHeight, numHeight;
212                 var gap1, gap2, gap3, tmp, labelH, unitH;
213                 gap1 = gap.copy;
214                 gap2 = gap.copy;
215                 gap3 = gap.copy;
216                 (rect.height<= (labelSize.y*2)).if{labelSize.y=rect.height/2};
218                 numHeight=labelSize.y;
220                 switch (layout,
221                          \line2, {
222                                 knobSize.isNil.if{knobSize=( ((rect.height/compactRatio)-margin.x)@(rect.height))};
223                                 knobSize=(knobSize.x-margin.x)@(knobSize.y.min(rect.height));
224                                 hasUnit.not.if{ gap2 = 0@0; unitWidth = 0};
225                                 labelBounds = Rect(0,0,rect.width-knobSize.x-gap3.x,labelSize.y); //to left
226                                 hasLabel.if{
227                                         unitBounds = Rect(labelBounds.width-unitWidth,labelSize.y+gap1.y,
228                                                 unitWidth, rect.height-labelSize.y-gap1.y);
230                                         numBounds = Rect(0,labelSize.y+gap1.y,
231                                                 labelBounds.width-gap2.x-unitBounds.width,rect.height-labelSize.y-gap1.y);
233                                 }{
234                                         unitBounds = Rect(labelBounds.width-unitWidth,0,
235                                                         unitWidth, rect.height);
237                                         numBounds = Rect(0,0,
238                                                 labelBounds.width-gap2.x-unitBounds.width,rect.height);
240                                 };
241                                 knobBounds=knobSize.asRect.moveTo(rect.width-knobSize.x,0);
242                         },
243                          \horz, {
244                                 knobSize.isNil.if{knobSize=( ((rect.height/compactRatio)-margin.x)@(rect.height))};
245                                 knobSize=(knobSize.x-margin.x)@(knobSize.y.min(rect.height));
246                                 knobBounds=knobSize.asRect.moveTo(rect.width-knobSize.x,0);
247                                 hasUnit.not.if{ gap2 = 0@0; unitWidth = 0};
248                                 hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0};
249                                 labelBounds = (labelSize.x@rect.height).asRect;
250                                 unitBounds = (unitWidth@rect.height).asRect
251                                         .moveTo(rect.width-knobBounds.width-gap2.x-unitWidth,0);
252                                 numBounds = Rect.newSides(labelSize.x+gap1.x,0,unitBounds.left-gap2.x,rect.height);
253                          },
254                          \vert , {
255                                 hasUnit.not.if{ gap3 = 0@0; unitWidth = 0};
256                                 hasLabel.not.if{ gap1 = 0@0; labelSize.y = 0};
258                                 knobSize.isNil.if{
259                                         knobSize=( ((rect.height-labelSize.y-numHeight-gap1.y-gap2.y)/compactRatio)
260                                                 @(rect.height-labelSize.y-numHeight-gap1.y-gap2.y))
261                                 };
262                                 knobSize=((knobSize.x).min(rect.width))
263                                         @(knobSize.y.min(rect.height-labelSize.y-numHeight-gap1.y-gap2.y));
265                                 labelBounds = (rect.width@labelSize.y).asRect;
266                                 knobBounds=knobSize.asRect.moveTo(0,labelSize.y+gap1.y);
268                                 numBounds = Rect(0,rect.height-numHeight,rect.width-unitWidth-gap3.x, numHeight);
270                                 unitBounds = Rect(rect.width-unitWidth,rect.height-numHeight,unitWidth,numHeight);
272                          },
273                          \vert2 , {
274                                 hasUnit.not.if{ gap3 = 0@0; unitWidth = 0};
275                                 hasLabel.not.if{ gap1 = 0@0; labelSize.y = 0};
277                                 knobSize.isNil.if{
278                                         knobSize=( ((rect.height-labelSize.y-numHeight-gap1.y-gap2.y)/compactRatio)
279                                                 @(rect.height-labelSize.y-numHeight-gap1.y-gap2.y))
280                                 };
281                                 knobSize=((knobSize.x).min(rect.width))
282                                         @(knobSize.y.min(rect.height-labelSize.y-numHeight-gap1.y-gap2.y));
285                                 labelBounds = (rect.width@labelSize.y).asRect;
286                                 knobBounds=knobSize.asRect.moveTo(0,labelSize.y+gap1.y);
287                                 knobBounds=knobBounds.moveBy((rect.width-knobBounds.width)/2,0);
288                                 numBounds = Rect(0,rect.height-numHeight,rect.width-unitWidth-gap3.x, numHeight);
290                                 unitBounds = Rect(rect.width-unitWidth,rect.height-numHeight,unitWidth,numHeight);
292                          }
293                 );
294                 ((knobBounds.height<0)||(knobBounds.width<0)).if{knobBounds=knobBounds.height_(0).width_(0)};
296                 ^[labelBounds, numBounds, knobBounds, unitBounds].collect{arg v; v.moveBy(margin.x,margin.y)}
297         }