This commit is contained in:
serso 2011-09-25 11:12:59 +04:00
parent ce416f56e0
commit 7921c09f45
7 changed files with 75 additions and 34 deletions

View File

@ -7,5 +7,7 @@
<declare-styleable name="NumberRangeSeekBar"> <declare-styleable name="NumberRangeSeekBar">
<attr name="boundaries" format="string"/> <attr name="boundaries" format="string"/>
<attr name="steps" format="integer"/>
</declare-styleable> </declare-styleable>
</resources> </resources>

View File

@ -18,6 +18,7 @@
a:title="Distance of drag event" a:title="Distance of drag event"
a:text=" pxs" a:text=" pxs"
a:defaultValue="15;350" a:defaultValue="15;350"
range:steps="10"
range:boundaries="10;500"/> range:boundaries="10;500"/>
<org.solovyev.android.view.prefs.FloatRangeSeekBarPreference <org.solovyev.android.view.prefs.FloatRangeSeekBarPreference
@ -25,6 +26,7 @@
a:title="Duration of drag event" a:title="Duration of drag event"
a:text=" ms" a:text=" ms"
a:defaultValue="40;2500" a:defaultValue="40;2500"
range:steps="10"
range:boundaries="5;4000"/> range:boundaries="5;4000"/>
<org.solovyev.android.view.prefs.FloatRangeSeekBarPreference <org.solovyev.android.view.prefs.FloatRangeSeekBarPreference
@ -32,6 +34,7 @@
a:title="Angle of drag event" a:title="Angle of drag event"
a:text=" degrees" a:text=" degrees"
a:defaultValue="0;45" a:defaultValue="0;45"
range:steps="5"
range:boundaries="0;45"/> range:boundaries="0;45"/>
</PreferenceCategory> </PreferenceCategory>

View File

@ -8,6 +8,7 @@ package org.solovyev.android.calculator;
import android.app.Activity; import android.app.Activity;
import android.content.*; import android.content.*;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.ClipboardManager; import android.text.ClipboardManager;
import android.util.Log; import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
@ -102,6 +103,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
}; };
registerReceiver(preferencesChangesReceiver, new IntentFilter(DragButtonCalibrationActivity.INTENT_ACTION)); registerReceiver(preferencesChangesReceiver, new IntentFilter(DragButtonCalibrationActivity.INTENT_ACTION));
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
} }
@Override @Override

View File

@ -137,8 +137,9 @@ public abstract class AbstractDialogPreference<T> extends DialogPreference {
private void persist(@Nullable T value) { private void persist(@Nullable T value) {
final String toBePersistedString = getMapper().formatValue(value); final String toBePersistedString = getMapper().formatValue(value);
if (toBePersistedString != null) { if (toBePersistedString != null) {
persistString(toBePersistedString); if ( callChangeListener(value) ) {
callChangeListener(value); persistString(toBePersistedString);
}
} }
} }

View File

@ -24,18 +24,26 @@ public abstract class RangeSeekBarPreference<T extends Number> extends AbstractD
@NotNull @NotNull
private final Interval<T> boundaries; private final Interval<T> boundaries;
private Integer steps;
public RangeSeekBarPreference(@NotNull Context context, AttributeSet attrs) { public RangeSeekBarPreference(@NotNull Context context, AttributeSet attrs) {
super(context, attrs, null); super(context, attrs, null);
//noinspection ConstantConditions
boundaries = getMapper().parseValue(attrs.getAttributeValue(localNameSpace, "boundaries")); boundaries = getMapper().parseValue(attrs.getAttributeValue(localNameSpace, "boundaries"));
assert boundaries != null; steps = attrs.getAttributeIntValue(localNameSpace, "steps", -1);
if ( steps.equals(-1) ) {
steps = null;
}
assert steps == null || steps >= 2;
createPreferenceView(); createPreferenceView();
} }
private void createPreferenceView() { private void createPreferenceView() {
this.rangeSeekBar = new NumberRangeSeekBar<T>(boundaries, null, context); this.rangeSeekBar = new NumberRangeSeekBar<T>(boundaries, steps, context);
this.rangeSeekBar.setNotifyWhileDragging(true); this.rangeSeekBar.setNotifyWhileDragging(true);
this.rangeSeekBar.setOnRangeSeekBarChangeListener(this); this.rangeSeekBar.setOnRangeSeekBarChangeListener(this);

View File

@ -14,7 +14,6 @@ import android.widget.ImageView;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.R;
import org.solovyev.common.math.DiscreteNormalizer;
import org.solovyev.common.math.LinearNormalizer; import org.solovyev.common.math.LinearNormalizer;
import org.solovyev.common.math.Normalizer; import org.solovyev.common.math.Normalizer;
import org.solovyev.common.utils.Converter; import org.solovyev.common.utils.Converter;
@ -44,7 +43,10 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
private final T minValue, maxValue; private final T minValue, maxValue;
@NotNull @NotNull
private final Normalizer normalizer; private final Normalizer fromValueNormalizer;
@NotNull
private final Normalizer fromScreenNormalizer;
private double normalizedMinValue = 0d; private double normalizedMinValue = 0d;
@ -63,7 +65,8 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
* *
* @param minValue The minimum value of the selectable range. * @param minValue The minimum value of the selectable range.
* @param maxValue The maximum value of the selectable range. * @param maxValue The maximum value of the selectable range.
* @param context * @param steps number of steps to be used in range seek bar
* @param context parent context
* @throws IllegalArgumentException Will be thrown if min/max value types are not one of Long, Double, Integer, Float, Short, Byte or BigDecimal. * @throws IllegalArgumentException Will be thrown if min/max value types are not one of Long, Double, Integer, Float, Short, Byte or BigDecimal.
*/ */
public AbstractRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, @Nullable Integer steps, Context context) throws IllegalArgumentException { public AbstractRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, @Nullable Integer steps, Context context) throws IllegalArgumentException {
@ -75,13 +78,28 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
this.toDoubleConverter = getToDoubleConverter(); this.toDoubleConverter = getToDoubleConverter();
this.toTConverter = getToTConverter(); this.toTConverter = getToTConverter();
if (steps == null) { fromValueNormalizer = new LinearNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue));
normalizer = new LinearNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue));
} else {
normalizer = new DiscreteNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue), steps);
}
tc = new ThumbContainer(); tc = new ThumbContainer();
fromScreenNormalizer = new Normalizer() {
@Override
public double normalize(double value) {
int width = getWidth();
if (width <= 2 * tc.padding) {
// prevent division by zero, simply return 0.
return 0d;
} else {
double result = (value - tc.padding) / (width - 2 * tc.padding);
return Math.min(1d, Math.max(0d, result));
}
}
@Override
public double denormalize(double value) {
return (float) (tc.padding + value * (getWidth() - 2 * tc.padding));
}
};
} }
@NotNull @NotNull
@ -180,11 +198,15 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
break; break;
case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_MOVE:
if (pressedThumb != null) { if (pressedThumb != null) {
double value = convertToNormalizedValue(event.getX());
if (Thumb.MIN.equals(pressedThumb)) { if (Thumb.MIN.equals(pressedThumb)) {
setNormalizedMinValue(convertToNormalizedValue(event.getX())); setNormalizedMinValue(value);
} else if (Thumb.MAX.equals(pressedThumb)) { } else if (Thumb.MAX.equals(pressedThumb)) {
setNormalizedMaxValue(convertToNormalizedValue(event.getX())); setNormalizedMaxValue(value);
} }
if (notifyWhileDragging && listener != null) { if (notifyWhileDragging && listener != null) {
listener.rangeSeekBarValuesChanged(getSelectedMinValue(), getSelectedMaxValue(), false); listener.rangeSeekBarValuesChanged(getSelectedMinValue(), getSelectedMaxValue(), false);
} }
@ -317,7 +339,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private T denormalizeValue(double normalized) { private T denormalizeValue(double normalized) {
return toTConverter.convert(normalizer.denormalize(normalized)); return toTConverter.convert(fromValueNormalizer.denormalize(normalized));
} }
/** /**
@ -327,7 +349,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
* @return The normalized double. * @return The normalized double.
*/ */
private double normalizeValue(T value) { private double normalizeValue(T value) {
return normalizer.normalize(toDoubleConverter.convert(value)); return fromValueNormalizer.normalize(toDoubleConverter.convert(value));
} }
/** /**
@ -337,7 +359,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
* @return The converted value in screen space. * @return The converted value in screen space.
*/ */
private float convertToScreenValue(double normalizedValue) { private float convertToScreenValue(double normalizedValue) {
return (float) (tc.padding + normalizedValue * (getWidth() - 2 * tc.padding)); return (float)this.fromScreenNormalizer.denormalize(normalizedValue);
} }
/** /**
@ -347,14 +369,7 @@ public abstract class AbstractRangeSeekBar<T> extends ImageView {
* @return The normalized value. * @return The normalized value.
*/ */
private double convertToNormalizedValue(float screenValue) { private double convertToNormalizedValue(float screenValue) {
int width = getWidth(); return this.fromScreenNormalizer.normalize(screenValue);
if (width <= 2 * tc.padding) {
// prevent division by zero, simply return 0.
return 0d;
} else {
double result = (screenValue - tc.padding) / (width - 2 * tc.padding);
return Math.min(1d, Math.max(0d, result));
}
} }
/** /**

View File

@ -1,6 +1,7 @@
package org.solovyev.common.math; package org.solovyev.common.math;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* User: serso * User: serso
@ -10,35 +11,43 @@ import org.jetbrains.annotations.NotNull;
public class DiscreteNormalizer implements Normalizer { public class DiscreteNormalizer implements Normalizer {
@NotNull @NotNull
private final LinearNormalizer linearNormalizer; private final Normalizer normalizer;
private final double min; private final double min;
private final double step; private final double step;
public DiscreteNormalizer(double min, double max, int steps) { public DiscreteNormalizer(double min, double max, int steps) {
this(min, max, steps, null);
}
public DiscreteNormalizer(double min, double max, int steps, @Nullable Normalizer normalizer) {
assert min <= max; assert min <= max;
assert steps > 1; assert steps > 1;
this.linearNormalizer = new LinearNormalizer(min, max); if (normalizer != null) {
this.normalizer = normalizer;
} else {
this.normalizer = new LinearNormalizer(min, max);
}
this.step = linearNormalizer.normalize((max - min) / (steps - 1)); this.step = this.normalizer.normalize((max - min) / (steps - 1));
this.min = linearNormalizer.normalize(min); this.min = this.normalizer.normalize(min);
} }
public DiscreteNormalizer(double min, double max, double step) { public DiscreteNormalizer(double min, double max, double step) {
assert min <= max; assert min <= max;
assert step > 0; assert step > 0;
this.linearNormalizer = new LinearNormalizer(min, max); this.normalizer = new LinearNormalizer(min, max);
this.step = linearNormalizer.normalize(step); this.step = normalizer.normalize(step);
this.min = linearNormalizer.normalize(min); this.min = normalizer.normalize(min);
} }
@Override @Override
public double normalize(double value) { public double normalize(double value) {
double normalizedValue = linearNormalizer.normalize(value); double normalizedValue = normalizer.normalize(value);
double result = min; double result = min;
while (true) { while (true) {
@ -54,6 +63,6 @@ public class DiscreteNormalizer implements Normalizer {
@Override @Override
public double denormalize(double value) { public double denormalize(double value) {
return linearNormalizer.denormalize(value); return normalizer.denormalize(value);
} }
} }