/*
* scale factor for conversion between absolute min-max and slider
+ * slider value is true value * scale factor
*/
- private float scaleFactor;
+ private float sliderScaleFactor;
+
+ /*
+ * value to subtract from slider value before conversion;
+ * normally zero, but >0 if min is negative
+ * true value = (slider value - offset) / scale factor
+ * slider value = true value * scale factor + offset
+ */
+ private int sliderOffset;
/*
* radio button group, to select what to colour by:
* update min-max scaling if there is a range to work with,
* else disable the widgets (this shouldn't happen if only
* valid options are offered in the combo box)
+ * offset slider to have only non-negative values if necessary (JAL-2983)
*/
- scaleFactor = (max == min) ? 1f : 100f / (max - min);
- float range = (max - min) * scaleFactor;
- slider.setMinimum((int) (min * scaleFactor));
- slider.setMaximum((int) (max * scaleFactor));
+ sliderScaleFactor = (max == min) ? 1f : 100f / (max - min);
+ float range = (max - min) * sliderScaleFactor;
+ int minimum = (int) (min * sliderScaleFactor);
+ int maximum = (int) (max * sliderScaleFactor);
+ sliderOffset = minimum < 0f ? -minimum : 0;
+ slider.setMinimum(minimum + sliderOffset);
+ slider.setMaximum(maximum + sliderOffset);
slider.setMajorTickSpacing((int) (range / 10f));
threshline = new GraphLine((max - min) / 2f, "Threshold",
fc.isAboveThreshold() ? ABOVE_THRESHOLD_OPTION
: BELOW_THRESHOLD_OPTION);
slider.setEnabled(true);
- slider.setValue((int) (fc.getThreshold() * scaleFactor));
+ setSliderValue(fc.getThreshold());
thresholdValue.setText(String.valueOf(fc.getThreshold()));
thresholdValue.setEnabled(true);
thresholdIsMin.setEnabled(true);
if (!adjusting)
{
thresholdValue
- .setText(String.valueOf(slider.getValue() / scaleFactor));
+ .setText(String.format("%.3f", getSliderValue()));
thresholdValue.setBackground(Color.white); // to reset red for invalid
sliderValueChanged();
}
f = Float.max(f, this.min);
f = Float.min(f, this.max);
thresholdValue.setText(String.valueOf(f));
- slider.setValue((int) (f * scaleFactor));
+ setSliderValue(f * sliderScaleFactor);
threshline.value = f;
thresholdValue.setBackground(Color.white); // ok
adjusting = false;
*/
protected void sliderValueChanged()
{
- threshline.value = getRoundedSliderValue();
+ threshline.value = getSliderValue();
/*
* repaint alignment, but not Overview or structure,
colourChanged(false);
}
- /**
- * Converts the slider value to its absolute value by dividing by the
- * scaleFactor. Rounding errors are squashed by forcing min/max of slider
- * range to the actual min/max of feature score range
- *
- * @return
- */
- private float getRoundedSliderValue()
- {
- int value = slider.getValue();
- float f = value == slider.getMaximum() ? max
- : (value == slider.getMinimum() ? min : value / scaleFactor);
- return f;
- }
-
void addActionListener(ActionListener listener)
{
if (featureSettings != null)
updateFiltersTab();
}
+
+ /**
+ * Answers the slider value, converted to the corresponding 'true' value by
+ * applying scaling
+ *
+ * @return
+ */
+ float getSliderValue()
+ {
+ int value = slider.getValue();
+ float f = (value - sliderOffset) / sliderScaleFactor;
+
+ /*
+ * avoid rounding errors at min/max of range
+ */
+ if (value == slider.getMaximum())
+ {
+ f = max;
+ }
+ else if (value == slider.getMinimum())
+ {
+ f = min;
+ }
+ return f;
+ }
+
+ /**
+ * Sets the slider value, converted from the corresponding 'true' value by
+ * applying scaling
+ *
+ * @param f
+ */
+ void setSliderValue(float f)
+ {
+ float v = f * sliderScaleFactor + sliderOffset;
+ slider.setValue((int) v);
+ }
}