diff --git a/FL/Fl_SliderX.C b/FL/Fl_SliderX.C index 54dc6e4..4d7b969 100644 --- a/FL/Fl_SliderX.C +++ b/FL/Fl_SliderX.C @@ -21,6 +21,8 @@ #include #include +#include + void Fl_SliderX::draw ( int X, int Y, int W, int H) { @@ -28,33 +30,15 @@ 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; */ - - { - //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); - } + xx = slider_position( value(), ww ); + S = (horizontal() ? H : W ); + int xsl, ysl, wsl, hsl; if (horizontal()) { xsl = X+xx; @@ -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 ); +} diff --git a/FL/Fl_SliderX.H b/FL/Fl_SliderX.H index 6dbc12c..4e1b538 100644 --- a/FL/Fl_SliderX.H +++ b/FL/Fl_SliderX.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 ); + }; diff --git a/mixer/src/Module_Parameter_Editor.C b/mixer/src/Module_Parameter_Editor.C index 852e14a..fbd3e72 100644 --- a/mixer/src/Module_Parameter_Editor.C +++ b/mixer/src/Module_Parameter_Editor.C @@ -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 );