Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / SCClassLibrary / Common / GUI / Base / EZSlider.sc
blobdad7c5b97b991c5da41c8928272a04a9798735ae
1 EZSlider : EZGui {
3         var <sliderView, <numberView, <unitView, <>controlSpec,
4                   popUp=false, numSize,numberWidth,unitWidth, gap;
5         var <>round = 0.001;
7         *new { arg parent, bounds, label, controlSpec, action, initVal,
8                         initAction=false, labelWidth=60, numberWidth=45,
9                         unitWidth=0, labelHeight=20,  layout=\horz, gap, margin;
11                 ^super.new.init(parent, bounds, label, controlSpec, action,
12                         initVal, initAction, labelWidth, numberWidth,
13                                 unitWidth, labelHeight, layout, gap, margin)
14         }
16         init { arg parentView, bounds, label, argControlSpec, argAction, initVal,
17                         initAction, labelWidth, argNumberWidth,argUnitWidth,
18                         labelHeight, argLayout, argGap, argMargin;
20                 var labelBounds, numBounds, unitBounds,sliderBounds;
21                 var numberStep;
23                 // Set Margin and Gap
24                 this.prMakeMarginGap(parentView, argMargin, argGap);
26                 unitWidth = argUnitWidth;
27                 numberWidth = argNumberWidth;
28                 layout=argLayout;
29                 bounds.isNil.if{bounds = 350@20};
32                 // if no parent, then pop up window
33                 # view,bounds = this.prMakeView( parentView,bounds);
36                 labelSize=labelWidth@labelHeight;
37                 numSize = numberWidth@labelHeight;
39                 // calculate bounds of all subviews
40                 # labelBounds,numBounds,sliderBounds, unitBounds
41                                 = this.prSubViewBounds(innerBounds, label.notNil, unitWidth>0);
43                 // instert the views
44                 label.notNil.if{ //only add a label if desired
45                         labelView = GUI.staticText.new(view, labelBounds);
46                         labelView.string = label;
47                 };
49                 (unitWidth>0).if{ //only add a unitLabel if desired
50                         unitView = GUI.staticText.new(view, unitBounds);
51                 };
53                 sliderView = GUI.slider.new(view, sliderBounds);
54                 numberView = GUI.numberBox.new(view, numBounds);
56                 // set view parameters and actions
58                 controlSpec = argControlSpec.asSpec;
59                 controlSpec.addDependant(this);
60                 this.onClose = { controlSpec.removeDependant(this) };
61                 (unitWidth>0).if{unitView.string = " "++controlSpec.units.asString};
62                 initVal = initVal ? controlSpec.default;
63                 action = argAction;
65                 sliderView.action = {
66                         this.valueAction_(controlSpec.map(sliderView.value));
67                 };
69                 sliderView.receiveDragHandler = { arg slider;
70                         slider.valueAction = controlSpec.unmap(GUI.view.currentDrag);
71                 };
73                 sliderView.beginDragAction = { arg slider;
74                         controlSpec.map(slider.value)
75                 };
77                 numberView.action = { this.valueAction_(numberView.value) };
79                 numberStep = controlSpec.step;
80                 if (numberStep == 0) {
81                         numberStep = controlSpec.guessNumberStep
82                 }{
83                         // controlSpec wants a step, so zooming in with alt is disabled.
84                         numberView.alt_scale = 1.0;
85                         sliderView.alt_scale = 1.0;
86                 };
88                 numberView.step = numberStep;
89                 numberView.scroll_step = numberStep;
90                 //numberView.scroll=true;
92                 if (initAction) {
93                         this.valueAction_(initVal);
94                 }{
95                         this.value_(initVal);
96                 };
97                 
98                 if (labelView.notNil) {
99                         labelView.mouseDownAction = {|view, x, y, modifiers, buttonNumber, clickCount|
100                                 if(clickCount == 2, {this.editSpec});
101                         }
102                 };
103                 
104                 this.prSetViewParams;
106         }
108         value_ { arg val;
109                 value = controlSpec.constrain(val);
110                 numberView.value = value.round(round);
111                 sliderView.value = controlSpec.unmap(value);
112         }
114         valueAction_ { arg val;
115                 this.value_(val);
116                 this.doAction;
117         }
119         doAction { action.value(this) }
121         set { arg label, spec, argAction, initVal, initAction = false;
122                 labelView.notNil.if { labelView.string = label.asString };
123                 spec.notNil.if { controlSpec = spec.asSpec };
124                 argAction.notNil.if { action = argAction };
126                 initVal = initVal ? value ? controlSpec.default;
128                 if (initAction) {
129                         this.valueAction_(initVal);
130                 }{
131                         this.value_(initVal);
132                 };
133         }
136         setColors{arg stringBackground,stringColor,sliderBackground,numBackground,
137                 numStringColor,numNormalColor,numTypingColor,knobColor,background;
139                         stringBackground.notNil.if{
140                                 labelView.notNil.if{labelView.background_(stringBackground)};
141                                 unitView.notNil.if{unitView.background_(stringBackground)};};
142                         stringColor.notNil.if{
143                                 labelView.notNil.if{labelView.stringColor_(stringColor)};
144                                 unitView.notNil.if{unitView.stringColor_(stringColor)};};
145                         numBackground.notNil.if{
146                                 numberView.background_(numBackground);};
147                         numNormalColor.notNil.if{
148                                 numberView.normalColor_(numNormalColor);};
149                         numTypingColor.notNil.if{
150                                 numberView.typingColor_(numTypingColor);};
151                         numStringColor.notNil.if{
152                                 numberView.stringColor_(numStringColor);};
153                         sliderBackground.notNil.if{
154                                 sliderView.background_(sliderBackground);};
155                         knobColor.notNil.if{
156                                 sliderView.knobColor_(knobColor);};
157                         background.notNil.if{
158                                 view.background=background;};
159                         numberView.refresh;
160         }
162         font_{ arg font;
164                         labelView.notNil.if{labelView.font=font};
165                         unitView.notNil.if{unitView.font=font};
166                         numberView.font=font;
167         }
169         ///////Private methods ///////
171         prSetViewParams{ // sets resize and alignment for different layouts
173                 switch (layout,
174                 \line2, {
175                         labelView.notNil.if{
176                                 labelView.resize_(2);
177                                 unitView.notNil.if{unitView.resize_(3)};
178                                 numberView.resize_(3);
179                                 }{
180                                 unitView.notNil.if{
181                                         unitView.resize_(2);
182                                         numberView.resize_(1);
183                                         }{
184                                         numberView.resize_(2);
185                                         };
186                                 };
187                         sliderView.resize_(5);
188                         popUp.if{view.resize_(2)};
189                 },
190                 \vert, {
191                         labelView.notNil.if{labelView.resize_(2)};
192                         unitView.notNil.if{unitView.resize_(8)};
193                         numberView.resize_(8);
194                         sliderView.resize_(5);
195                         popUp.if{view.resize_(4)};
196                 },
197                 \horz, {
198                         labelView.notNil.if{labelView.resize_(4).align_(\right)};
199                         unitView.notNil.if{unitView.resize_(6)};
200                         numberView.resize_(6);
201                         sliderView.resize_(5);
202                         popUp.if{view.resize_(2)};
203                 });
205         }
207         prSubViewBounds{arg rect, hasLabel, hasUnit;  // calculate subview bounds
208                 var numBounds,labelBounds,sliderBounds, unitBounds;
209                 var gap1, gap2, gap3, tmp, labelH, unitH;
210                 gap1 = gap.copy;
211                 gap2 = gap.copy;
212                 gap3 = gap.copy;
213                 labelH=labelSize.y;//  needed for \vert
214                 unitH=labelSize.y; //  needed for \vert
215                 hasUnit.not.if{ gap3 = 0@0; unitWidth = 0};
217                 switch (layout,
218                         \line2, {
220                                 hasLabel.if{ // with label
221                                         unitBounds = (unitWidth@labelSize.y)
222                                                 .asRect.left_(rect.width-unitWidth);// view to right
223                                         numBounds = (numSize.x@labelSize.y)
224                                                 .asRect.left_(rect.width-unitBounds.width-numberWidth-gap3.x); // view to right
225                                         labelBounds = (labelSize.x@labelSize.y)
226                                                 .asRect.width_(numBounds.left-gap2.x); //adjust width
227                                 }{ // no label
228                                 labelBounds = (0@labelSize.y).asRect; //just a dummy
229                                 numBounds = (numberWidth@labelSize.y).asRect; //view to left
230                                 (unitWidth>0).if{
231                                         unitBounds = Rect (numBounds.width+gap3.x, 0,
232                                                 rect.width-numBounds.width-gap3.x,labelSize.y); //adjust to fit
233                                                 }{
234                                         unitBounds = Rect (0, 0,0,0); //no unitView
235                                                 numBounds = (rect.width@labelSize.y).asRect; //view to left
236                                                 };
238                                 };
239                                 sliderBounds = Rect( //adjust to fit
240                                                 0,
241                                                 labelSize.y+gap1.y,
242                                                 rect.width,
243                                                 rect.height-numSize.y-gap1.y;
244                                                 );
245                                 },
247                          \vert, {
248                                 hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0 ;};
249                                 hasLabel.not.if{labelH=0};
250                                 labelBounds = (rect.width@labelH).asRect; // to top
251                                 hasUnit.not.if{unitH=0};
252                                 unitBounds = (rect.width@unitH)
253                                         .asRect.top_(rect.height-labelSize.y); // to bottom
254                                 numBounds = (rect.width@labelSize.y)
255                                         .asRect.top_(rect.height-unitBounds.height-numSize.y-gap3.y); // to bottom
257                                 sliderBounds = Rect( //adjust to fit
258                                         0,
259                                         labelBounds.height+gap1.y,
260                                         rect.width,
261                                         rect.height - labelBounds.height - unitBounds.height
262                                                         - numBounds.height - gap1.y - gap2.y - gap3.y
263                                         );
264                                 },
266                          \horz, {
267                                 hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0 ;};
268                                 labelSize.y = rect.height;
269                                 labelBounds = (labelSize.x@labelSize.y).asRect; //to left
270                                 unitBounds = (unitWidth@labelSize.y).asRect.left_(rect.width-unitWidth); // to right
271                                 numBounds = (numSize.x@labelSize.y).asRect
272                                         .left_(rect.width-unitBounds.width-numSize.x-gap3.x);// to right
273                                 sliderBounds  =  Rect( // adjust to fit
274                                         labelBounds.width+gap1.x,
275                                         0,
276                                         rect.width - labelBounds.width - unitBounds.width
277                                                         - numBounds.width - gap1.x - gap2.x - gap3.x,
278                                         labelBounds.height
279                                         );
280                 });
283                 ^[labelBounds, numBounds, sliderBounds, unitBounds].collect{arg v; v.moveBy(margin.x,margin.y)}
284         }
285         
286         update {arg changer, what ...moreArgs;
287                 var oldValue;
288                 if(changer === controlSpec, {
289                         oldValue = this.value;
290                         this.value = oldValue;
291                         if(this.value != oldValue, { this.doAction });
292                 });
293         }
294         
295         editSpec {
296                 var ezspec;
297                 [labelView, sliderView, numberView, unitView].do({|view|
298                         view.notNil.if({ view.enabled_(false).visible_(false)});
299                 });
300                 ezspec = EZControlSpecEditor(view, view.bounds.moveTo(0,0), controlSpec: controlSpec, layout: layout);
301                 ezspec.labelView.mouseDownAction = {|view, x, y, modifiers, buttonNumber, clickCount|
302                         if(clickCount == 2, {
303                                 ezspec.remove;
304                                 [labelView, sliderView, numberView, unitView].do({|view|
305                                         view.notNil.if({ view.enabled_(true).visible_(true)});
306                                 });
307                         });
308                 };                      
309         }