diff options
author | Robert Jonsson <spamatica@gmail.com> | 2010-10-13 19:34:22 +0000 |
---|---|---|
committer | Robert Jonsson <spamatica@gmail.com> | 2010-10-13 19:34:22 +0000 |
commit | 8a2c2824a59d7644e13bc52c9a0ecbd641f21f95 (patch) | |
tree | 064ad3f2bf8daab0ad27b128abd86a9bbdb1e496 /muse2/muse/widgets/drange.cpp | |
parent | a27706d9629e8b592cca4659f865b70adef24e6d (diff) |
new branch muse2, first checkin
Diffstat (limited to 'muse2/muse/widgets/drange.cpp')
-rw-r--r-- | muse2/muse/widgets/drange.cpp | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/muse2/muse/widgets/drange.cpp b/muse2/muse/widgets/drange.cpp new file mode 100644 index 00000000..5c986403 --- /dev/null +++ b/muse2/muse/widgets/drange.cpp @@ -0,0 +1,262 @@ +//========================================================= +// MusE +// Linux Music Editor +// $Id: drange.cpp,v 1.2.2.1 2009/03/09 02:05:18 terminator356 Exp $ +// +// Copyright (C) 1997 Josef Wilgen +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License, version 2, +// as published by the Free Software Foundation. +// +// (C) Copyright 2000 Werner Schweer (ws@seh.de) +//========================================================= + +#include <cmath> +#include "mmath.h" +#include "drange.h" + +const double DoubleRange::MinRelStep = 1.0e-10; +const double DoubleRange::DefaultRelStep = 1.0e-2; +const double DoubleRange::MinEps = 1.0e-10; + +//----------------------------------------------------------- +// This class is useful as a base class or a member for sliders. +// It represents an interval of type double within which a value can +// be moved. The value can be either an arbitrary point inside +// the interval (see @DoubleRange::setValue@), or it can be fitted +// into a step raster (see @DoubleRange::fitValue@ and +// @DoubleRange::incValue@). +// +// As a special case, a DoubleRange can be periodic, which means that +// a value outside the interval will be mapped to a value inside the +// interval when @DoubleRange::setValue@, @DoubleRange::fitValue@, +// @DoubleRange::incValue@ or @DoubleRange::incPages@ are called. +//------------------------------------------------------------ + +//--------------------------------------------------------- +// doubleRange +//--------------------------------------------------------- + +DoubleRange::DoubleRange() + { + d_minValue = 0; + d_maxValue = 100.0; + d_prevValue = 0.0; + d_exactPrevValue = 0.0; + d_exactValue = 0.0; + d_value = 0.0; + d_step = 0.1; + d_periodic = FALSE; + } + +//--------------------------------------------------------- +// setNewValue +//--------------------------------------------------------- + +void DoubleRange::setNewValue(double x, bool align) + { + d_prevValue = d_value; + + double vmin = qwtMin(d_minValue, d_maxValue); + double vmax = qwtMax(d_minValue, d_maxValue); + + // Range check + + if (x < vmin) { + if ((d_periodic) && (vmin != vmax)) + d_value = x + ceil((vmin - x) / (vmax - vmin)) + * (vmax - vmin); + else + d_value = vmin; + } + else if (x > vmax) { + if ((d_periodic) && (vmin != vmax)) + d_value = x - ceil( ( x - vmax) / (vmax - vmin )) + * (vmax - vmin); + else + d_value = vmax; + } + else + d_value = x; + + d_exactPrevValue = d_exactValue; + d_exactValue = d_value; + + // align to grid + if (align) { + if (d_step != 0.0) + d_value = d_minValue + rint((d_value - d_minValue) / d_step ) * d_step; + else + d_value = d_minValue; + + // correct rounding error at the border + if (fabs(d_value - d_maxValue) < MinEps * qwtAbs(d_step)) + d_value = d_maxValue; + + // correct rounding error if value = 0 + if (fabs(d_value) < MinEps * qwtAbs(d_step)) + d_value = 0.0; + } + if (d_prevValue != d_value) + valueChange(); + } + +//--------------------------------------------------------- +// fitValue +// Adjust the value to the closest point in the step +// raster. +// The value is clipped when it lies outside the range. +// When the range is @DoubleRange::periodic@, it will +// be mapped to a point in the interval such that +//--------------------------------------------------------- + +void DoubleRange::fitValue(double x) + { + setNewValue(x, true); + } + +//--------------------------------------------------------- +// setValue +// Set a new value without adjusting to the step raster +// The value is clipped when it lies outside the range. +// When the range is @DoubleRange::periodic@, it will +// be mapped to a point in the interval such that +// +// new value := x + n * (max. value - min. value) +// +// with an integer number n. +//--------------------------------------------------------- + +void DoubleRange::setValue(double x) + { + setNewValue(x, false); + } + +//--------------------------------------------------------- +// setRange +// Specify range and step size +// - A change of the range changes the value if it lies outside the +// new range. The current value +// will *not* be adjusted to the new step raster. +// - vmax < vmin is allowed. +// - If the step size is left out or set to zero, it will be +// set to 1/100 of the interval length. +// - If the step size has an absurd value, it will be corrected +// to a better one. +//--------------------------------------------------------- + +void DoubleRange::setRange(double vmin, double vmax, double vstep, int pageSize) + { + bool rchg = ((d_maxValue != vmax) || (d_minValue != vmin)); + + if (rchg) { + d_minValue = vmin; + d_maxValue = vmax; + } + + // + // look if the step width has an acceptable + // value or otherwise change it. + // + setStep(vstep); + + // + // limit page size + // + d_pageSize = qwtLim(pageSize,0, int(qwtAbs((d_maxValue - d_minValue) / d_step))); + + // + // If the value lies out of the range, it + // will be changed. Note that it will not be adjusted to + // the new step width. + setNewValue(d_value, false); + + // call notifier after the step width has been + // adjusted. + if (rchg) + rangeChange(); + } + +//--------------------------------------------------------- +// setStep +// Change the step raster +// +// The value will *not* be adjusted to the new step raster. +//--------------------------------------------------------- + +void DoubleRange::setStep(double vstep) + { + double newStep,intv; + + intv = d_maxValue - d_minValue; + + if (vstep == 0.0) + newStep = intv * DefaultRelStep; + else { + if (((intv > 0) && (vstep < 0)) || ((intv < 0) && (vstep > 0))) + newStep = -vstep; + else + newStep = vstep; + + if ( fabs(newStep) < fabs(MinRelStep * intv) ) + newStep = MinRelStep * intv; + } + + if (newStep != d_step) { + d_step = newStep; + stepChange(); + } + } + +//--------------------------------------------------------- +// setPeriodic +// Make the range periodic +// +// When the range is periodic, the value will be set to a point +// inside the interval such that +// +// point = value + n * width +// +// if the user tries to set a new value which is outside the range. +// If the range is nonperiodic (the default), values outside the +// range will be clipped. +//--------------------------------------------------------- + +void DoubleRange::setPeriodic(bool tf) + { + d_periodic = tf; + } + +//------------------------------------------------------------ +// incValue +// Increment the value by a specified number of steps +// +// As a result of this operation, the new value will always be +// adjusted to the step raster. +//------------------------------------------------------------ + +void DoubleRange::incValue(int nSteps) + { + setNewValue(d_value + double(nSteps) * d_step, true); + } + +//--------------------------------------------------------- +// incPages +// Increment the value by a specified number of pages +//--------------------------------------------------------- + +void DoubleRange::incPages(int nPages) + { + setNewValue(d_value + double(nPages) * double(d_pageSize) + * d_step, true); + } + +//--------------------------------------------------------- +// step +//--------------------------------------------------------- + +double DoubleRange::step() const + { + return qwtAbs(d_step); + } + |