diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index e62066d4..51f2e6a6 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -7,5 +7,7 @@
+
+
diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml
index 1d426216..899bdca0 100644
--- a/res/xml/preferences.xml
+++ b/res/xml/preferences.xml
@@ -18,6 +18,7 @@
a:title="Distance of drag event"
a:text=" pxs"
a:defaultValue="15;350"
+ range:steps="10"
range:boundaries="10;500"/>
diff --git a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java
index be0ad54d..f9e6a368 100644
--- a/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java
+++ b/src/main/java/org/solovyev/android/calculator/CalculatorActivity.java
@@ -8,6 +8,7 @@ package org.solovyev.android.calculator;
import android.app.Activity;
import android.content.*;
import android.os.Bundle;
+import android.preference.PreferenceManager;
import android.text.ClipboardManager;
import android.util.Log;
import android.util.TypedValue;
@@ -102,6 +103,8 @@ public class CalculatorActivity extends Activity implements FontSizeAdjuster, Sh
};
registerReceiver(preferencesChangesReceiver, new IntentFilter(DragButtonCalibrationActivity.INTENT_ACTION));
+
+ PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
}
@Override
diff --git a/src/main/java/org/solovyev/android/view/prefs/AbstractDialogPreference.java b/src/main/java/org/solovyev/android/view/prefs/AbstractDialogPreference.java
index bdf441f8..809a93f6 100644
--- a/src/main/java/org/solovyev/android/view/prefs/AbstractDialogPreference.java
+++ b/src/main/java/org/solovyev/android/view/prefs/AbstractDialogPreference.java
@@ -137,8 +137,9 @@ public abstract class AbstractDialogPreference extends DialogPreference {
private void persist(@Nullable T value) {
final String toBePersistedString = getMapper().formatValue(value);
if (toBePersistedString != null) {
- persistString(toBePersistedString);
- callChangeListener(value);
+ if ( callChangeListener(value) ) {
+ persistString(toBePersistedString);
+ }
}
}
diff --git a/src/main/java/org/solovyev/android/view/prefs/RangeSeekBarPreference.java b/src/main/java/org/solovyev/android/view/prefs/RangeSeekBarPreference.java
index b7c2c3fb..bd3c1bac 100644
--- a/src/main/java/org/solovyev/android/view/prefs/RangeSeekBarPreference.java
+++ b/src/main/java/org/solovyev/android/view/prefs/RangeSeekBarPreference.java
@@ -24,18 +24,26 @@ public abstract class RangeSeekBarPreference extends AbstractD
@NotNull
private final Interval boundaries;
+ private Integer steps;
+
public RangeSeekBarPreference(@NotNull Context context, AttributeSet attrs) {
super(context, attrs, null);
+ //noinspection ConstantConditions
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();
}
private void createPreferenceView() {
- this.rangeSeekBar = new NumberRangeSeekBar(boundaries, null, context);
+ this.rangeSeekBar = new NumberRangeSeekBar(boundaries, steps, context);
this.rangeSeekBar.setNotifyWhileDragging(true);
this.rangeSeekBar.setOnRangeSeekBarChangeListener(this);
diff --git a/src/main/java/org/solovyev/android/view/widgets/AbstractRangeSeekBar.java b/src/main/java/org/solovyev/android/view/widgets/AbstractRangeSeekBar.java
index 3091ed18..60f2beeb 100644
--- a/src/main/java/org/solovyev/android/view/widgets/AbstractRangeSeekBar.java
+++ b/src/main/java/org/solovyev/android/view/widgets/AbstractRangeSeekBar.java
@@ -14,7 +14,6 @@ import android.widget.ImageView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.R;
-import org.solovyev.common.math.DiscreteNormalizer;
import org.solovyev.common.math.LinearNormalizer;
import org.solovyev.common.math.Normalizer;
import org.solovyev.common.utils.Converter;
@@ -44,7 +43,10 @@ public abstract class AbstractRangeSeekBar extends ImageView {
private final T minValue, maxValue;
@NotNull
- private final Normalizer normalizer;
+ private final Normalizer fromValueNormalizer;
+
+ @NotNull
+ private final Normalizer fromScreenNormalizer;
private double normalizedMinValue = 0d;
@@ -63,7 +65,8 @@ public abstract class AbstractRangeSeekBar extends ImageView {
*
* @param minValue The minimum 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.
*/
public AbstractRangeSeekBar(@NotNull T minValue, @NotNull T maxValue, @Nullable Integer steps, Context context) throws IllegalArgumentException {
@@ -75,13 +78,28 @@ public abstract class AbstractRangeSeekBar extends ImageView {
this.toDoubleConverter = getToDoubleConverter();
this.toTConverter = getToTConverter();
- if (steps == null) {
- normalizer = new LinearNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue));
- } else {
- normalizer = new DiscreteNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue), steps);
- }
+ fromValueNormalizer = new LinearNormalizer(toDoubleConverter.convert(minValue), toDoubleConverter.convert(maxValue));
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
@@ -180,11 +198,15 @@ public abstract class AbstractRangeSeekBar extends ImageView {
break;
case MotionEvent.ACTION_MOVE:
if (pressedThumb != null) {
+
+ double value = convertToNormalizedValue(event.getX());
+
if (Thumb.MIN.equals(pressedThumb)) {
- setNormalizedMinValue(convertToNormalizedValue(event.getX()));
+ setNormalizedMinValue(value);
} else if (Thumb.MAX.equals(pressedThumb)) {
- setNormalizedMaxValue(convertToNormalizedValue(event.getX()));
+ setNormalizedMaxValue(value);
}
+
if (notifyWhileDragging && listener != null) {
listener.rangeSeekBarValuesChanged(getSelectedMinValue(), getSelectedMaxValue(), false);
}
@@ -317,7 +339,7 @@ public abstract class AbstractRangeSeekBar extends ImageView {
*/
@SuppressWarnings("unchecked")
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 extends ImageView {
* @return The normalized double.
*/
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 extends ImageView {
* @return The converted value in screen space.
*/
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 extends ImageView {
* @return The normalized value.
*/
private double convertToNormalizedValue(float screenValue) {
- int width = getWidth();
- 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));
- }
+ return this.fromScreenNormalizer.normalize(screenValue);
}
/**
diff --git a/src/main/java/org/solovyev/common/math/DiscreteNormalizer.java b/src/main/java/org/solovyev/common/math/DiscreteNormalizer.java
index 0dff938b..14ccf0fb 100644
--- a/src/main/java/org/solovyev/common/math/DiscreteNormalizer.java
+++ b/src/main/java/org/solovyev/common/math/DiscreteNormalizer.java
@@ -1,6 +1,7 @@
package org.solovyev.common.math;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* User: serso
@@ -10,35 +11,43 @@ import org.jetbrains.annotations.NotNull;
public class DiscreteNormalizer implements Normalizer {
@NotNull
- private final LinearNormalizer linearNormalizer;
+ private final Normalizer normalizer;
private final double min;
private final double step;
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 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.min = linearNormalizer.normalize(min);
+ this.step = this.normalizer.normalize((max - min) / (steps - 1));
+ this.min = this.normalizer.normalize(min);
}
public DiscreteNormalizer(double min, double max, double step) {
assert min <= max;
assert step > 0;
- this.linearNormalizer = new LinearNormalizer(min, max);
+ this.normalizer = new LinearNormalizer(min, max);
- this.step = linearNormalizer.normalize(step);
- this.min = linearNormalizer.normalize(min);
+ this.step = normalizer.normalize(step);
+ this.min = normalizer.normalize(min);
}
@Override
public double normalize(double value) {
- double normalizedValue = linearNormalizer.normalize(value);
+ double normalizedValue = normalizer.normalize(value);
double result = min;
while (true) {
@@ -54,6 +63,6 @@ public class DiscreteNormalizer implements Normalizer {
@Override
public double denormalize(double value) {
- return linearNormalizer.denormalize(value);
+ return normalizer.denormalize(value);
}
}