class library: SynthDef - lazy implementation of removeUGen
[supercollider.git] / HelpSource / Classes / EZSlider.schelp
blob3b83b1b885cd7f266e8d050eb4c861dad4020291
1 class:: EZSlider
2 summary:: Wrapper class for label, slider, number box
3 categories:: GUI>EZ-GUI
4 related:: Classes/Slider, Classes/NumberBox, Classes/StaticText, Classes/CompositeView, Classes/EZGui
6 description::
7 EZSlider is wrapper class which creates an (optional) link::Classes/StaticText::, and a link::Classes/Slider:: plus a link::Classes/NumberBox::. If the parent is code::nil::, then EZSlider will create its own window. See link::Classes/EZGui:: more options.
9 subsection:: Scrolling and Arrow Keys
10 EZSlider's number box scrolls by default, using the step size of the link::Classes/ControlSpec::. If the controlSpec's step is set to 0, or is not set, then the the stepping and scrolling will be guessed according to the code::minval:: and code::maxval:: values of the spec on creation of the view.  Unlike the step variable of a regular link::Classes/NumberBox::, code::controlSpec.step:: is also the smallest possible increment for the link::Classes/NumberBox::. By default, the shift-key modifier will allow you to step by 100x code::controlSpec.step::, while the ctrl-key will give you 10x code::controlSpec.step::.  Since the alt-key would give you 0.1 of the minimum step, it is disabled by default, but you can change that by setting code::numberView.alt_step:: to any value you like. Accordingly you can customize the other modifiers to fit your needs. See link::Classes/NumberBox:: and link::Classes/Slider::. This also effects the arrow keys for the slider.
12 classmethods::
14 subsection:: Creation / Class Methods
16 method:: new
17 argument:: parent
18 The parent view or window. If the parent is code::nil::, then EZSlider will create its own link::Classes/Window::, and place it conveniently on the screen if the bounds are a link::Classes/Point::. If the bounds are a link::Classes/Rect::, then the link::Classes/Rect:: determines the window bounds.
20 argument:: bounds
21 An instance of link::Classes/Rect:: or link::Classes/Point::. Default value is code::160@20::.
23 argument:: label
24 The label. Default value is code::nil::. If code::nil::, then no link::Classes/StaticText:: is created.
26 argument:: controlSpec
27 The link::Classes/ControlSpec:: for scaling the value.
29 argument:: action
30 A link::Classes/Function:: called when the value changes. The function is passed the EZSlider instance as its argument.
32 argument:: initVal
33 The value to initialize the slider and number box with. If code::nil::, then it uses the link::Classes/ControlSpec::'s default value.
35 argument:: initAction
36 A link::Classes/Boolean:: indicating whether the action function should be called when setting the initial value. The default is false.
38 argument:: labelWidth
39 Number of pixels width for the label. The default is 60.
41 argument:: numberWidth
42 Number of pixels width for the number box. The default is 45.
44 argument:: unitWidth
45 Number of pixels width for the unit label. The default is 0. If 0, then no unitLabel is created.
47 argument:: labelHeight
48 The default is 20;
50 argument:: layout
51 code::\vert::, code::\line2::, or code::\horz::. The default is code::\horz::.
53 argument:: gap
54 A link::Classes/Point::. By default, the view tries to get its parent's gap, otherwise it defaults to code::2@2::. Setting it overrides these.
56 argument:: margin
57 A link::Classes/Point::. This will inset the bounds occupied  by the subviews of view.
59 discussion::
60 code::
62 w = Window.new.front;
63 g = EZSlider( w,         // parent
64               390@20,    // bounds
65               " test ",  // label
66               \freq,     // controlSpec
67               { |ez| (ez.value.asString ++" is the value of " ++ ez).postln } // action
69 g.setColors(Color.grey,Color.white)
72 // Simplest version, no parent view, so a window is created
74         g = EZSlider(label:" test ");
75         g.action_({ |ez| (ez.value.asString ++" is the value of " ++ ez).postln });
78 The contained views can be accessed via the EZSlider instance variables: code::labelView::, code::sliderView::, code::numberView::.
80 instancemethods::
82 subsection:: Accessing Instance and Class Variables
84 method:: numberView
85 Returns the numberView.
87 method:: action
88 A link::Classes/Function:: or link::Classes/FunctionList:: to be evaluated when the value changes. The first argument will be the EZSlider.
90 method:: value
91 The value of the slider.
93 method:: round
94 Rounds the values in the number box.
96 method:: controlSpec
97 An instance of ControlSpec for scaling the values.
99 method:: value
100 Gets/sets the list/menu to the index at value. Does not perform the action.
101 argument:: val
102 An link::Classes/Integer::.
104 method:: valueAction
105 Sets the value and performs the action at the index value and the global action.
106 argument:: val
107 An link::Classes/Integer::.
109 method:: doAction
110 Performs the action at the current index and the global action.
112 method:: set
113 Set the args after creation. You can only set the label if it was not nil from the beginning.
114 argument:: label
115 argument:: spec
116 argument:: argAction
117 argument:: initVal
118 argument:: initAction
120 method:: visible
121 Sets/gets it the component views are visible.
122 argument:: bool
123 An instance of link::Classes/Boolean::. Default is code::true::.
125 subsection:: Changing Appearance
127 method:: setColors
128 argument:: stringBackground
129 An instance of link::Classes/Color::. The code::background:: of the label and unit views.
130 argument:: stringColor
131 An instance of link::Classes/Color::. The code::stringColor:: of the label and unit views.
132 argument:: sliderBackground
133 An instance of link::Classes/Color::. The slider code::background::.
134 argument:: numBackground
135 An instance of link::Classes/Color::. The code::numColor:: of the number view.
136 argument:: numStringColor
137 An instance of link::Classes/Color::. The code::stringColor:: of the number view.
138 argument:: numNormalColor
139 An instance of link::Classes/Color::. The code::normalColor:: of the number view.
140 argument:: numTypingColor
141 An instance of link::Classes/Color::. The code::typingColor:: of the number view.
142 argument:: knobColor
143 An instance of link::Classes/Color::. The code::knobColor:: of the knob view.
144 argument:: background
145 An instance of link::Classes/Color::. The code::background:: of the enclosing view.
147 method:: font
148 Set the Font used by all the views.
149 argument:: font
150 An instance of link::Classes/Font::.
152 examples::
153 code::
154 (       // basic use
155         w=Window.new.front;
156         g=EZSlider(w, 400@16," test  ", \freq,unitWidth:30, numberWidth:60,layout:\horz);
157         g.setColors(Color.grey,Color.white);
159 g.view.enabled=false
160 // lots of sliders on on view
162 w=Window.new.front;
163 w.view.decorator=FlowLayout(w.view.bounds);
164 w.view.decorator.gap=2@2;
166 20.do{
167         EZSlider(w, 392@16," Freq ", \freq,unitWidth:30,initVal:6000.rand, numberWidth:60,layout:\horz)
168         .setColors(Color.grey,Color.white)
169         .font_(Font("Helvetica",11));
174 Window.closeAll  // use this to close all the windows
176 /////////////////////////////////////////////////////////////////
177 ////////// click these parentheses to see all features and layouts
181 m=nil;
182 //m=2@2;                // uncomment this for margin
184 /////////////////
185 /// Layout \horz
187 (               // all features, small font
188                 g=EZSlider(nil, 400@14," freq  ", \freq,unitWidth:30, numberWidth:60,layout:\horz, margin: m);
189                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
190                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
191                 g.window.bounds = g.window.bounds.moveBy(-180,50);
192                 g.font_(Font("Helvetica",10));
195 (               // no unitView
196                 g=EZSlider(nil, 400@16," freq  ", \freq,unitWidth:0, numberWidth:60,layout:\horz, margin: m);
197                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
198                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
199                 g.window.bounds = g.window.bounds.moveBy(-180, -20);
201 (               // no label, so use window name as label
202                 g=EZSlider(nil, 400@16, nil, \freq,unitWidth:0, numberWidth:60,layout:\horz, margin: m);
203                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
204                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
205                 g.window.bounds = g.window.bounds.moveBy(-180, -90);
206                 g.window.name="Freq";
209 /////////////////
210 /// Layout \line2
212 (               // all features
213                 g=EZSlider(nil, 300@42," freq  ", \freq,unitWidth:30, numberWidth:60,layout:\line2, margin: m);
214                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
215                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
216                 g.window.bounds = g.window.bounds.moveBy(-180,-160);
219 (               // no unitView, with label
220                 g=EZSlider(nil, 300@42," freq  ", \freq,unitWidth:0, numberWidth:60,layout:\line2, margin: m);
221                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
222                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
223                 g.window.bounds = g.window.bounds.moveBy(-180,-260);
226 (               // no label
227                 g=EZSlider(nil, 300@42,nil, \freq, unitWidth:30, numberWidth:60,layout:\line2, margin: m);
228                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
229                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
230                 g.window.bounds = g.window.bounds.moveBy(-180,-360);
231                 g.window.name="Freq";
234 (               // no lablel, so use window name as label
235                 g=EZSlider(nil, 150@42,nil, \freq,unitWidth:0, numberWidth:60,layout:\line2, margin: m);
236                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
237                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
238                 g.window.bounds = g.window.bounds.moveBy(-180,-460);
239                 g.window.name="Freq";
242 /////////////////
243 /// Layout \vert
245 (               // all features, small font
246                 g=EZSlider(nil, 45@300," Vol  ", \db.asSpec.step_(0.01),unitWidth:30, numberWidth:60,layout:\vert, margin: m);
247                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
248                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
249                 g.window.bounds = g.window.bounds.moveBy(250,50);
250                 g.font_(Font("Helvetica",10));
252 (               // no label, small font
253                 g=EZSlider(nil, 45@300, nil, \db.asSpec.step_(0.01),unitWidth:30, numberWidth:60,layout:\vert, margin: m);
254                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
255                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
256                 g.window.bounds = g.window.bounds.moveBy(310,50);
257                 g.font_(Font("Helvetica",10));
259 (               // no Units small font
260                 g=EZSlider(nil, 45@300, " Vol", \db.asSpec.step_(0.01),unitWidth:0, numberWidth:60,layout:\vert, margin: m);
261                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
262                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
263                 g.window.bounds = g.window.bounds.moveBy(370,50);
264                 g.font_(Font("Helvetica",10));
266 (               // no unitView, no Units small font
267                 g=EZSlider(nil, 45@300, nil, \db.asSpec.step_(0.01),unitWidth:0, numberWidth:60,layout:\vert, margin: m);
268                 g.setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey,
269                         Color.white, Color.yellow,nil,nil, Color.grey(0.7));
270                 g.window.bounds = g.window.bounds.moveBy(430,50);
271                 g.font_(Font("Helvetica",10));
279 ///////////////////////////////////////////////////////////////
280 ///////////////////////////////////////////////////////////////
283 // Sound example
285 // start server
286 s.waitForBoot({
288 var w, startButton, noteControl, cutoffControl, resonControl;
289 var balanceControl, ampControl;
290 var node, cmdPeriodFunc;
292 // define a synth
293 SynthDef("window-test", { arg note = 36, fc = 1000, rq = 0.25, bal=0, amp=0.4, gate = 1;
294                 var x;
295                 x = Mix.fill(4, {
296                         LFSaw.ar((note + {0.1.rand2}.dup).midicps, 0, 0.02)
297                 });
298                 x = RLPF.ar(x, fc, rq).softclip;
299                 x = RLPF.ar(x, fc, rq, amp).softclip;
300                 x = Balance2.ar(x[0], x[1], bal);
301                 x = x * EnvGen.kr(Env.cutoff, gate, doneAction: 2);
302                 Out.ar(0, x);
303         }, [0.1, 0.1, 0.1, 0.1, 0.1, 0]
304 ).add;
309 // make the window
310 w = Window("another control panel", Rect(20, 400, 440, 180));
311 w.front; // make window visible and front window.
312 w.view.decorator = FlowLayout(w.view.bounds);
313 w.view.decorator.gap=2@2;
315 // add a button to start and stop the sound.
316 startButton = Button(w, 75 @ 20);
317 startButton.states = [
318         ["Start", Color.black, Color.green(0.7)],
319         ["Stop", Color.white, Color.red(0.7)]
321 startButton.action = {|view|
322                 if (view.value == 1) {
323                         // start sound
324                         node = Synth( "window-test", [
325                                 "note", noteControl.value,
326                                 "fc", cutoffControl.value,
327                                 "rq", resonControl.value,
328                                 "bal", balanceControl.value,
329                                 "amp", ampControl.value.dbamp ]);
330                 } {
331                         // set gate to zero to cause envelope to release
332                         node.release; node = nil;
333                 };
336 // create controls for all parameters
337 w.view.decorator.nextLine;
338 noteControl = EZSlider(w, 430 @ 20, "Note ", ControlSpec(24, 60, \lin, 1, 36, \note),
339         {|ez| node.set( "note", ez.value )}, unitWidth:30)
340                 .setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);
342 w.view.decorator.nextLine;
343 cutoffControl = EZSlider(w, 430 @ 20, "Cutoff ", ControlSpec(200, 5000, \exp,0.01,1000,\Hz),
344         {|ez| node.set( "fc", ez.value )}, unitWidth:30)
345                 .setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);
347 w.view.decorator.nextLine;
348 resonControl = EZSlider(w, 430 @ 20, "Reson ", ControlSpec(0.1, 0.7,\lin,0.001,0.2,\rq),
349         {|ez| node.set( "rq", ez.value )}, unitWidth:30)
350                 .setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);
352 w.view.decorator.nextLine;
353 balanceControl = EZSlider(w, 430 @ 20, "Balance ", \bipolar,
354         {|ez| node.set( "bal", ez.value )},  unitWidth:30)
355                 .setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);
357 w.view.decorator.nextLine;
358 ampControl = EZSlider(w, 430 @ 20, "Amp ", \db,
359         {|ez| node.set( "amp", ez.value.dbamp )}, -6, unitWidth:30)
360                 .setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);
363 // set start button to zero upon a cmd-period
364 cmdPeriodFunc = { startButton.value = 0; };
365 CmdPeriod.add(cmdPeriodFunc);
367 // stop the sound when window closes and remove cmdPeriodFunc.
368 w.onClose = {
369         node.free; node = nil;
370         CmdPeriod.remove(cmdPeriodFunc);
378 // a variant of the above example so one can
379 // add new parameters and more views are created automatically
382 // start server
383 s.waitForBoot({
385 var w, startButton, sliders;
386 var node, cmdPeriodFunc;
387 var params, specs;
389 // define a synth
390 SynthDef("window-test", { arg note = 36, fc = 1000, rq = 0.25, bal = 0, amp=0.4, width=0, gate = 1;
391                 var x;
392                 x = Mix.fill(4, {
393                         VarSaw.ar((note + {0.1.rand2}.dup).midicps, 0, width, 0.02)
394                 });
395                 x = RLPF.ar(x, fc, rq).softclip;
396                 x = RLPF.ar(x, fc, rq, amp).softclip;
397                 x = Balance2.ar(x[0], x[1], bal);
398                 x = x * EnvGen.kr(Env.cutoff, gate, 5, doneAction: 2);
399                 Out.ar(0, x);
400         }, [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0]
401 ).add;
404 params = ["note", "fc", "rq", "bal", "amp", "width"];
405 specs = [
406         ControlSpec(24, 60, \lin, 1, 36, \note),
407         ControlSpec(200, 5000, \exp,0.01,1000,\Hz),
408         ControlSpec(0.1, 0.7,\lin,0.001,0.2,\rq),
409         ControlSpec(-1, 1, \lin, 0, 0, \pan),
410         ControlSpec(0.0001, 2, \exp, 0, 0.3, \vol), // db spec acts weird, so use self made one
411         ControlSpec(0, 1, \lin, 0, 0.3, \width),
414 // make the window
415 w = Window("another control panel", Rect(20, 400, 440, 180));
416 w.front; // make window visible and front window.
417 w.view.decorator = FlowLayout(w.view.bounds);
418 w.view.decorator.gap=2@2;
421 // add a button to start and stop the sound.
422 startButton = Button(w, 75 @ 20);
423 startButton.states = [
424         ["Start", Color.black, Color.green(0.7)],
425         ["Stop", Color.white, Color.red(0.7)]
427 startButton.action = {|view|
428                 var args;
429                 if (view.value == 1) {
430                         // start sound
431                         params.do { |param, i|
432                                 args = args.add(param);
433                                 args = args.add(sliders[i].value)
434                         };
435                         node = Synth("window-test", args.postcs);
436                 } {
437                         // set gate to zero to cause envelope to release
438                         node.release; node = nil;
439                 };
442 // create controls for all parameters
443 w.view.decorator.nextLine;
444 sliders = params.collect { |param, i|
445         EZSlider(w, 430 @ 20, param, specs[i], {|ez| node.set( param, ez.value )})
446                 .setColors(Color.grey,Color.white, Color.grey(0.7),Color.grey, Color.white, Color.yellow);
448 // set start button to zero upon a cmd-period
449 cmdPeriodFunc = { startButton.value = 0; };
450 CmdPeriod.add(cmdPeriodFunc);
452 // stop the sound when window closes and remove cmdPeriodFunc.
453 w.onClose = {
454         node.free; node = nil;
455         CmdPeriod.remove(cmdPeriodFunc);