Implement logarithmic slider mode.
This commit is contained in:
parent
50a5f66fff
commit
de6c22ac46
250
FL/Fl_SliderX.C
250
FL/Fl_SliderX.C
|
@ -21,6 +21,8 @@
|
|||
#include <FL/Fl.H>
|
||||
#include <FL/fl_draw.H>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
void
|
||||
Fl_SliderX::draw ( int X, int Y, int W, int H)
|
||||
{
|
||||
|
@ -28,32 +30,14 @@ Fl_SliderX::draw ( int X, int Y, int W, int H)
|
|||
|
||||
if (damage()&FL_DAMAGE_ALL) draw_box();
|
||||
|
||||
double val;
|
||||
|
||||
if (minimum() == maximum())
|
||||
val = 0.5;
|
||||
else {
|
||||
val = (value()-minimum())/(maximum()-minimum());
|
||||
if (val > 1.0) val = 1.0;
|
||||
else if (val < 0.0) val = 0.0;
|
||||
}
|
||||
|
||||
int ww = (horizontal() ? W : H);
|
||||
int hh = (horizontal() ? H : W);
|
||||
int xx, S;
|
||||
|
||||
/* S = int(val*ww+.5); */
|
||||
/* if (minimum()>maximum()) {S = ww-S; xx = ww-S;} */
|
||||
/* else xx = 0; */
|
||||
xx = slider_position( value(), ww );
|
||||
|
||||
{
|
||||
//S = //int(ww+.5);
|
||||
S = hh;
|
||||
int T = (horizontal() ? H : W)/2+1;
|
||||
// if (type()==FL_VERT_NICE_SLIDER || type()==FL_HOR_NICE_SLIDER) T += 4;
|
||||
if (S < T) S = T;
|
||||
xx = int(val*(ww-S)+.5);
|
||||
}
|
||||
S = (horizontal() ? H : W );
|
||||
|
||||
int xsl, ysl, wsl, hsl;
|
||||
if (horizontal()) {
|
||||
|
@ -131,3 +115,229 @@ Fl_SliderX::draw ( int X, int Y, int W, int H)
|
|||
/* h()-Fl::box_dh(box())); */
|
||||
|
||||
}
|
||||
|
||||
/** return a value between 0.0 and 1.0 which represents the current slider position. */
|
||||
int
|
||||
Fl_SliderX::slider_position ( double value, int w )
|
||||
{
|
||||
double A = minimum();
|
||||
double B = maximum();
|
||||
if (B == A) return 0;
|
||||
bool flip = B < A;
|
||||
if (flip) {A = B; B = minimum();}
|
||||
if (!horizontal()) flip = !flip;
|
||||
// if both are negative, make the range positive:
|
||||
if (B <= 0) {flip = !flip; double t = A; A = -B; B = -t; value = -value;}
|
||||
double fraction;
|
||||
if (!log()) {
|
||||
// linear slider
|
||||
fraction = (value-A)/(B-A);
|
||||
} else if (A > 0) {
|
||||
// logatithmic slider
|
||||
if (value <= A) fraction = 0;
|
||||
else fraction = (::log(value)-::log(A))/(::log(B)-::log(A));
|
||||
} else if (A == 0) {
|
||||
// squared slider
|
||||
if (value <= 0) fraction = 0;
|
||||
else fraction = sqrt(value/B);
|
||||
} else {
|
||||
// squared signed slider
|
||||
if (value < 0) fraction = (1-sqrt(value/A))*.5;
|
||||
else fraction = (1+sqrt(value/B))*.5;
|
||||
}
|
||||
if (flip) fraction = 1-fraction;
|
||||
|
||||
w -= int(slider_size()*w+.5); if (w <= 0) return 0;
|
||||
if (fraction >= 1) return w;
|
||||
else if (fraction <= 0) return 0;
|
||||
else return int(fraction*w+.5);
|
||||
}
|
||||
|
||||
double
|
||||
Fl_SliderX::slider_value ( int X, int w )
|
||||
{
|
||||
w -= int(slider_size()*w+.5); if (w <= 0) return minimum();
|
||||
double A = minimum();
|
||||
double B = maximum();
|
||||
bool flip = B < A;
|
||||
if (flip) {A = B; B = minimum();}
|
||||
if (!horizontal()) flip = !flip;
|
||||
if (flip) X = w-X;
|
||||
double fraction = double(X)/w;
|
||||
if (fraction <= 0) return A;
|
||||
if (fraction >= 1) return B;
|
||||
// if both are negative, make the range positive:
|
||||
flip = (B <= 0);
|
||||
if (flip) {double t = A; A = -B; B = -t; fraction = 1-fraction;}
|
||||
double value;
|
||||
double derivative;
|
||||
if (!log()) {
|
||||
// linear slider
|
||||
value = fraction*(B-A)+A;
|
||||
derivative = (B-A)/w;
|
||||
} else if (A > 0) {
|
||||
// log slider
|
||||
double d = (::log(B)-::log(A));
|
||||
value = exp(fraction*d+::log(A));
|
||||
derivative = value*d/w;
|
||||
} else if (A == 0) {
|
||||
// squared slider
|
||||
value = fraction*fraction*B;
|
||||
derivative = 2*fraction*B/w;
|
||||
} else {
|
||||
// squared signed slider
|
||||
fraction = 2*fraction - 1;
|
||||
if (fraction < 0) B = A;
|
||||
value = fraction*fraction*B;
|
||||
derivative = 4*fraction*B/w;
|
||||
}
|
||||
// find nicest multiple of 10,5, or 2 of step() that is close to 1 pixel:
|
||||
if (step() && derivative > step()) {
|
||||
double w = log10(derivative);
|
||||
double l = ceil(w);
|
||||
int num = 1;
|
||||
int i; for (i = 0; i < l; i++) num *= 10;
|
||||
int denom = 1;
|
||||
for (i = -1; i >= l; i--) denom *= 10;
|
||||
if (l-w > 0.69897) denom *= 5;
|
||||
else if (l-w > 0.30103) denom *= 2;
|
||||
value = floor(value*denom/num+.5)*num/denom;
|
||||
}
|
||||
if (flip) return -value;
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
int Fl_SliderX::handle(int event, int X, int Y, int W, int H) {
|
||||
// Fl_Widget_Tracker wp(this);
|
||||
switch (event) {
|
||||
case FL_PUSH: {
|
||||
Fl_Widget_Tracker wp(this);
|
||||
if (!Fl::event_inside(X, Y, W, H)) return 0;
|
||||
handle_push();
|
||||
if (wp.deleted()) return 1; }
|
||||
// fall through ...
|
||||
case FL_DRAG: {
|
||||
|
||||
static int offcenter;
|
||||
|
||||
int ww = (horizontal() ? W : H);
|
||||
|
||||
|
||||
if ( event == FL_PUSH )
|
||||
{
|
||||
int x = slider_position( value(), ww );
|
||||
|
||||
offcenter = (Fl::event_x()-X) - x;
|
||||
}
|
||||
|
||||
try_again:
|
||||
|
||||
int mx = (horizontal() ? Fl::event_x()-X : Fl::event_y()-Y) - offcenter;
|
||||
double v = slider_value( mx, ww );
|
||||
|
||||
if (event == FL_PUSH && v == value()) {
|
||||
offcenter = int(slider_size()*ww+0.5)/2;
|
||||
event = FL_DRAG;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
handle_drag(clamp(v));
|
||||
} return 1;
|
||||
case FL_RELEASE:
|
||||
handle_release();
|
||||
return 1;
|
||||
case FL_KEYBOARD:
|
||||
{ Fl_Widget_Tracker wp(this);
|
||||
switch (Fl::event_key()) {
|
||||
case FL_Up:
|
||||
if (horizontal()) return 0;
|
||||
handle_push();
|
||||
if (wp.deleted()) return 1;
|
||||
handle_drag(clamp(increment(value(),-1)));
|
||||
if (wp.deleted()) return 1;
|
||||
handle_release();
|
||||
return 1;
|
||||
case FL_Down:
|
||||
if (horizontal()) return 0;
|
||||
handle_push();
|
||||
if (wp.deleted()) return 1;
|
||||
handle_drag(clamp(increment(value(),1)));
|
||||
if (wp.deleted()) return 1;
|
||||
handle_release();
|
||||
return 1;
|
||||
case FL_Left:
|
||||
if (!horizontal()) return 0;
|
||||
handle_push();
|
||||
if (wp.deleted()) return 1;
|
||||
handle_drag(clamp(increment(value(),-1)));
|
||||
if (wp.deleted()) return 1;
|
||||
handle_release();
|
||||
return 1;
|
||||
case FL_Right:
|
||||
if (!horizontal()) return 0;
|
||||
handle_push();
|
||||
if (wp.deleted()) return 1;
|
||||
handle_drag(clamp(increment(value(),1)));
|
||||
if (wp.deleted()) return 1;
|
||||
handle_release();
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// break not required because of switch...
|
||||
case FL_FOCUS :
|
||||
case FL_UNFOCUS :
|
||||
if (Fl::visible_focus()) {
|
||||
redraw();
|
||||
return 1;
|
||||
} else return 0;
|
||||
case FL_ENTER :
|
||||
case FL_LEAVE :
|
||||
return 1;
|
||||
case FL_MOUSEWHEEL :
|
||||
{
|
||||
if ( this != Fl::belowmouse() )
|
||||
return 0;
|
||||
if (Fl::e_dy==0)
|
||||
return 0;
|
||||
|
||||
const int steps = Fl::event_ctrl() ? 128 : 16;
|
||||
|
||||
const float step = fabs( maximum() - minimum() ) / (float)steps;
|
||||
|
||||
int dy = Fl::e_dy;
|
||||
|
||||
/* slider is in 'upside down' configuration, invert meaning of mousewheel */
|
||||
if ( minimum() > maximum() )
|
||||
dy = 0 - dy;
|
||||
|
||||
handle_drag(clamp(value() + step * dy));
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Fl_SliderX::handle(int event) {
|
||||
if (event == FL_PUSH && Fl::visible_focus()) {
|
||||
Fl::focus(this);
|
||||
redraw();
|
||||
}
|
||||
|
||||
return handle(event,
|
||||
x()+Fl::box_dx(box()),
|
||||
y()+Fl::box_dy(box()),
|
||||
w()-Fl::box_dw(box()),
|
||||
h()-Fl::box_dh(box()));
|
||||
}
|
||||
|
||||
void
|
||||
Fl_SliderX::resize ( int X, int Y, int W, int H )
|
||||
{
|
||||
Fl_Slider::resize(X,Y,W,H);
|
||||
|
||||
slider_size( horizontal() ? H / (float)W : W / (float)H );
|
||||
}
|
||||
|
|
|
@ -23,15 +23,31 @@
|
|||
|
||||
class Fl_SliderX : public Fl_Slider
|
||||
{
|
||||
bool _log;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
void log ( bool v ) { _log = v; }
|
||||
bool log ( void ) const { return _log; }
|
||||
|
||||
Fl_SliderX( int X, int Y, int W, int H, const char *L=0 ) : Fl_Slider(X,Y,W,H,L)
|
||||
{
|
||||
_log = 0;
|
||||
}
|
||||
|
||||
virtual ~Fl_SliderX ( ) { };
|
||||
|
||||
virtual int slider_position ( double value, int w );
|
||||
virtual double slider_value ( int X, int w );
|
||||
|
||||
virtual void draw ( int X, int Y, int W, int H );
|
||||
virtual void draw ( void ) { draw(x(),y(),w(),h()); }
|
||||
|
||||
|
||||
virtual int handle(int event, int X, int Y, int W, int H);
|
||||
virtual int handle(int event);
|
||||
|
||||
virtual void resize ( int X, int Y, int W, int H );
|
||||
|
||||
};
|
||||
|
|
|
@ -357,7 +357,10 @@ Module_Parameter_Editor::make_controls ( void )
|
|||
o->maximum( p->hints.minimum );
|
||||
o->minimum( p->hints.maximum );
|
||||
}
|
||||
if ( p->hints.type & Module::Port::Hints::LOGARITHMIC )
|
||||
o->log(true);
|
||||
|
||||
o->precision( 2 );
|
||||
/* a couple of plugins have ridiculously small units */
|
||||
float r = fabs( p->hints.maximum - p->hints.minimum );
|
||||
|
||||
|
|
Loading…
Reference in New Issue