@SuppressWarnings("serial")
public class AnnotationColourChooser extends AnnotationRowFilter
{
- private static final int ONETHOUSAND = 1000;
-
private ColourSchemeI oldcs;
private JButton defColours;
"error.implementation_error_dont_know_about_threshold_setting"));
}
thresholdIsMin.setSelected(acg.isThresholdIsMinMax());
- thresholdValue.setText("" + acg.getAnnotationThreshold());
+ thresholdValue
+ .setText(String.valueOf(acg.getAnnotationThreshold()));
}
jbInit();
{
updateView();
}
- getCurrentAnnotation().threshold.value = slider.getValue() / 1000f;
+ getCurrentAnnotation().threshold.value = getSliderValue();
propagateSeqAssociatedThreshold(updateAllAnnotation,
getCurrentAnnotation());
ap.paintAlignment(false, false);
thresholdValue.setEnabled(true);
thresholdIsMin.setEnabled(!useOriginalColours.isSelected());
+ final AlignmentAnnotation currentAnnotation = getCurrentAnnotation();
if (selectedThresholdItem == AnnotationColourGradient.NO_THRESHOLD)
{
slider.setEnabled(false);
thresholdIsMin.setEnabled(false);
}
else if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD
- && getCurrentAnnotation().threshold == null)
+ && currentAnnotation.threshold == null)
{
- getCurrentAnnotation().setThreshold(new GraphLine(
- (getCurrentAnnotation().graphMax
- - getCurrentAnnotation().graphMin) / 2f,
+ currentAnnotation.setThreshold(new GraphLine(
+ (currentAnnotation.graphMax - currentAnnotation.graphMin)
+ / 2f,
"Threshold", Color.black));
}
if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD)
{
adjusting = true;
- float range = getCurrentAnnotation().graphMax * ONETHOUSAND
- - getCurrentAnnotation().graphMin * ONETHOUSAND;
-
- slider.setMinimum(
- (int) (getCurrentAnnotation().graphMin * ONETHOUSAND));
- slider.setMaximum(
- (int) (getCurrentAnnotation().graphMax * ONETHOUSAND));
- slider.setValue(
- (int) (getCurrentAnnotation().threshold.value * ONETHOUSAND));
- thresholdValue.setText(getCurrentAnnotation().threshold.value + "");
- slider.setMajorTickSpacing((int) (range / 10f));
+ setSliderModel(currentAnnotation.graphMin, currentAnnotation.graphMax,
+ currentAnnotation.threshold.value);
slider.setEnabled(true);
+
+ setThresholdValueText();
thresholdValue.setEnabled(true);
adjusting = false;
}
- colorAlignmentContaining(getCurrentAnnotation(), selectedThresholdItem);
+ colorAlignmentContaining(currentAnnotation, selectedThresholdItem);
ap.alignmentChanged();
}
package jalview.gui;
+import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.HiddenColumns;
import jalview.io.cache.JvCacheableInputBox;
import jalview.schemes.AnnotationColourGradient;
{
if (slider.isEnabled())
{
- getCurrentAnnotation().threshold.value = slider.getValue() / 1000f;
+ getCurrentAnnotation().threshold.value = getSliderValue();
updateView();
propagateSeqAssociatedThreshold(updateAllAnnotation,
getCurrentAnnotation());
thresholdValue.setEnabled(true);
percentThreshold.setEnabled(true);
+ final AlignmentAnnotation currentAnnotation = getCurrentAnnotation();
if (selectedThresholdItem == AnnotationColourGradient.NO_THRESHOLD)
{
slider.setEnabled(false);
}
else if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD)
{
- if (getCurrentAnnotation().threshold == null)
+ if (currentAnnotation.threshold == null)
{
- getCurrentAnnotation().setThreshold(new jalview.datamodel.GraphLine(
- (getCurrentAnnotation().graphMax
- - getCurrentAnnotation().graphMin) / 2f,
+ currentAnnotation.setThreshold(new jalview.datamodel.GraphLine(
+ (currentAnnotation.graphMax
+ - currentAnnotation.graphMin) / 2f,
"Threshold", Color.black));
}
adjusting = true;
- float range = getCurrentAnnotation().graphMax * 1000
- - getCurrentAnnotation().graphMin * 1000;
- slider.setMinimum((int) (getCurrentAnnotation().graphMin * 1000));
- slider.setMaximum((int) (getCurrentAnnotation().graphMax * 1000));
- slider.setValue(
- (int) (getCurrentAnnotation().threshold.value * 1000));
+ setSliderModel(currentAnnotation.graphMin,
+ currentAnnotation.graphMax,
+ currentAnnotation.threshold.value);
setThresholdValueText();
- slider.setMajorTickSpacing((int) (range / 10f));
slider.setEnabled(true);
thresholdValue.setEnabled(true);
adjusting = false;
// build filter params
filterParams.setThresholdType(
AnnotationFilterParameter.ThresholdType.NO_THRESHOLD);
- if (getCurrentAnnotation().isQuantitative())
+ if (currentAnnotation.isQuantitative())
{
filterParams
- .setThresholdValue(getCurrentAnnotation().threshold.value);
+ .setThresholdValue(currentAnnotation.threshold.value);
if (selectedThresholdItem == AnnotationColourGradient.ABOVE_THRESHOLD)
{
// adding them to the selection
av.showAllHiddenColumns();
av.getColumnSelection().filterAnnotations(
- getCurrentAnnotation().annotations, filterParams);
+ currentAnnotation.annotations, filterParams);
boolean hideCols = getActionOption() == ACTION_OPTION_HIDE;
if (hideCols)
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.math.BigDecimal;
+import java.math.MathContext;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import javax.swing.JComboBox;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
-import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@SuppressWarnings("serial")
public abstract class AnnotationRowFilter extends JPanel
{
+ private static final String TWO_DP = "%.2f";
+
+ private final static MathContext FOUR_SIG_FIG = new MathContext(4);
+
protected AlignViewport av;
protected AlignmentPanel ap;
protected JCheckBox percentThreshold = new JCheckBox();
- protected JSlider slider = new JSlider();
+ protected Slider slider;
protected JTextField thresholdValue = new JTextField(20);
{
this.av = viewport;
this.ap = alignPanel;
+ this.slider = new Slider(0f, 100f, 50f);
+
thresholdValue.addFocusListener(new FocusAdapter()
{
@Override
adjusting = true;
if (percentThreshold.isSelected())
{
- thresholdValue.setText("" + (slider.getValue() - slider.getMinimum())
- * 100f / (slider.getMaximum() - slider.getMinimum()));
+ thresholdValue
+ .setText(String.format(TWO_DP, getSliderPercentageValue()));
}
else
{
- thresholdValue.setText((slider.getValue() / 1000f) + "");
+ /*
+ * round to 4 significant digits without trailing zeroes
+ */
+ float f = getSliderValue();
+ BigDecimal formatted = new BigDecimal(f).round(FOUR_SIG_FIG)
+ .stripTrailingZeros();
+ thresholdValue.setText(formatted.toPlainString());
}
adjusting = oldadj;
}
+ /**
+ * Answers the value of the slider position (descaled to 'true' value)
+ *
+ * @return
+ */
+ protected float getSliderValue()
+ {
+ return slider.getSliderValue();
+ }
+
+ /**
+ * Sets the slider value (scaled from the true value to the slider range)
+ *
+ * @param value
+ */
+ protected void setSliderValue(float value)
+ {
+ slider.setSliderValue(value);
+ }
+ /**
+ * Answers the value of the slider position as a percentage between minimum and
+ * maximum of its range
+ *
+ * @return
+ */
+ protected float getSliderPercentageValue()
+ {
+ return slider.getSliderPercentageValue();
+ }
+
+ /**
+ * Sets the slider position for a given percentage value of its min-max range
+ *
+ * @param pct
+ */
+ protected void setSliderPercentageValue(float pct)
+ {
+ slider.setSliderPercentageValue(pct);
+ }
+
protected void addSliderMouseListeners()
{
updateView();
}
+ /**
+ * Updates the slider position, and the display, for an update in the slider's
+ * text input field
+ */
protected void thresholdValue_actionPerformed()
{
try
float f = Float.parseFloat(thresholdValue.getText());
if (percentThreshold.isSelected())
{
- slider.setValue(slider.getMinimum() + ((int) ((f / 100f)
- * (slider.getMaximum() - slider.getMinimum()))));
+ setSliderPercentageValue(f);
}
else
{
- slider.setValue((int) (f * 1000));
+ setSliderValue(f);
}
updateView();
} catch (NumberFormatException ex)
valueChanged(true);
}
}
+
+ /**
+ * Sets the min-max range and current value of the slider, with rescaling from
+ * true values to slider range as required
+ *
+ * @param min
+ * @param max
+ * @param value
+ */
+ protected void setSliderModel(float min, float max, float value)
+ {
+ slider.setSliderModel(min, max, value);
+
+ /*
+ * tick mark every 10th position
+ */
+ slider.setMajorTickSpacing(
+ (slider.getMaximum() - slider.getMinimum()) / 10);
+ }
}
JPanel groupPanel;
- JSlider transparency = new JSlider();
+ JSlider transparency;
/*
* when true, constructor is still executing - so ignore UI events
// save transparency for restore on Cancel
originalTransparency = fr.getTransparency();
int originalTransparencyAsPercent = (int) (originalTransparency * 100);
- transparency.setMaximum(100 - originalTransparencyAsPercent);
+ transparency = new JSlider(0, 70, 100 - originalTransparencyAsPercent);
originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
}
});
- transparency.setMaximum(70);
transparency.setToolTipText(
MessageManager.getString("label.transparency_tip"));
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.math.BigDecimal;
+import java.math.MathContext;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
-import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
*/
public class FeatureTypeSettings extends JalviewDialog
{
+ private final static MathContext FOUR_SIG_FIG = new MathContext(4);
+
private final static String LABEL_18N = MessageManager
.getString("label.label");
private float max;
/*
- * scale factor for conversion between absolute min-max and slider
- * slider value is true value * scale factor
- */
- 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:
* simple colour, by category (text), or graduated
*/
private JComboBox<Object> threshold = new JComboBox<>();
- private JSlider slider = new JSlider();
+ private Slider slider;
private JTextField thresholdValue = new JTextField(20);
* valid options are offered in the combo box)
* offset slider to have only non-negative values if necessary (JAL-2983)
*/
- 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));
+ slider.setSliderModel(min, max, min);
+ slider.setMajorTickSpacing(
+ (int) ((slider.getMaximum() - slider.getMinimum()) / 10f));
threshline = new GraphLine((max - min) / 2f, "Threshold",
Color.black);
fc.isAboveThreshold() ? ABOVE_THRESHOLD_OPTION
: BELOW_THRESHOLD_OPTION);
slider.setEnabled(true);
- setSliderValue(fc.getThreshold());
- thresholdValue.setText(String.valueOf(fc.getThreshold()));
+ slider.setSliderValue(fc.getThreshold());
+ setThresholdValueText(fc.getThreshold());
thresholdValue.setEnabled(true);
thresholdIsMin.setEnabled(true);
}
thresholdValue_actionPerformed();
}
});
+ slider = new Slider(0f, 100f, 50f);
slider.setPaintLabels(false);
slider.setPaintTicks(true);
slider.setBackground(Color.white);
{
if (!adjusting)
{
- thresholdValue
- .setText(String.format("%.3f", getSliderValue()));
+ setThresholdValueText(slider.getSliderValue());
thresholdValue.setBackground(Color.white); // to reset red for invalid
sliderValueChanged();
}
float f = Float.parseFloat(thresholdValue.getText());
f = Float.max(f, this.min);
f = Float.min(f, this.max);
- thresholdValue.setText(String.valueOf(f));
- setSliderValue(f * sliderScaleFactor);
+ setThresholdValueText(f);
+ slider.setSliderValue(f);
threshline.value = f;
thresholdValue.setBackground(Color.white); // ok
adjusting = false;
}
/**
+ * Sets the text field for threshold value, rounded to four significant figures
+ *
+ * @param f
+ */
+ void setThresholdValueText(float f)
+ {
+ BigDecimal formatted = new BigDecimal(f).round(FOUR_SIG_FIG)
+ .stripTrailingZeros();
+ thresholdValue.setText(formatted.toPlainString());
+ }
+
+ /**
* Action on change of threshold slider value. This may be done interactively
* (by moving the slider), or programmatically (to update the slider after
* manual input of a threshold value).
*/
protected void sliderValueChanged()
{
- threshline.value = getSliderValue();
+ threshline.value = slider.getSliderValue();
/*
* repaint alignment, but not Overview or structure,
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);
- }
}
--- /dev/null
+package jalview.gui;
+
+import javax.swing.JSlider;
+
+/**
+ * A modified {@code javax.swing.JSlider} that
+ * <ul>
+ * <li>supports float valued numbers (by scaling up integer values)</li>
+ * <li>rescales 'true' value range to avoid negative values, as these are not
+ * rendered correctly by some look and feel libraries</li>
+ * </ul>
+ *
+ * @author gmcarstairs
+ */
+@SuppressWarnings("serial")
+public class Slider extends JSlider
+{
+ /*
+ * 'true' value corresponding to zero on the slider
+ */
+ private float trueMin;
+
+ /*
+ * 'true' value corresponding to slider maximum
+ */
+ private float trueMax;
+
+ /*
+ * scaleFactor applied to true value range to give a
+ * slider range of 0 - 100
+ */
+ private int sliderScaleFactor;
+
+ /**
+ * Constructor that rescales min - max to 0 - 100 for the slider
+ *
+ * @param min
+ * @param max
+ * @param value
+ */
+ public Slider(float min, float max, float value)
+ {
+ super();
+ setSliderModel(min, max, value);
+ }
+
+ /**
+ * Sets the min-max range and current value of the slider, with rescaling from
+ * true values to slider range as required
+ *
+ * @param min
+ * @param max
+ * @param value
+ */
+ public void setSliderModel(float min, float max, float value)
+ {
+ trueMin = min;
+ trueMax = max;
+ setMinimum(0);
+ sliderScaleFactor = (int) (100f / (max - min));
+ int sliderMax = (int) ((max - min) * sliderScaleFactor);
+ setMaximum(sliderMax);
+ setSliderValue(value);
+ }
+
+ /**
+ * Answers the value of the slider position (descaled to 'true' value)
+ *
+ * @return
+ */
+ public float getSliderValue()
+ {
+ /*
+ * convert slider max to 'true max' in case of rounding errors
+ */
+ int value = getValue();
+ return value == getMaximum() ? trueMax
+ : value / (float) sliderScaleFactor + trueMin;
+ }
+
+ /**
+ * Sets the slider value (scaled from the true value to the slider range)
+ *
+ * @param value
+ */
+ public void setSliderValue(float value)
+ {
+ setValue((int) ((value - trueMin) * sliderScaleFactor));
+ }
+
+ /**
+ * Answers the value of the slider position as a percentage between minimum and
+ * maximum of its range
+ *
+ * @return
+ */
+ public float getSliderPercentageValue()
+ {
+ return (getValue() - getMinimum()) * 100f
+ / (getMaximum() - getMinimum());
+ }
+
+ /**
+ * Sets the slider position for a given percentage value of its min-max range
+ *
+ * @param pct
+ */
+ public void setSliderPercentageValue(float pct)
+ {
+ float pc = pct / 100f * getMaximum();
+ setValue((int) pc);
+ }
+}