*/
package jalview.gui;
+import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureColourI;
import jalview.bin.Cache;
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();
}
*/
if (ap != null)
{
- ap.paintAlignment(true, true);
+ refreshDisplay(true);
}
}
});
* save the colour, and repaint stuff
*/
fr.setColour(featureType, acg);
- ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview);
+ refreshDisplay(updateStructsAndOverview);
updateColoursTab();
}
{
fr.setColour(featureType, originalColour);
fr.setFeatureFilter(featureType, originalFilter);
- ap.paintAlignment(true, true);
+ refreshDisplay(true);
}
/**
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,
* (note this might now be an empty filter with no conditions)
*/
fr.setFeatureFilter(featureType, combined.isEmpty() ? null : combined);
- ap.paintAlignment(true, true);
+ refreshDisplay(true);
updateFiltersTab();
}
/**
- * Answers the slider value, converted to the corresponding 'true' value by
- * applying scaling
+ * Repaints alignment, structure and overview (if shown). If there is a
+ * complementary view which is showing this view's features, then also
+ * repaints that.
*
- * @return
+ * @param updateStructsAndOverview
*/
- float getSliderValue()
+ void refreshDisplay(boolean updateStructsAndOverview)
{
- 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())
+ ap.paintAlignment(true, updateStructsAndOverview);
+ AlignViewportI complement = ap.getAlignViewport().getCodingComplement();
+ if (complement != null && complement.isShowComplementFeatures())
{
- f = min;
+ AlignFrame af2 = Desktop.getAlignFrameFor(complement);
+ af2.alignPanel.paintAlignment(true, updateStructsAndOverview);
}
- 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);
}
}