CLASS:: Slider
summary:: A view consisting of a sliding handle.
categories:: GUI>Views

DESCRIPTION::

A view that allows setting a numerical value by means of moving a sliding handle. It can have horizontal or vertical orientation, meaning the direction in which the handle moves.




CLASSMETHODS::

PRIVATE:: key

METHOD:: new

	When a new Slider is created, its link::#-orientation:: is determined by the initial size: if it is wider than high, the orientation will be horizontal, otherwise it will be vertical.





INSTANCEMETHODS::



SUBSECTION:: Data

METHOD:: value
	Numerical value between 0 and 1, represented by the handle position within the groove.

	argument::
		A Float.

METHOD:: valueAction
	Sets link::#-value:: and triggers link::#-action::.

METHOD:: increment
	Increments the value by link::#-step:: multiplied by 'factor'.

	argument:: factor
		Any number.

METHOD:: decrement
	Decrements the value by link::#-step:: multiplied by 'factor'.

	argument:: factor
		Any number.




SUBSECTION:: Appearance

METHOD:: orientation
	The orientation of the Slider - the direction in which the handle moves. The default value depends on the size of the view when created.

	argument::
		One of the two Symbols: \horizontal or \vertical.

METHOD:: thumbSize
	The size of the handle - its width or height, depending on link::#-orientation::.

	argument::
		An Integer amount of pixels.

METHOD:: knobColor
	The color of the handle.

	argument::
		A Color.



SUBSECTION:: Interaction

METHOD:: step
	The amount by which the value will changed when link::#-increment:: or link::#-decrement:: is called, or when related keys are pressed.

	argument::
		A Float.

METHOD:: pixelStep
	The absolute amount by which the value would change if the handle moved by one pixel.

	returns::
		A Float.

METHOD:: shift_scale
	The factor by which link::#-step:: is multiplied when incrementing or decrementing the value by keyboard while the Shift key is pressed.

	argument::
		A Float.

METHOD:: ctrl_scale
	The factor by which link::#-step:: is multiplied when incrementing or decrementing the value by keyboard while the Ctrl key is pressed.

	argument::
		A Float.

METHOD:: alt_scale
	The factor by which link::#-step:: is multiplied when incrementing or decrementing the value by keyboard while the Alt key is pressed.

	argument::
		A Float.


SUBSECTION:: Actions

METHOD:: action
	The action object evaluated whenever the user moves the handle.

METHOD:: defaultKeyDownAction

	Implements the default effects of key presses as follows:

	table::
	## strong::Key::   || strong::Effect::
	## r               || valueAction_(1.0.rand)
	## n               || valueAction_(0)
	## x               || valueAction_(1)
	## c               || valueAction_(0.5)
	## ]               || increment
	## [               || decrement
	## up arrow        || increment
	## down arrow      || decrement
	## right arrow     || increment
	## left arrow      || decrement
	::



SUBSECTION:: Drag and drop

METHOD:: defaultGetDrag
	returns::
		The link::#-value::.

METHOD:: defaultCanReceiveDrag
	returns::
		True if the current drag data is a number.

METHOD:: defaultReceiveDrag
	Sets link::#-valueAction:: to the current drag data.



EXAMPLES::
subsection:: Show the slider value in a NumberBox
code::
(
w = Window.new.front;
c = NumberBox(w, Rect(20, 20, 150, 20));
a = Slider(w, Rect(20, 60, 150, 20))
	.action_({
		c.value_(a.value)
		});
a.action.value;
)

( // change the bounds to become vertical
w = Window.new.front;
c = NumberBox(w, Rect(20, 20, 150, 20));
a = Slider(w, Rect(200, 60, 20, 150))
	.action_({
		c.value_(a.value)
	});
a.action.value;
)
::

subsection:: Use a Spec to round and map the output range
code::
(
w = Window.new.front;
b = ControlSpec(-50, 50, \linear, 0.01); // min, max, mapping, step
c = StaticText(w, Rect(20, 20, 150, 20)).align_(\center).background_(Color.rand);
a = Slider(w, Rect(20, 50, 150, 20))
	.focusColor_(Color.red(alpha:0.2))
	.background_(Color.rand)
	.value_(0.5)
	.action_({
		c.string_(b.map(a.value).asString)
		// round the float so it will fit in the NumberBox
		});
a.action.value;
)
::

subsection:: Change the stepsize of the slider, selected via a PopUpMenu
code::
(
w = Window.new.front;
a = ["0", "0.0625", "0.125", "0.25", "0.5", "1"];
b = Slider(w, Rect(20, 100, 100, 20))
	.action_({
		c.value_(b.value)
		}).background_(Color.rand);
d = PopUpMenu(w, Rect(20, 60, 100, 20))
	.items_(a)
	.action_({
		b.step_((a.at(d.value)).asFloat);
	});
StaticText(w, Rect(130, 60, 100, 20)).string_("change step");
c = NumberBox(w, Rect(20, 20, 100, 20));
)
::

subsection:: Use the slider view to accept key actions
code::
( // select the slider, type something and watch the post window
w = Window.new;
c = Slider(w, Rect(0,0,100,30));
c.keyDownAction = { |view, char, modifiers, unicode, keycode|
	[char, modifiers, unicode, keycode].postln
};
w.front;
)
::

subsection:: Adding functionality to a view by the method addAction
This is useful for adding things to existing frameworks that have action functions already.
code::
(
w = Window.new("A Slider");
a = Slider.new(w, Rect(40, 10, 300, 30));
w.front
);

// now incrementally add some action to the slider
a.addAction({ |sl| sl.value.postln });
a.addAction({ |sl| w.view.background = Color.green(sl.value) });
a.addAction({ |sl| sl.background = Color.red(1 - sl.value) });

// adding and removing an action:
f = { |sl| "--------*******-------".postln; };
a.addAction(f);
a.removeAction(f);

// or remove all, of course
a.action = nil;
::

subsection:: Use Slider for triggering sounds
code::

	(
		s.waitForBoot({
			
			SynthDef(\pluck, { |out, freq=55|
				Out.ar(out,
					Pluck.ar(WhiteNoise.ar(0.06),
						EnvGen.kr(Env.perc(0,4), 1.0, doneAction: Done.freeSelf),
						freq.reciprocal,
						freq.reciprocal,
						10,
						coef:0.1)
				);
			}).add;


			w = Window.new("Hold arrow keys to trigger sound",
				Rect(300, Window.screenBounds.height - 300, 400, 100)).front;
			a = Slider(w, Rect(50, 20, 300, 40)).value_(0.5).step_(0.05).focus
			.action_({
				// trigger a synth with varying frequencies
				Synth(\pluck, [\freq, 55 + (1100 * a.value)]);
				w.view.background_(Gradient(Color.rand,Color.rand));
			})
		});

	)
::

subsection:: Change background color of Window
code::
(
w = Window("RGB fader", Rect(100, 500, 400, 400))
	.front;
f = { w.view.background_(Color.new(r.value, g.value, b.value, 1)) };
r = Slider(w, Rect(100, 140, 200, 20))
	.value_(0.5)
	.action_({ f.value });
g = Slider(w, Rect(100, 170, 200, 20))
	.value_(0.5)
	.action_({ f.value });
b = Slider(w, Rect(100, 200, 200, 20))
	.value_(0.5)
	.action_({ f.value });
f.value;
);
::
