DRC | 2ff39b8 | 2011-07-28 08:38:59 +0000 | [diff] [blame^] | 1 | // |
| 2 | // "$Id: Fl_Valuator.cxx 7903 2010-11-28 21:06:39Z matt $" |
| 3 | // |
| 4 | // Valuator widget for the Fast Light Tool Kit (FLTK). |
| 5 | // |
| 6 | // Copyright 1998-2010 by Bill Spitzak and others. |
| 7 | // |
| 8 | // This library is free software; you can redistribute it and/or |
| 9 | // modify it under the terms of the GNU Library General Public |
| 10 | // License as published by the Free Software Foundation; either |
| 11 | // version 2 of the License, or (at your option) any later version. |
| 12 | // |
| 13 | // This library is distributed in the hope that it will be useful, |
| 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 | // Library General Public License for more details. |
| 17 | // |
| 18 | // You should have received a copy of the GNU Library General Public |
| 19 | // License along with this library; if not, write to the Free Software |
| 20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| 21 | // USA. |
| 22 | // |
| 23 | // Please report all bugs and problems on the following page: |
| 24 | // |
| 25 | // http://www.fltk.org/str.php |
| 26 | // |
| 27 | |
| 28 | |
| 29 | // Base class for sliders and all other one-value "knobs" |
| 30 | |
| 31 | #include <FL/Fl.H> |
| 32 | #include <FL/Fl_Valuator.H> |
| 33 | #include <FL/math.h> |
| 34 | #include <stdio.h> |
| 35 | #include "flstring.h" |
| 36 | |
| 37 | Fl_Valuator::Fl_Valuator(int X, int Y, int W, int H, const char* L) |
| 38 | /** |
| 39 | Creates a new Fl_Valuator widget using the given position, |
| 40 | size, and label string. The default boxtype is FL_NO_BOX. |
| 41 | */ |
| 42 | : Fl_Widget(X,Y,W,H,L) { |
| 43 | align(FL_ALIGN_BOTTOM); |
| 44 | when(FL_WHEN_CHANGED); |
| 45 | value_ = 0; |
| 46 | previous_value_ = 1; |
| 47 | min = 0; |
| 48 | max = 1; |
| 49 | A = 0.0; |
| 50 | B = 1; |
| 51 | } |
| 52 | |
| 53 | const double epsilon = 4.66e-10; |
| 54 | |
| 55 | /** See double Fl_Valuator::step() const */ |
| 56 | void Fl_Valuator::step(double s) { |
| 57 | if (s < 0) s = -s; |
| 58 | A = rint(s); |
| 59 | B = 1; |
| 60 | while (fabs(s-A/B) > epsilon && B<=(0x7fffffff/10)) {B *= 10; A = rint(s*B);} |
| 61 | } |
| 62 | |
| 63 | /** Sets the step value to 1/10<SUP>digits</SUP>.*/ |
| 64 | void Fl_Valuator::precision(int p) { |
| 65 | A = 1.0; |
| 66 | for (B = 1; p--;) B *= 10; |
| 67 | } |
| 68 | /** Asks for partial redraw */ |
| 69 | void Fl_Valuator::value_damage() {damage(FL_DAMAGE_EXPOSE);} // by default do partial-redraw |
| 70 | |
| 71 | /** |
| 72 | Sets the current value. The new value is <I>not</I> |
| 73 | clamped or otherwise changed before storing it. Use |
| 74 | clamp() or round() to modify the value before |
| 75 | calling value(). The widget is redrawn if the new value |
| 76 | is different than the current one. The initial value is zero. |
| 77 | <P>changed() will return true if the user has moved the slider, |
| 78 | but it will be turned off by value(x) and just before doing a callback |
| 79 | (the callback can turn it back on if desired). |
| 80 | */ |
| 81 | int Fl_Valuator::value(double v) { |
| 82 | clear_changed(); |
| 83 | if (v == value_) return 0; |
| 84 | value_ = v; |
| 85 | value_damage(); |
| 86 | return 1; |
| 87 | } |
| 88 | /** Clamps the value, but accepts v if the previous value is not already out of range */ |
| 89 | double Fl_Valuator::softclamp(double v) { |
| 90 | int which = (min<=max); |
| 91 | double p = previous_value_; |
| 92 | if ((v<min)==which && p!=min && (p<min)!=which) return min; |
| 93 | else if ((v>max)==which && p!=max && (p>max)!=which) return max; |
| 94 | else return v; |
| 95 | } |
| 96 | |
| 97 | // inline void Fl_Valuator::handle_push() {previous_value_ = value_;} |
| 98 | /** Called during a drag operation, after an FL_WHEN_CHANGED event is received and before the callback. */ |
| 99 | void Fl_Valuator::handle_drag(double v) { |
| 100 | if (v != value_) { |
| 101 | value_ = v; |
| 102 | value_damage(); |
| 103 | set_changed(); |
| 104 | if (when() & FL_WHEN_CHANGED) do_callback(); |
| 105 | } |
| 106 | } |
| 107 | /** Called after an FL_WHEN_RELEASE event is received and before the callback. */ |
| 108 | void Fl_Valuator::handle_release() { |
| 109 | if (when()&FL_WHEN_RELEASE) { |
| 110 | // insure changed() is off even if no callback is done. It may have |
| 111 | // been turned on by the drag, and then the slider returned to it's |
| 112 | // initial position: |
| 113 | clear_changed(); |
| 114 | // now do the callback only if slider in new position or always is on: |
| 115 | if (value_ != previous_value_ || when() & FL_WHEN_NOT_CHANGED) { |
| 116 | do_callback(); |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | /** |
| 122 | Round the passed value to the nearest step increment. Does |
| 123 | nothing if step is zero. |
| 124 | */ |
| 125 | double Fl_Valuator::round(double v) { |
| 126 | if (A) return rint(v*B/A)*A/B; |
| 127 | else return v; |
| 128 | } |
| 129 | |
| 130 | /** Clamps the passed value to the valuator range.*/ |
| 131 | double Fl_Valuator::clamp(double v) { |
| 132 | if ((v<min)==(min<=max)) return min; |
| 133 | else if ((v>max)==(min<=max)) return max; |
| 134 | else return v; |
| 135 | } |
| 136 | |
| 137 | /** |
| 138 | Adds n times the step value to the passed value. If |
| 139 | step was set to zero it uses fabs(maximum() - minimum()) / |
| 140 | 100. |
| 141 | */ |
| 142 | double Fl_Valuator::increment(double v, int n) { |
| 143 | if (!A) return v+n*(max-min)/100; |
| 144 | if (min > max) n = -n; |
| 145 | return (rint(v*B/A)+n)*A/B; |
| 146 | } |
| 147 | |
| 148 | /** |
| 149 | Uses internal rules to format the fields numerical value into |
| 150 | the character array pointed to by the passed parameter.</P> |
| 151 | |
| 152 | <P>The actual format used depends on the current step value. If |
| 153 | the step value has been set to zero then a %g format is used. |
| 154 | If the step value is non-zero, then a %.*f format is used, |
| 155 | where the precision is calculated to show sufficient digits |
| 156 | for the current step value. An integer step value, such as 1 |
| 157 | or 1.0, gives a precision of 0, so the formatted value will |
| 158 | appear as an integer.</P> |
| 159 | |
| 160 | <P>This method is used by the Fl_Value_... group of widgets to |
| 161 | format the current value into a text string. |
| 162 | The return value is the length of the formatted text. |
| 163 | The formatted value is written into in <i>buffer</i>. |
| 164 | <i>buffer</i> should have space for at least 128 bytes.</P> |
| 165 | |
| 166 | <P>You may override this function to create your own text formatting. |
| 167 | */ |
| 168 | int Fl_Valuator::format(char* buffer) { |
| 169 | double v = value(); |
| 170 | // MRS: THIS IS A HACK - RECOMMEND ADDING BUFFER SIZE ARGUMENT |
| 171 | if (!A || !B) return snprintf(buffer, 128, "%g", v); |
| 172 | |
| 173 | // Figure out how many digits are required to correctly format the |
| 174 | // value. |
| 175 | int i, c = 0; |
| 176 | char temp[32]; |
| 177 | // output a number with many digits after the decimal point. This |
| 178 | // seems to be needed to get high precission |
| 179 | snprintf(temp, sizeof(temp), "%.12f", A/B); |
| 180 | // strip all trailing 0's |
| 181 | for (i=strlen(temp)-1; i>0; i--) { |
| 182 | if (temp[i]!='0') break; |
| 183 | } |
| 184 | // count digits until we find the decimal point (or comma or whatever |
| 185 | // letter is set in the current locale) |
| 186 | for (; i>0; i--, c++) { |
| 187 | if (!isdigit(temp[i])) break; |
| 188 | } |
| 189 | |
| 190 | // MRS: THIS IS A HACK - RECOMMEND ADDING BUFFER SIZE ARGUMENT |
| 191 | return snprintf(buffer, 128, "%.*f", c, v); |
| 192 | } |
| 193 | |
| 194 | // |
| 195 | // End of "$Id: Fl_Valuator.cxx 7903 2010-11-28 21:06:39Z matt $". |
| 196 | // |