Merge branch 'develop' into bug/JAL-2346annotationChoice
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 14 Feb 2017 12:34:54 +0000 (12:34 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 14 Feb 2017 12:34:54 +0000 (12:34 +0000)
Conflicts:
src/jalview/appletgui/AnnotationColourChooser.java
src/jalview/gui/AnnotationRowFilter.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/PopupMenu.java
src/jalview/schemes/AnnotationColourGradient.java

1  2 
src/jalview/appletgui/AnnotationColourChooser.java
src/jalview/gui/AnnotationColourChooser.java
src/jalview/gui/AnnotationRowFilter.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/PopupMenu.java
src/jalview/schemes/AnnotationColourGradient.java

   */
  package jalview.appletgui;
  
+ import jalview.datamodel.AlignmentAnnotation;
+ import jalview.datamodel.SequenceGroup;
+ import jalview.schemes.AnnotationColourGradient;
+ import jalview.schemes.ColourSchemeI;
+ import jalview.util.MessageManager;
  import java.awt.BorderLayout;
  import java.awt.Button;
  import java.awt.Checkbox;
@@@ -40,16 -46,9 +46,10 @@@ import java.awt.event.ItemEvent
  import java.awt.event.ItemListener;
  import java.awt.event.MouseEvent;
  import java.awt.event.MouseListener;
 -import java.util.Hashtable;
 +import java.util.HashMap;
 +import java.util.Map;
  import java.util.Vector;
  
- import jalview.datamodel.AlignmentAnnotation;
- import jalview.datamodel.SequenceGroup;
- import jalview.schemes.AnnotationColourGradient;
- import jalview.schemes.ColourSchemeI;
- import jalview.util.MessageManager;
  public class AnnotationColourChooser extends Panel implements
          ActionListener, AdjustmentListener, ItemListener, MouseListener
  {
  
    ColourSchemeI oldcs;
  
 -  Hashtable oldgroupColours;
 +  Map<SequenceGroup, ColourSchemeI> oldgroupColours;
  
 -  jalview.datamodel.AlignmentAnnotation currentAnnotation;
 +  /*
 +   * map from annotation to its menu item display label
 +   * - so we know which item to pre-select on restore
 +   */
 +  private Map<AlignmentAnnotation, String> annotationLabels;
 +
 +  AlignmentAnnotation currentAnnotation;
  
    boolean adjusting = false;
  
      oldcs = av.getGlobalColourScheme();
      if (av.getAlignment().getGroups() != null)
      {
 -      oldgroupColours = new Hashtable();
 +      oldgroupColours = new HashMap<SequenceGroup, ColourSchemeI>();
        for (SequenceGroup sg : ap.av.getAlignment().getGroups())
        {
-         if (sg.cs != null)
-         {
-           oldgroupColours.put(sg, sg.cs);
-         }
 -        if (sg.getColourScheme() != null)
 -        {
 -          oldgroupColours.put(sg, sg.getColourScheme());
 -        }
 -        else
 -        {
 -          oldgroupColours.put(sg, "null");
 -        }
++        oldgroupColours.put(sg, sg.getColourScheme());
        }
      }
      this.av = av;
        // seqAssociated.setState(acg.isSeqAssociated());
      }
  
 -    Vector<String> list = new Vector<String>();
 -    int index = 1;
 -    for (int i = 0; i < anns.length; i++)
 -    {
 -      String label = anns[i].label;
 -      if (anns[i].sequenceRef != null)
 -      {
 -        label = label + "_" + anns[i].sequenceRef.getName();
 -      }
 -      if (!list.contains(label))
 -      {
 -        list.addElement(label);
 -      }
 -      else
 -      {
 -        list.addElement(label + "_" + (index++));
 -      }
 -    }
 +    Vector<String> list = getAnnotationItems();
  
      for (int i = 0; i < list.size(); i++)
      {
      if (oldcs instanceof AnnotationColourGradient)
      {
        AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
 -      annotations.select(acg.getAnnotation());
 +      String label = annotationLabels.get(acg.getAnnotation());
 +      annotations.select(label);
        switch (acg.getAboveThreshold())
        {
        case AnnotationColourGradient.NO_THRESHOLD:
                  MessageManager
                          .getString("error.implementation_error_dont_know_threshold_annotationcolourgradient"));
        }
 -      thresholdIsMin.setState(acg.thresholdIsMinMax);
 +      thresholdIsMin.setState(acg.isThresholdIsMinMax());
        thresholdValue.setText("" + acg.getAnnotationThreshold());
      }
  
      validate();
    }
  
 +  /**
 +   * Builds and returns a list of menu items (display text) for choice of
 +   * annotation. Also builds a map between annotations and their display labels.
 +   * 
 +   * @return
 +   */
 +  protected Vector<String> getAnnotationItems()
 +  {
 +    // TODO remove duplication with gui.AnnotationRowFilter
 +    // TODO add 'per sequence only' option / parameter
 +
 +    annotationLabels = new HashMap<AlignmentAnnotation, String>();
 +    Vector<String> list = new Vector<String>();
 +    AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
 +    if (anns == null)
 +    {
 +      return list;
 +    }
 +    int index = 1;
 +    for (int i = 0; i < anns.length; i++)
 +    {
 +      String label = anns[i].label;
 +      if (anns[i].sequenceRef != null)
 +      {
 +        /*
 +         * be helpful and include sequence id in label for
 +         * sequence-associated annotation (JAL-2236)
 +         */
 +        label = label + "_" + anns[i].sequenceRef.getName();
 +      }
 +      if (!list.contains(label))
 +      {
 +        list.addElement(label);
 +        annotationLabels.put(anns[i], label);
 +      }
 +      else
 +      {
 +        label = label + "_" + (index++);
 +        list.addElement(label);
 +        annotationLabels.put(anns[i], label);
 +      }
 +    }
 +    return list;
 +  }
 +
    private void setDefaultMinMax()
    {
      minColour.setBackground(av.applet.getDefaultColourParameter(
      AnnotationColourGradient acg = null;
      if (currentColours.getState())
      {
-       acg = new AnnotationColourGradient(currentAnnotation,
-               av.getGlobalColourScheme(), aboveThreshold);
      }
      else
      {
        acg.setPredefinedColours(true);
      }
  
 -    acg.thresholdIsMinMax = thresholdIsMin.getState();
 +    acg.setThresholdIsMinMax(thresholdIsMin.getState());
  
      av.setGlobalColourScheme(acg);
  
      {
        for (SequenceGroup sg : ap.av.getAlignment().getGroups())
        {
-         if (sg.cs == null)
 -
+         if (sg.getColourScheme() == null)
          {
            continue;
          }
  
          if (currentColours.getState())
          {
-           sg.cs = new AnnotationColourGradient(currentAnnotation, sg.cs,
-                   aboveThreshold);
+           sg.setColourScheme(new AnnotationColourGradient(
+                   currentAnnotation, sg.getColourScheme(), aboveThreshold));
          }
          else
          {
-           sg.cs = new AnnotationColourGradient(currentAnnotation,
-                   minColour.getBackground(), maxColour.getBackground(),
-                   aboveThreshold);
+           sg.setColourScheme(new AnnotationColourGradient(
+                   currentAnnotation, minColour.getBackground(), maxColour
+                           .getBackground(), aboveThreshold));
          }
 -
        }
      }
  
      {
        for (SequenceGroup sg : ap.av.getAlignment().getGroups())
        {
-         sg.cs = oldgroupColours.get(sg);
 -        Object cs = oldgroupColours.get(sg);
 -        if (cs instanceof ColourSchemeI)
 -        {
 -          sg.setColourScheme((ColourSchemeI) cs);
 -        }
 -        else
 -        {
 -          // probably the "null" string we set it to if it was null originally.
 -          sg.setColourScheme(null);
 -        }
++        sg.setColourScheme(oldgroupColours.get(sg));
        }
      }
      ap.paintAlignment(true);
--
    }
  
    @Override
@@@ -21,8 -21,6 +21,8 @@@
  package jalview.gui;
  
  import jalview.bin.Cache;
 +import jalview.datamodel.AlignmentAnnotation;
 +import jalview.datamodel.GraphLine;
  import jalview.datamodel.SequenceGroup;
  import jalview.schemes.AnnotationColourGradient;
  import jalview.schemes.ColourSchemeI;
@@@ -37,11 -35,9 +37,11 @@@ import java.awt.event.ActionListener
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  import java.util.Hashtable;
 +import java.util.Vector;
  
  import javax.swing.BorderFactory;
  import javax.swing.JButton;
 +import javax.swing.JCheckBox;
  import javax.swing.JColorChooser;
  import javax.swing.JComboBox;
  import javax.swing.JInternalFrame;
@@@ -53,21 -49,27 +53,21 @@@ import net.miginfocom.swing.MigLayout
  @SuppressWarnings("serial")
  public class AnnotationColourChooser extends AnnotationRowFilter
  {
 +  private static final int ONETHOUSAND = 1000;
  
 -  ColourSchemeI oldcs;
 +  private ColourSchemeI oldcs;
  
 -  Hashtable<SequenceGroup, ColourSchemeI> oldgroupColours;
 +  private JButton defColours;
  
 -  /**
 -   * enabled if the user is dragging the slider - try to keep updates to a
 -   * minimun
 -   */
 +  private Hashtable<SequenceGroup, ColourSchemeI> oldgroupColours;
  
 -  JComboBox<String> annotations;
 +  private JCheckBox currentColours = new JCheckBox();
  
 -  JButton defColours = new JButton();
 +  private JPanel minColour = new JPanel();
  
 -  JPanel jPanel1 = new JPanel();
 +  private JPanel maxColour = new JPanel();
  
 -  JPanel jPanel2 = new JPanel();
 -
 -  BorderLayout borderLayout1 = new BorderLayout();
 -
 -  private JComboBox<String> threshold = new JComboBox<String>();
 +  private JCheckBox thresholdIsMin = new JCheckBox();
  
    public AnnotationColourChooser(AlignViewport av, final AlignmentPanel ap)
    {
@@@ -78,9 -80,9 +78,9 @@@
        oldgroupColours = new Hashtable<SequenceGroup, ColourSchemeI>();
        for (SequenceGroup sg : ap.av.getAlignment().getGroups())
        {
-         if (sg.cs != null)
+         if (sg.getColourScheme() != null)
          {
-           oldgroupColours.put(sg, sg.cs);
+           oldgroupColours.put(sg, sg.getColourScheme());
          }
        }
      }
        seqAssociated.setSelected(acg.isSeqAssociated());
  
      }
 -    annotations = new JComboBox<String>(
 -            getAnnotationItems(seqAssociated.isSelected()));
 +    Vector<String> annotItems = getAnnotationItems(seqAssociated
 +            .isSelected());
 +    annotations = new JComboBox<String>(annotItems);
  
      populateThresholdComboBox(threshold);
  
      if (oldcs instanceof AnnotationColourGradient)
      {
        AnnotationColourGradient acg = (AnnotationColourGradient) oldcs;
 -      annotations.setSelectedItem(acg.getAnnotation());
 +      String label = getAnnotationMenuLabel(acg.getAnnotation());
 +      annotations.setSelectedItem(label);
        switch (acg.getAboveThreshold())
        {
        case AnnotationColourGradient.NO_THRESHOLD:
                  MessageManager
                          .getString("error.implementation_error_dont_know_about_threshold_setting"));
        }
 -      thresholdIsMin.setSelected(acg.thresholdIsMinMax);
 +      thresholdIsMin.setSelected(acg.isThresholdIsMinMax());
        thresholdValue.setText("" + acg.getAnnotationThreshold());
      }
  
 -    try
 -    {
 -      jbInit();
 -    } catch (Exception ex)
 -    {
 -    }
 +    jbInit();
      adjusting = false;
  
      updateView();
      frame.pack();
    }
  
 -  public AnnotationColourChooser()
 +  @Override
 +  protected void jbInit()
    {
 -    try
 -    {
 -      jbInit();
 -    } catch (Exception ex)
 -    {
 -      ex.printStackTrace();
 -    }
 -  }
 +    super.jbInit();
  
 -  private void jbInit() throws Exception
 -  {
      minColour.setFont(JvSwingUtils.getLabelFont());
      minColour.setBorder(BorderFactory.createEtchedBorder());
      minColour.setPreferredSize(new Dimension(40, 20));
          }
        }
      });
 -    ok.setOpaque(false);
 -    ok.setText(MessageManager.getString("action.ok"));
 -    ok.addActionListener(new ActionListener()
 -    {
 -      @Override
 -      public void actionPerformed(ActionEvent e)
 -      {
 -        ok_actionPerformed();
 -      }
 -    });
 -    cancel.setOpaque(false);
 -    cancel.setText(MessageManager.getString("action.cancel"));
 -    cancel.addActionListener(new ActionListener()
 -    {
 -      @Override
 -      public void actionPerformed(ActionEvent e)
 -      {
 -        cancel_actionPerformed();
 -      }
 -    });
 +
 +    defColours = new JButton();
      defColours.setOpaque(false);
      defColours.setText(MessageManager.getString("action.set_defaults"));
      defColours.setToolTipText(MessageManager
        }
      });
  
 -    annotations.addActionListener(new ActionListener()
 -    {
 -      @Override
 -      public void actionPerformed(ActionEvent e)
 -      {
 -        annotations_actionPerformed();
 -      }
 -    });
 -    getThreshold().addActionListener(new ActionListener()
 -    {
 -      @Override
 -      public void actionPerformed(ActionEvent e)
 -      {
 -        threshold_actionPerformed();
 -      }
 -    });
 -    thresholdValue.addActionListener(new ActionListener()
 -    {
 -      @Override
 -      public void actionPerformed(ActionEvent e)
 -      {
 -        thresholdValue_actionPerformed();
 -      }
 -    });
 -    slider.setPaintLabels(false);
 -    slider.setPaintTicks(true);
 -    slider.setBackground(Color.white);
 -    slider.setEnabled(false);
 -    slider.setOpaque(false);
 -    slider.setPreferredSize(new Dimension(100, 32));
 -    thresholdValue.setEnabled(false);
 -    thresholdValue.setColumns(7);
      currentColours.setFont(JvSwingUtils.getLabelFont());
      currentColours.setOpaque(false);
      currentColours.setText(MessageManager
        }
      });
  
 -    this.setLayout(borderLayout1);
 +    this.setLayout(new BorderLayout());
 +    JPanel jPanel1 = new JPanel();
 +    JPanel jPanel2 = new JPanel();
      jPanel2.setLayout(new MigLayout("", "[left][center][right]", "[][][]"));
      jPanel1.setBackground(Color.white);
      jPanel2.setBackground(Color.white);
  
        for (SequenceGroup sg : ap.av.getAlignment().getGroups())
        {
-         sg.cs = oldgroupColours.get(sg);
+         sg.setColourScheme(oldgroupColours.get(sg));
        }
      }
    }
      }
    }
  
 -  public JComboBox<String> getThreshold()
 -  {
 -    return threshold;
 -  }
 -
 -  public void setThreshold(JComboBox<String> threshold)
 -  {
 -    this.threshold = threshold;
 -  }
 -
    public void currentColours_actionPerformed()
    {
      if (currentColours.isSelected())
      {
        getCurrentAnnotation()
                .setThreshold(
 -                      new jalview.datamodel.GraphLine(
 +                      new GraphLine(
                                (getCurrentAnnotation().graphMax - getCurrentAnnotation().graphMin) / 2f,
                                "Threshold", Color.black));
      }
      if (selectedThresholdItem != AnnotationColourGradient.NO_THRESHOLD)
      {
        adjusting = true;
 -      float range = getCurrentAnnotation().graphMax * 1000
 -              - getCurrentAnnotation().graphMin * 1000;
 +      float range = getCurrentAnnotation().graphMax * ONETHOUSAND
 +              - getCurrentAnnotation().graphMin * ONETHOUSAND;
  
 -      slider.setMinimum((int) (getCurrentAnnotation().graphMin * 1000));
 -      slider.setMaximum((int) (getCurrentAnnotation().graphMax * 1000));
 -      slider.setValue((int) (getCurrentAnnotation().threshold.value * 1000));
 +      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));
        slider.setEnabled(true);
        thresholdValue.setEnabled(true);
        adjusting = false;
      }
 -    colorAlignmContaining(getCurrentAnnotation(), selectedThresholdItem);
 +    colorAlignmentContaining(getCurrentAnnotation(), selectedThresholdItem);
  
      ap.alignmentChanged();
      // ensure all associated views (overviews, structures, etc) are notified of
      ap.paintAlignment(true);
    }
  
 +  protected boolean colorAlignmentContaining(AlignmentAnnotation currentAnn, int selectedThresholdOption)
 +  {
 +  
 +    AnnotationColourGradient acg = null;
 +    if (currentColours.isSelected())
 +    {
 +      acg = new AnnotationColourGradient(currentAnn,
 +              av.getGlobalColourScheme(), selectedThresholdOption);
 +    }
 +    else
 +    {
 +      acg = new AnnotationColourGradient(currentAnn,
 +              minColour.getBackground(), maxColour.getBackground(),
 +              selectedThresholdOption);
 +    }
 +    acg.setSeqAssociated(seqAssociated.isSelected());
 +  
 +    if (currentAnn.graphMin == 0f && currentAnn.graphMax == 0f)
 +    {
 +      acg.setPredefinedColours(true);
 +    }
 +  
 +    acg.setThresholdIsMinMax(thresholdIsMin.isSelected());
 +  
 +    av.setGlobalColourScheme(acg);
 +  
 +    if (av.getAlignment().getGroups() != null)
 +    {
 +  
 +      for (SequenceGroup sg : ap.av.getAlignment().getGroups())
 +      {
 +        if (sg.cs == null)
 +        {
 +          continue;
 +        }
 +  
 +        if (currentColours.isSelected())
 +        {
-           sg.cs = new AnnotationColourGradient(currentAnn, sg.cs,
-                   selectedThresholdOption);
++          sg.setColourScheme(new AnnotationColourGradient(currentAnn, sg
++                  .getColourScheme(), selectedThresholdOption));
 +          ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
 +                  .isSelected());
 +        }
 +        else
 +        {
-           sg.cs = new AnnotationColourGradient(currentAnn,
++          sg.setColourScheme(new AnnotationColourGradient(currentAnn,
 +                  minColour.getBackground(), maxColour.getBackground(),
-                   selectedThresholdOption);
++                  selectedThresholdOption));
 +          ((AnnotationColourGradient) sg.cs).setSeqAssociated(seqAssociated
 +                  .isSelected());
 +        }
 +      }
 +    }
 +    return false;
 +  }
 +
  }
@@@ -22,21 -22,12 +22,21 @@@ package jalview.gui
  
  import jalview.datamodel.AlignmentAnnotation;
  import jalview.datamodel.GraphLine;
  import jalview.schemes.AnnotationColourGradient;
  import jalview.util.MessageManager;
  
 +import java.awt.Color;
 +import java.awt.Dimension;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +import java.awt.event.FocusAdapter;
 +import java.awt.event.FocusEvent;
 +import java.awt.event.ItemEvent;
 +import java.awt.event.ItemListener;
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
 +import java.util.HashMap;
 +import java.util.Map;
  import java.util.Vector;
  
  import javax.swing.JButton;
@@@ -58,10 -49,22 +58,18 @@@ public abstract class AnnotationRowFilt
  
    protected int[] annmap;
  
 -  protected boolean enableSeqAss = false;
 -
 -  private AlignmentAnnotation currentAnnotation;
 -
    protected boolean adjusting = false;
 -
++  
+   protected JCheckBox currentColours = new JCheckBox();
+   protected JPanel minColour = new JPanel();
+   protected JPanel maxColour = new JPanel();
  
    protected JCheckBox seqAssociated = new JCheckBox();
  
+   protected JCheckBox thresholdIsMin = new JCheckBox();
    protected JSlider slider = new JSlider();
  
    protected JTextField thresholdValue = new JTextField(20);
     */
    protected boolean sliderDragging = false;
  
 +  protected JComboBox<String> threshold = new JComboBox<String>();
 +
 +  protected JComboBox<String> annotations;
 +
 +  /*
 +   * map from annotation to its menu item display label
 +   * - so we know which item to pre-select on restore
 +   */
 +  private Map<AlignmentAnnotation, String> annotationLabels;
 +
 +  private AlignmentAnnotation currentAnnotation;
 +
 +  /**
 +   * Constructor
 +   * 
 +   * @param av
 +   * @param ap
 +   */
 +  public AnnotationRowFilter(AlignViewport av, final AlignmentPanel ap)
 +  {
 +    this.av = av;
 +    this.ap = ap;
 +    thresholdValue.addFocusListener(new FocusAdapter()
 +    {
 +      @Override
 +      public void focusLost(FocusEvent e)
 +      {
 +        thresholdValue_actionPerformed();
 +      }
 +    });
 +  }
 +
    protected void addSliderChangeListener()
    {
  
      });
    }
  
 -  public AnnotationRowFilter(AlignViewport av, final AlignmentPanel ap)
 -  {
 -    this.av = av;
 -    this.ap = ap;
 -  }
 -
 -  public AnnotationRowFilter()
 -  {
 -
 -  }
 -
 +  /**
 +   * Builds and returns a list of menu items (display text) for choice of
 +   * annotation. Also builds maps between annotations, their positions in the
 +   * list, and their display labels in the list.
 +   * 
 +   * @param isSeqAssociated
 +   * @return
 +   */
    public Vector<String> getAnnotationItems(boolean isSeqAssociated)
    {
 +    annotationLabels = new HashMap<AlignmentAnnotation, String>();
 +
      Vector<String> list = new Vector<String>();
      int index = 1;
      int[] anmap = new int[av.getAlignment().getAlignmentAnnotation().length];
 +    seqAssociated.setEnabled(false);
      for (int i = 0; i < av.getAlignment().getAlignmentAnnotation().length; i++)
      {
 -      if (av.getAlignment().getAlignmentAnnotation()[i].sequenceRef == null)
 +      AlignmentAnnotation annotation = av.getAlignment()
 +              .getAlignmentAnnotation()[i];
 +      if (annotation.sequenceRef == null)
        {
          if (isSeqAssociated)
          {
        }
        else
        {
 -        enableSeqAss = true;
 +        seqAssociated.setEnabled(true);
        }
 -      String label = av.getAlignment().getAlignmentAnnotation()[i].label;
 +      String label = annotation.label;
        // add associated sequence ID if available
 -      if (!isSeqAssociated
 -              && av.getAlignment().getAlignmentAnnotation()[i].sequenceRef != null)
 +      if (!isSeqAssociated && annotation.sequenceRef != null)
        {
 -        label = label
 -                + "_"
 -                + av.getAlignment().getAlignmentAnnotation()[i].sequenceRef
 -                        .getName();
 +        label = label + "_" + annotation.sequenceRef.getName();
        }
        // make label unique
        if (!list.contains(label))
        {
          anmap[list.size()] = i;
          list.add(label);
 +        annotationLabels.put(annotation, label);
        }
        else
        {
          if (!isSeqAssociated)
          {
            anmap[list.size()] = i;
 -          list.add(label + "_" + (index++));
 +          label = label + "_" + (index++);
 +          list.add(label);
 +          annotationLabels.put(annotation, label);
          }
        }
      }
      return selectedThresholdItem;
    }
  
 -  public void modelChanged()
 -  {
 -    seqAssociated.setEnabled(enableSeqAss);
 -  }
 -
    public void ok_actionPerformed()
    {
      try
      }
    }
  
 -  public void thresholdCheck_actionPerformed()
 +  protected void thresholdCheck_actionPerformed()
    {
      updateView();
    }
  
 -  public void annotations_actionPerformed()
 +  protected void selectedAnnotationChanged()
    {
      updateView();
    }
  
 -  public void threshold_actionPerformed()
 +  protected void threshold_actionPerformed()
    {
      updateView();
    }
  
 -  public void thresholdValue_actionPerformed()
 +  protected void thresholdValue_actionPerformed()
    {
      try
      {
      }
    }
  
 -  public void thresholdIsMin_actionPerformed()
 +  protected void thresholdIsMin_actionPerformed()
    {
      updateView();
    }
  
 -  protected void populateThresholdComboBox(JComboBox<String> threshold)
 +  protected void populateThresholdComboBox(JComboBox<String> thresh)
    {
 -    threshold.addItem(MessageManager
 +    thresh.addItem(MessageManager
              .getString("label.threshold_feature_no_threshold"));
 -    threshold.addItem(MessageManager
 +    thresh.addItem(MessageManager
              .getString("label.threshold_feature_above_threshold"));
 -    threshold.addItem(MessageManager
 +    thresh.addItem(MessageManager
              .getString("label.threshold_feature_below_threshold"));
    }
  
 -  protected void seqAssociated_actionPerformed(JComboBox<String> annotations)
 +  /**
 +   * Rebuilds the drop-down list of annotations to choose from when the 'per
 +   * sequence only' checkbox is checked or unchecked.
 +   * 
 +   * @param anns
 +   */
 +  protected void seqAssociated_actionPerformed(JComboBox<String> anns)
    {
      adjusting = true;
 -    String cursel = (String) annotations.getSelectedItem();
 -    boolean isvalid = false, isseqs = seqAssociated.isSelected();
 -    annotations.removeAllItems();
 +    String cursel = (String) anns.getSelectedItem();
 +    boolean isvalid = false;
 +    boolean isseqs = seqAssociated.isSelected();
 +    anns.removeAllItems();
      for (String anitem : getAnnotationItems(seqAssociated.isSelected()))
      {
        if (anitem.equals(cursel) || (isseqs && cursel.startsWith(anitem)))
          isvalid = true;
          cursel = anitem;
        }
 -      annotations.addItem(anitem);
 +      anns.addItem(anitem);
      }
 -    adjusting = false;
      if (isvalid)
      {
 -      annotations.setSelectedItem(cursel);
 +      anns.setSelectedItem(cursel);
      }
      else
      {
 -      if (annotations.getItemCount() > 0)
 +      if (anns.getItemCount() > 0)
        {
 -        annotations.setSelectedIndex(0);
 +        anns.setSelectedIndex(0);
        }
      }
 +    adjusting = false;
 +
 +    updateView();
    }
  
    protected void propagateSeqAssociatedThreshold(boolean allAnnotation,
      }
    }
  
-   protected AlignmentAnnotation getCurrentAnnotation()
 -  protected boolean colorAlignmContaining(AlignmentAnnotation currentAnn,
 -          int selectedThresholdOption)
++  public AlignmentAnnotation getCurrentAnnotation()
    {
 +    return currentAnnotation;
 +  }
  
 -    AnnotationColourGradient acg = null;
 -    if (currentColours.isSelected())
 -    {
 -      acg = new AnnotationColourGradient(currentAnn,
 -              av.getGlobalColourScheme(), selectedThresholdOption);
 -    }
 -    else
 -    {
 -      acg = new AnnotationColourGradient(currentAnn,
 -              minColour.getBackground(), maxColour.getBackground(),
 -              selectedThresholdOption);
 -    }
 -    acg.setSeqAssociated(seqAssociated.isSelected());
 +  protected void setCurrentAnnotation(AlignmentAnnotation currentAnnotation)
 +  {
 +    this.currentAnnotation = currentAnnotation;
 +  }
  
 -    if (currentAnn.graphMin == 0f && currentAnn.graphMax == 0f)
 -    {
 -      acg.setPredefinedColours(true);
 -    }
 +  protected abstract void valueChanged(boolean updateAllAnnotation);
  
 -    acg.thresholdIsMinMax = thresholdIsMin.isSelected();
 +  protected abstract void updateView();
  
 -    av.setGlobalColourScheme(acg);
 +  protected abstract void reset();
  
 -    if (av.getAlignment().getGroups() != null)
 +  protected String getAnnotationMenuLabel(AlignmentAnnotation ann)
 +  {
 +    return annotationLabels.get(ann);
 +  }
 +
 +  protected void jbInit()
 +  {
 +    ok.setOpaque(false);
 +    ok.setText(MessageManager.getString("action.ok"));
 +    ok.addActionListener(new ActionListener()
      {
 +      @Override
 +      public void actionPerformed(ActionEvent e)
 +      {
 +        ok_actionPerformed();
 +      }
 +    });
  
 -      for (SequenceGroup sg : ap.av.getAlignment().getGroups())
 +    cancel.setOpaque(false);
 +    cancel.setText(MessageManager.getString("action.cancel"));
 +    cancel.addActionListener(new ActionListener()
 +    {
 +      @Override
 +      public void actionPerformed(ActionEvent e)
        {
 -        if (sg.cs == null)
 -        {
 -          continue;
 -        }
 +        cancel_actionPerformed();
 +      }
 +    });
  
 -        AnnotationColourGradient scheme = null;
 -        if (currentColours.isSelected())
 -        {
 -          scheme = new AnnotationColourGradient(currentAnn,
 -                  sg.getColourScheme(), selectedThresholdOption);
 -        }
 -        else
 -        {
 -          scheme = new AnnotationColourGradient(currentAnn,
 -                  minColour.getBackground(), maxColour.getBackground(),
 -                  selectedThresholdOption);
 -        }
 -        scheme.setSeqAssociated(seqAssociated.isSelected());
 -        sg.setColourScheme(scheme);
 +    annotations.addItemListener(new ItemListener()
 +    {
 +      @Override
 +      public void itemStateChanged(ItemEvent e)
 +      {
 +        selectedAnnotationChanged();
        }
 -    }
 -    return false;
 +    });
 +    annotations.setToolTipText(MessageManager
 +            .getString("info.select_annotation_row"));
 +
 +    threshold.addActionListener(new ActionListener()
 +    {
 +      @Override
 +      public void actionPerformed(ActionEvent e)
 +      {
 +        threshold_actionPerformed();
 +      }
 +    });
 +
 +    thresholdValue.setEnabled(false);
 +    thresholdValue.setColumns(7);
 +    thresholdValue.addActionListener(new ActionListener()
 +    {
 +      @Override
 +      public void actionPerformed(ActionEvent e)
 +      {
 +        thresholdValue_actionPerformed();
 +      }
 +    });
 +
 +    slider.setPaintLabels(false);
 +    slider.setPaintTicks(true);
 +    slider.setBackground(Color.white);
 +    slider.setEnabled(false);
 +    slider.setOpaque(false);
 +    slider.setPreferredSize(new Dimension(100, 32));
    }
  
 -  public jalview.datamodel.AlignmentAnnotation getCurrentAnnotation()
 +  public JComboBox<String> getThreshold()
    {
 -    return currentAnnotation;
 +    return threshold;
    }
  
 -  public void setCurrentAnnotation(
 -          jalview.datamodel.AlignmentAnnotation currentAnnotation)
 +  public void setThreshold(JComboBox<String> thresh)
    {
 -    this.currentAnnotation = currentAnnotation;
 +    this.threshold = thresh;
    }
  
 -  public abstract void valueChanged(boolean updateAllAnnotation);
 -
 -  public abstract void updateView();
 +  public JComboBox<String> getAnnotations()
 +  {
 +    return annotations;
 +  }
  
 -  public abstract void reset();
 +  public void setAnnotations(JComboBox<String> anns)
 +  {
 +    this.annotations = anns;
 +  }
  }
   */
  package jalview.gui;
  
- import java.awt.Color;
- import java.awt.Rectangle;
- import java.io.BufferedReader;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.OutputStreamWriter;
- import java.io.PrintWriter;
- import java.lang.reflect.InvocationTargetException;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Enumeration;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Hashtable;
- import java.util.IdentityHashMap;
- import java.util.Iterator;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Map.Entry;
- import java.util.Set;
- import java.util.Vector;
- import java.util.jar.JarEntry;
- import java.util.jar.JarInputStream;
- import java.util.jar.JarOutputStream;
  import jalview.analysis.Conservation;
  import jalview.api.FeatureColourI;
  import jalview.api.ViewStyleI;
@@@ -62,7 -29,6 +29,7 @@@ import jalview.datamodel.AlignedCodonFr
  import jalview.datamodel.Alignment;
  import jalview.datamodel.AlignmentAnnotation;
  import jalview.datamodel.AlignmentI;
 +import jalview.datamodel.GraphLine;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.RnaViewerModel;
  import jalview.datamodel.SequenceGroup;
@@@ -73,6 -39,7 +40,7 @@@ import jalview.ext.varna.RnaModel
  import jalview.gui.StructureViewer.ViewerType;
  import jalview.io.DataSourceType;
  import jalview.io.FileFormat;
+ import jalview.renderer.ResidueShaderI;
  import jalview.schemabinding.version2.AlcodMap;
  import jalview.schemabinding.version2.AlcodonFrame;
  import jalview.schemabinding.version2.Annotation;
@@@ -110,7 -77,7 +78,6 @@@ import jalview.schemes.AnnotationColour
  import jalview.schemes.ColourSchemeI;
  import jalview.schemes.ColourSchemeProperty;
  import jalview.schemes.FeatureColour;
--import jalview.schemes.ResidueColourScheme;
  import jalview.schemes.ResidueProperties;
  import jalview.schemes.UserColourScheme;
  import jalview.structure.StructureSelectionManager;
@@@ -129,6 -96,39 +96,39 @@@ import jalview.ws.params.ArgumentI
  import jalview.ws.params.AutoCalcSetting;
  import jalview.ws.params.WsParamSetI;
  
+ import java.awt.Color;
+ import java.awt.Rectangle;
+ import java.io.BufferedReader;
+ import java.io.DataInputStream;
+ import java.io.DataOutputStream;
+ import java.io.File;
+ import java.io.FileInputStream;
+ import java.io.FileOutputStream;
+ import java.io.IOException;
+ import java.io.InputStreamReader;
+ import java.io.OutputStreamWriter;
+ import java.io.PrintWriter;
+ import java.lang.reflect.InvocationTargetException;
+ import java.net.MalformedURLException;
+ import java.net.URL;
+ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.Enumeration;
+ import java.util.HashMap;
+ import java.util.HashSet;
+ import java.util.Hashtable;
+ import java.util.IdentityHashMap;
+ import java.util.Iterator;
+ import java.util.LinkedHashMap;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.Map.Entry;
+ import java.util.Set;
+ import java.util.Vector;
+ import java.util.jar.JarEntry;
+ import java.util.jar.JarInputStream;
+ import java.util.jar.JarOutputStream;
  import javax.swing.JInternalFrame;
  import javax.swing.SwingUtilities;
  
@@@ -1175,38 -1175,43 +1175,43 @@@ public class Jalview2XM
            // group has references so set its ID field
            jGroup.setId(groupRefs.get(sg));
          }
-         if (sg.cs != null)
+         ColourSchemeI colourScheme = sg.getColourScheme();
+         if (colourScheme != null)
          {
-           if (sg.cs.conservationApplied())
+           ResidueShaderI groupColourScheme = sg
+                   .getGroupColourScheme();
+           if (groupColourScheme.conservationApplied())
            {
-             jGroup.setConsThreshold(sg.cs.getConservationInc());
+             jGroup.setConsThreshold(groupColourScheme.getConservationInc());
  
-             if (sg.cs instanceof jalview.schemes.UserColourScheme)
+             if (colourScheme instanceof jalview.schemes.UserColourScheme)
              {
-               jGroup.setColour(setUserColourScheme(sg.cs, userColours, jms));
+               jGroup.setColour(setUserColourScheme(colourScheme,
+                       userColours, jms));
              }
              else
              {
-               jGroup.setColour(ColourSchemeProperty.getColourName(sg.cs));
+               jGroup.setColour(colourScheme.getSchemeName());
              }
            }
-           else if (sg.cs instanceof jalview.schemes.AnnotationColourGradient)
+           else if (colourScheme instanceof jalview.schemes.AnnotationColourGradient)
            {
              jGroup.setColour("AnnotationColourGradient");
              jGroup.setAnnotationColours(constructAnnotationColours(
-                     (jalview.schemes.AnnotationColourGradient) sg.cs,
+                     (jalview.schemes.AnnotationColourGradient) colourScheme,
                      userColours, jms));
            }
-           else if (sg.cs instanceof jalview.schemes.UserColourScheme)
+           else if (colourScheme instanceof jalview.schemes.UserColourScheme)
            {
-             jGroup.setColour(setUserColourScheme(sg.cs, userColours, jms));
+             jGroup.setColour(setUserColourScheme(colourScheme,
+                     userColours, jms));
            }
            else
            {
-             jGroup.setColour(ColourSchemeProperty.getColourName(sg.cs));
+             jGroup.setColour(colourScheme.getSchemeName());
            }
  
-           jGroup.setPidThreshold(sg.cs.getThreshold());
+           jGroup.setPidThreshold(groupColourScheme.getThreshold());
          }
  
          jGroup.setOutlineColour(sg.getOutlineColour().getRGB());
                  .getGlobalColourScheme()));
        }
  
+       ResidueShaderI vcs = av.getResidueShading();
        ColourSchemeI cs = av.getGlobalColourScheme();
  
        if (cs != null)
        {
-         if (cs.conservationApplied())
+         if (vcs.conservationApplied())
          {
-           view.setConsThreshold(cs.getConservationInc());
+           view.setConsThreshold(vcs.getConservationInc());
            if (cs instanceof jalview.schemes.UserColourScheme)
            {
              view.setBgColour(setUserColourScheme(cs, userColours, jms));
            }
          }
-         if (cs instanceof ResidueColourScheme)
-         {
-           view.setPidThreshold(cs.getThreshold());
-         }
+         view.setPidThreshold(vcs.getThreshold());
        }
  
        view.setConservationSelected(av.getConservationSelected());
      return matchedFile;
    }
  
++  /**
++   * Populates the AnnotationColours xml for save. This captures the settings of
++   * the options in the 'Colour by Annotation' dialog.
++   * 
++   * @param acg
++   * @param userColours
++   * @param jms
++   * @return
++   */
    private AnnotationColours constructAnnotationColours(
            AnnotationColourGradient acg, List<UserColourScheme> userColours,
            JalviewModelSequence jms)
      AnnotationColours ac = new AnnotationColours();
      ac.setAboveThreshold(acg.getAboveThreshold());
      ac.setThreshold(acg.getAnnotationThreshold());
 -    ac.setAnnotation(acg.getAnnotation());
 -    if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme)
 +    // 2.10.2 save annotationId (unique) not annotation label
 +    ac.setAnnotation(acg.getAnnotation().annotationId);
-     if (acg.getBaseColour() instanceof jalview.schemes.UserColourScheme)
++    if (acg.getBaseColour() instanceof UserColourScheme)
      {
        ac.setColourScheme(setUserColourScheme(acg.getBaseColour(),
                userColours, jms));
      }
      else
      {
-       ac.setColourScheme(ColourSchemeProperty.getColourName(acg
-               .getBaseColour()));
+       ac.setColourScheme(ColourSchemeProperty.getColourName(acg.getBaseColour()));
      }
  
      ac.setMaxColour(acg.getMaxColour().getRGB());
            @Override
            public void run()
            {
 -            JvOptionPane.showInternalMessageDialog(Desktop.desktop,
 -                    finalErrorMessage, "Error "
 -                            + (saving ? "saving" : "loading")
 -                            + " Jalview file", JvOptionPane.WARNING_MESSAGE);
 +            JvOptionPane
 +                    .showInternalMessageDialog(Desktop.desktop,
 +                            finalErrorMessage, "Error "
 +                                    + (saving ? "saving" : "loading")
 +                                    + " Jalview file",
 +                            JvOptionPane.WARNING_MESSAGE);
            }
          });
        }
                    && jGroup.getAnnotationColours() != null)
            {
              addAnnotSchemeGroup = true;
            }
            else
            {
-             cs = ColourSchemeProperty.getColour(al, jGroup.getColour());
-           }
-           if (cs != null)
-           {
-             cs.setThreshold(jGroup.getPidThreshold(), true);
+             cs = ColourSchemeProperty.getColourScheme(al, jGroup.getColour());
            }
          }
+         int pidThreshold = jGroup.getPidThreshold();
  
          Vector<SequenceI> seqs = new Vector<SequenceI>();
  
          SequenceGroup sg = new SequenceGroup(seqs, jGroup.getName(), cs,
                  jGroup.getDisplayBoxes(), jGroup.getDisplayText(),
                  jGroup.getColourText(), jGroup.getStart(), jGroup.getEnd());
+         sg.getGroupColourScheme().setThreshold(pidThreshold, true);
+         sg.getGroupColourScheme().setConservationInc(jGroup.getConsThreshold());
          sg.setOutlineColour(new java.awt.Color(jGroup.getOutlineColour()));
  
          sg.textColour = new java.awt.Color(jGroup.getTextCol1());
          if (addAnnotSchemeGroup)
          {
            // reconstruct the annotation colourscheme
-           sg.cs = constructAnnotationColour(jGroup.getAnnotationColours(),
-                   null, al, jms, false);
+           sg.setColourScheme(constructAnnotationColour(
+                   jGroup.getAnnotationColours(), null, al, jms, false));
          }
        }
      }
  
      af.viewport.setShowAnnotation(view.getShowAnnotation());
      af.viewport.setAbovePIDThreshold(view.getPidSelected());
+     af.viewport.setThreshold(view.getPidThreshold());
  
      af.viewport.setColourText(view.getShowColourText());
  
      af.viewport.setConservationSelected(view.getConservationSelected());
+     af.viewport.setIncrement(view.getConsThreshold());
      af.viewport.setShowJVSuffix(view.getShowFullId());
      af.viewport.setRightAlignIds(view.getRightAlignIds());
      af.viewport.setFont(
        }
        else
        {
-         cs = ColourSchemeProperty.getColour(al, view.getBgColour());
-       }
-       if (cs != null)
-       {
-         cs.setThreshold(view.getPidThreshold(), true);
-         cs.setConsensus(af.viewport.getSequenceConsensusHash());
+         cs = ColourSchemeProperty.getColourScheme(al, view.getBgColour());
        }
      }
  
      af.viewport.setGlobalColourScheme(cs);
+     af.viewport.getResidueShading().setThreshold(
+             view.getPidThreshold(), true);
+     af.viewport.getResidueShading().setConsensus(
+             af.viewport.getSequenceConsensusHash());
      af.viewport.setColourAppliesToAllGroups(false);
  
      if (view.getConservationSelected() && cs != null)
      {
-       cs.setConservationInc(view.getConsThreshold());
+       af.viewport.getResidueShading().setConservationInc(
+               view.getConsThreshold());
      }
  
      af.changeColour(cs);
      return af;
    }
  
++  /**
++   * Reads saved data to restore Colour by Annotation settings
++   * 
++   * @param viewAnnColour
++   * @param af
++   * @param al
++   * @param jms
++   * @param checkGroupAnnColour
++   * @return
++   */
    private ColourSchemeI constructAnnotationColour(
            AnnotationColours viewAnnColour, AlignFrame af, AlignmentI al,
            JalviewModelSequence jms, boolean checkGroupAnnColour)
    {
      boolean propagateAnnColour = false;
-     AnnotationColourGradient cs = null;
 -    ColourSchemeI cs = null;
      AlignmentI annAlignment = af != null ? af.viewport.getAlignment() : al;
      if (checkGroupAnnColour && al.getGroups() != null
              && al.getGroups().size() > 0)
        // pre 2.8.1 behaviour
        // check to see if we should transfer annotation colours
        propagateAnnColour = true;
 -      for (jalview.datamodel.SequenceGroup sg : al.getGroups())
 +      for (SequenceGroup sg : al.getGroups())
        {
-         if (sg.cs instanceof AnnotationColourGradient)
+         if (sg.getColourScheme() instanceof AnnotationColourGradient)
          {
            propagateAnnColour = false;
          }
        }
      }
 -    // int find annotation
 -    if (annAlignment.getAlignmentAnnotation() != null)
 +
 +    /*
-      * pre 2.10.2: annotationId is AlignmentAnnotation.label
-      * 2.10.2- : annotationId is AlignmentAnnotation.annotationId
++     * 2.10.2- : saved annotationId is AlignmentAnnotation.annotationId
 +     */
 +    String annotationId = viewAnnColour.getAnnotation();
-     AlignmentAnnotation annotation = annotationIds.get(annotationId);
++    AlignmentAnnotation matchedAnnotation = annotationIds.get(annotationId);
 +
-     if (annotation == null && annAlignment.getAlignmentAnnotation() != null)
++    /*
++     * pre 2.10.2: saved annotationId is AlignmentAnnotation.label
++     */
++    if (matchedAnnotation == null && annAlignment.getAlignmentAnnotation() != null)
      {
        for (int i = 0; i < annAlignment.getAlignmentAnnotation().length; i++)
        {
 -        if (annAlignment.getAlignmentAnnotation()[i].label
 -                .equals(viewAnnColour.getAnnotation()))
 +        if (annotationId
 +                .equals(annAlignment.getAlignmentAnnotation()[i].label))
          {
-           annotation = annAlignment.getAlignmentAnnotation()[i];
 -          if (annAlignment.getAlignmentAnnotation()[i].getThreshold() == null)
 -          {
 -            annAlignment.getAlignmentAnnotation()[i]
 -                    .setThreshold(new jalview.datamodel.GraphLine(
 -                            viewAnnColour.getThreshold(), "Threshold",
 -                            java.awt.Color.black)
 -
 -                    );
 -          }
 -
 -          if (viewAnnColour.getColourScheme().equals(
 -                  ResidueColourScheme.NONE))
 -          {
 -            cs = new AnnotationColourGradient(
 -                    annAlignment.getAlignmentAnnotation()[i],
 -                    new java.awt.Color(viewAnnColour.getMinColour()),
 -                    new java.awt.Color(viewAnnColour.getMaxColour()),
 -                    viewAnnColour.getAboveThreshold());
 -          }
 -          else if (viewAnnColour.getColourScheme().startsWith("ucs"))
 -          {
 -            cs = new AnnotationColourGradient(
 -                    annAlignment.getAlignmentAnnotation()[i],
 -                    getUserColourScheme(jms,
 -                            viewAnnColour.getColourScheme()),
 -                    viewAnnColour.getAboveThreshold());
 -          }
 -          else
 -          {
 -            cs = new AnnotationColourGradient(
 -                    annAlignment.getAlignmentAnnotation()[i],
 -                    ColourSchemeProperty.getColourScheme(al,
 -                            viewAnnColour.getColourScheme()),
 -                    viewAnnColour.getAboveThreshold());
 -          }
 -          if (viewAnnColour.hasPerSequence())
 -          {
 -            ((AnnotationColourGradient) cs).setSeqAssociated(viewAnnColour
 -                    .isPerSequence());
 -          }
 -          if (viewAnnColour.hasPredefinedColours())
 -          {
 -            ((AnnotationColourGradient) cs)
 -                    .setPredefinedColours(viewAnnColour
 -                            .isPredefinedColours());
 -          }
 -          if (propagateAnnColour && al.getGroups() != null)
 -          {
 -            // Also use these settings for all the groups
 -            for (int g = 0; g < al.getGroups().size(); g++)
 -            {
 -              jalview.datamodel.SequenceGroup sg = al.getGroups().get(g);
 -
 -              if (sg.cs == null)
 -              {
 -                continue;
 -              }
++          matchedAnnotation = annAlignment.getAlignmentAnnotation()[i];
 +          break;
 +        }
 +      }
 +    }
-     if (annotation == null)
++    if (matchedAnnotation == null)
 +    {
 +      System.err.println("Failed to match annotation colour scheme for "
 +              + annotationId);
 +      return null;
 +    }
-     if (annotation.getThreshold() == null)
++    if (matchedAnnotation.getThreshold() == null)
 +    {
-       annotation.setThreshold(new GraphLine(viewAnnColour.getThreshold(),
++      matchedAnnotation.setThreshold(new GraphLine(viewAnnColour.getThreshold(),
 +              "Threshold", Color.black));
 +    }
  
 -              /*
 -               * if (viewAnnColour.getColourScheme().equals(ResidueColourScheme.NONE)) { sg.cs =
 -               * new AnnotationColourGradient(
 -               * annAlignment.getAlignmentAnnotation()[i], new
 -               * java.awt.Color(viewAnnColour. getMinColour()), new
 -               * java.awt.Color(viewAnnColour. getMaxColour()),
 -               * viewAnnColour.getAboveThreshold()); } else
 -               */
 -              {
 -                sg.setColourScheme(new AnnotationColourGradient(
 -                        annAlignment.getAlignmentAnnotation()[i], sg
 -                                .getColourScheme(), viewAnnColour
 -                                .getAboveThreshold()));
 -                if (cs instanceof AnnotationColourGradient)
 -                {
 -                  if (viewAnnColour.hasPerSequence())
 -                  {
 -                    ((AnnotationColourGradient) cs)
 -                            .setSeqAssociated(viewAnnColour.isPerSequence());
 -                  }
 -                  if (viewAnnColour.hasPredefinedColours())
 -                  {
 -                    ((AnnotationColourGradient) cs)
 -                            .setPredefinedColours(viewAnnColour
 -                                    .isPredefinedColours());
 -                  }
 -                }
 -              }
++    AnnotationColourGradient cs = null;
 +    if (viewAnnColour.getColourScheme().equals("None"))
 +    {
-       cs = new AnnotationColourGradient(annotation, new Color(
++      cs = new AnnotationColourGradient(matchedAnnotation, new Color(
 +              viewAnnColour.getMinColour()), new Color(
 +              viewAnnColour.getMaxColour()),
 +              viewAnnColour.getAboveThreshold());
 +    }
 +    else if (viewAnnColour.getColourScheme().startsWith("ucs"))
 +    {
-       cs = new AnnotationColourGradient(annotation, getUserColourScheme(
++      cs = new AnnotationColourGradient(matchedAnnotation, getUserColourScheme(
 +              jms, viewAnnColour.getColourScheme()),
 +              viewAnnColour.getAboveThreshold());
 +    }
 +    else
 +    {
-       cs = new AnnotationColourGradient(annotation,
-               ColourSchemeProperty.getColour(al,
++      cs = new AnnotationColourGradient(matchedAnnotation,
++              ColourSchemeProperty.getColourScheme(al,
 +                      viewAnnColour.getColourScheme()),
 +              viewAnnColour.getAboveThreshold());
 +    }
-     if (viewAnnColour.hasPerSequence())
-     {
-       cs.setSeqAssociated(viewAnnColour.isPerSequence());
-     }
-     if (viewAnnColour.hasPredefinedColours())
-     {
-       cs.setPredefinedColours(viewAnnColour.isPredefinedColours());
-     }
 -            }
 -          }
++    boolean perSequenceOnly = viewAnnColour.isPerSequence();
++    boolean useOriginalColours = viewAnnColour.isPredefinedColours();
++    cs.setSeqAssociated(perSequenceOnly);
++    cs.setPredefinedColours(useOriginalColours);
 -          break;
 +    if (propagateAnnColour && al.getGroups() != null)
 +    {
 +      // Also use these settings for all the groups
 +      for (int g = 0; g < al.getGroups().size(); g++)
 +      {
 +        SequenceGroup sg = al.getGroups().get(g);
-         if (sg.cs == null)
++        if (sg.getGroupColourScheme() == null)
 +        {
 +          continue;
          }
  
-         /*
-          * if (viewAnnColour.getColourScheme().equals("None" )) { sg.cs =
-          * new AnnotationColourGradient(
-          * annAlignment.getAlignmentAnnotation()[i], new
-          * java.awt.Color(viewAnnColour. getMinColour()), new
-          * java.awt.Color(viewAnnColour. getMaxColour()),
-          * viewAnnColour.getAboveThreshold()); } else
-          *
-         {*/
-         sg.cs = new AnnotationColourGradient(annotation, sg.cs,
++        AnnotationColourGradient groupScheme = new AnnotationColourGradient(
++                matchedAnnotation, sg.getColourScheme(),
 +                viewAnnColour.getAboveThreshold());
-         if (cs instanceof AnnotationColourGradient)
-         {
-           if (viewAnnColour.hasPerSequence())
-           {
-             cs.setSeqAssociated(viewAnnColour.isPerSequence());
-           }
-           if (viewAnnColour.hasPredefinedColours())
-           {
-             cs.setPredefinedColours(viewAnnColour.isPredefinedColours());
-           }
-         }
++        sg.setColourScheme(groupScheme);
++        groupScheme.setSeqAssociated(perSequenceOnly);
++        groupScheme.setPredefinedColours(useOriginalColours);
        }
      }
      return cs;
   */
  package jalview.gui;
  
- import java.awt.Color;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Hashtable;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.TreeMap;
- import java.util.Vector;
  import jalview.analysis.AAFrequency;
  import jalview.analysis.AlignmentAnnotationUtils;
  import jalview.analysis.AlignmentUtils;
@@@ -51,35 -38,41 +38,40 @@@ import jalview.datamodel.Sequence
  import jalview.datamodel.SequenceFeature;
  import jalview.datamodel.SequenceGroup;
  import jalview.datamodel.SequenceI;
- import jalview.io.FileFormat;
+ import jalview.gui.ColourMenuHelper.ColourChangeListener;
  import jalview.io.FileFormatI;
+ import jalview.io.FileFormats;
  import jalview.io.FormatAdapter;
  import jalview.io.SequenceAnnotationReport;
 -import jalview.schemes.AnnotationColourGradient;
  import jalview.schemes.Blosum62ColourScheme;
- import jalview.schemes.BuriedColourScheme;
- import jalview.schemes.ClustalxColourScheme;
- import jalview.schemes.HelixColourScheme;
- import jalview.schemes.HydrophobicColourScheme;
- import jalview.schemes.NucleotideColourScheme;
+ import jalview.schemes.ColourSchemeI;
+ import jalview.schemes.ColourSchemes;
  import jalview.schemes.PIDColourScheme;
- import jalview.schemes.PurinePyrimidineColourScheme;
- import jalview.schemes.StrandColourScheme;
- import jalview.schemes.TaylorColourScheme;
- import jalview.schemes.TurnColourScheme;
- import jalview.schemes.UserColourScheme;
- import jalview.schemes.ZappoColourScheme;
+ import jalview.schemes.ResidueColourScheme;
  import jalview.util.GroupUrlLink;
  import jalview.util.GroupUrlLink.UrlStringTooLongException;
  import jalview.util.MessageManager;
  import jalview.util.UrlLink;
  
- import javax.swing.ButtonGroup;
+ import java.awt.Color;
+ import java.awt.event.ActionEvent;
+ import java.awt.event.ActionListener;
+ import java.util.Arrays;
+ import java.util.Collection;
+ import java.util.Collections;
+ import java.util.Hashtable;
+ import java.util.LinkedHashMap;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.SortedMap;
+ import java.util.TreeMap;
+ import java.util.Vector;
  import javax.swing.JCheckBoxMenuItem;
  import javax.swing.JColorChooser;
  import javax.swing.JMenu;
  import javax.swing.JMenuItem;
  import javax.swing.JPopupMenu;
- import javax.swing.JRadioButtonMenuItem;
  
  /**
   * DOCUMENT ME!
   * @author $author$
   * @version $Revision: 1.118 $
   */
- public class PopupMenu extends JPopupMenu
+ public class PopupMenu extends JPopupMenu implements ColourChangeListener
  {
    JMenu groupMenu = new JMenu();
  
    JMenuItem groupName = new JMenuItem();
  
-   protected JRadioButtonMenuItem clustalColour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem zappoColour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem taylorColour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem hydrophobicityColour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem helixColour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem strandColour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem turnColour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem buriedColour = new JRadioButtonMenuItem();
    protected JCheckBoxMenuItem abovePIDColour = new JCheckBoxMenuItem();
  
-   protected JRadioButtonMenuItem userDefinedColour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem PIDColour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem BLOSUM62Colour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem purinePyrimidineColour = new JRadioButtonMenuItem();
-   protected JRadioButtonMenuItem RNAInteractionColour = new JRadioButtonMenuItem();
-   JRadioButtonMenuItem noColourmenuItem = new JRadioButtonMenuItem();
+   protected JMenuItem modifyPID = new JMenuItem();
  
    protected JCheckBoxMenuItem conservationMenuItem = new JCheckBoxMenuItem();
  
+   protected JMenuItem modifyConservation = new JMenuItem();
    AlignmentPanel ap;
  
    JMenu sequenceMenu = new JMenu();
  
    JMenuItem outline = new JMenuItem();
  
-   JRadioButtonMenuItem nucleotideMenuItem = new JRadioButtonMenuItem();
    JMenu colourMenu = new JMenu();
  
    JCheckBoxMenuItem showBoxes = new JCheckBoxMenuItem();
      this.ap = ap;
      sequence = seq;
  
-     ButtonGroup colours = new ButtonGroup();
-     colours.add(noColourmenuItem);
-     colours.add(clustalColour);
-     colours.add(zappoColour);
-     colours.add(taylorColour);
-     colours.add(hydrophobicityColour);
-     colours.add(helixColour);
-     colours.add(strandColour);
-     colours.add(turnColour);
-     colours.add(buriedColour);
-     colours.add(abovePIDColour);
-     colours.add(userDefinedColour);
-     colours.add(PIDColour);
-     colours.add(BLOSUM62Colour);
-     colours.add(purinePyrimidineColour);
-     colours.add(RNAInteractionColour);
-     for (String ff : FileFormat.getWritableFormats(true))
+     for (String ff : FileFormats.getInstance().getWritableFormats(true))
      {
        JMenuItem item = new JMenuItem(ff);
  
-       item.addActionListener(new java.awt.event.ActionListener()
+       item.addActionListener(new ActionListener()
        {
          @Override
          public void actionPerformed(ActionEvent e)
                menuItem.setText(MessageManager.formatMessage(
                        "label.2d_rna_structure_line",
                        new Object[] { aa.label }));
-               menuItem.addActionListener(new java.awt.event.ActionListener()
+               menuItem.addActionListener(new ActionListener()
                {
                  @Override
                  public void actionPerformed(ActionEvent e)
                menuItem.setText(MessageManager.formatMessage(
                        "label.2d_rna_sequence_name",
                        new Object[] { seq.getName() }));
-               menuItem.addActionListener(new java.awt.event.ActionListener()
+               menuItem.addActionListener(new ActionListener()
                {
                  @Override
                  public void actionPerformed(ActionEvent e)
  
        menuItem = new JMenuItem(
                MessageManager.getString("action.hide_sequences"));
-       menuItem.addActionListener(new java.awt.event.ActionListener()
+       menuItem.addActionListener(new ActionListener()
        {
          @Override
          public void actionPerformed(ActionEvent e)
          menuItem = new JMenuItem(MessageManager.formatMessage(
                  "label.represent_group_with",
                  new Object[] { seq.getName() }));
-         menuItem.addActionListener(new java.awt.event.ActionListener()
+         menuItem.addActionListener(new ActionListener()
          {
            @Override
            public void actionPerformed(ActionEvent e)
  
          add(menuItem);
        }
      }
  
      SequenceGroup sg = ap.av.getSelectionGroup();
        groupName.setText(MessageManager
                .getString("label.edit_name_and_description_current_group"));
  
-       if (sg.cs instanceof ZappoColourScheme)
-       {
-         zappoColour.setSelected(true);
-       }
-       else if (sg.cs instanceof TaylorColourScheme)
-       {
-         taylorColour.setSelected(true);
-       }
-       else if (sg.cs instanceof PIDColourScheme)
-       {
-         PIDColour.setSelected(true);
-       }
-       else if (sg.cs instanceof Blosum62ColourScheme)
-       {
-         BLOSUM62Colour.setSelected(true);
-       }
-       else if (sg.cs instanceof UserColourScheme)
-       {
-         userDefinedColour.setSelected(true);
-       }
-       else if (sg.cs instanceof HydrophobicColourScheme)
-       {
-         hydrophobicityColour.setSelected(true);
-       }
-       else if (sg.cs instanceof HelixColourScheme)
-       {
-         helixColour.setSelected(true);
-       }
-       else if (sg.cs instanceof StrandColourScheme)
-       {
-         strandColour.setSelected(true);
-       }
-       else if (sg.cs instanceof TurnColourScheme)
-       {
-         turnColour.setSelected(true);
-       }
-       else if (sg.cs instanceof BuriedColourScheme)
-       {
-         buriedColour.setSelected(true);
-       }
-       else if (sg.cs instanceof ClustalxColourScheme)
-       {
-         clustalColour.setSelected(true);
-       }
-       else if (sg.cs instanceof PurinePyrimidineColourScheme)
-       {
-         purinePyrimidineColour.setSelected(true);
-       }
+       ColourMenuHelper.setColourSelected(colourMenu, sg.getColourScheme());
  
-       /*
-        * else if (sg.cs instanceof CovariationColourScheme) {
-        * covariationColour.setSelected(true); }
-        */
-       else
-       {
-         noColourmenuItem.setSelected(true);
-       }
+       conservationMenuItem.setEnabled(!sg.isNucleotide());
  
-       if (sg.cs != null && sg.cs.conservationApplied())
+       if (sg.cs != null)
        {
-         conservationMenuItem.setSelected(true);
+         if (sg.cs.conservationApplied())
+         {
+           conservationMenuItem.setSelected(true);
+         }
+         if (sg.cs.getThreshold() > 0)
+         {
+           abovePIDColour.setSelected(true);
+         }
        }
+       modifyConservation.setEnabled(conservationMenuItem.isSelected());
+       modifyPID.setEnabled(abovePIDColour.isSelected());
        displayNonconserved.setSelected(sg.getShowNonconserved());
        showText.setSelected(sg.getDisplayText());
        showColourText.setSelected(sg.getColourText());
      label = label.substring(1, label.length() - 1); // a, b, c
      final JMenuItem item = new JMenuItem(label);
      item.setToolTipText(calcId);
-     item.addActionListener(new java.awt.event.ActionListener()
+     item.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
      JMenuItem item = new JMenuItem(label);
      item.setToolTipText(MessageManager.formatMessage(
              "label.open_url_param", new Object[] { url }));
-     item.addActionListener(new java.awt.event.ActionListener()
+     item.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
    {
      groupMenu.setText(MessageManager.getString("label.selection"));
      groupName.setText(MessageManager.getString("label.name"));
-     groupName.addActionListener(new java.awt.event.ActionListener()
+     groupName.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
      sequenceMenu.setText(MessageManager.getString("label.sequence"));
      sequenceName.setText(MessageManager
              .getString("label.edit_name_description"));
-     sequenceName.addActionListener(new java.awt.event.ActionListener()
+     sequenceName.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
      });
      chooseAnnotations.setText(MessageManager
              .getString("action.choose_annotations"));
-     chooseAnnotations.addActionListener(new java.awt.event.ActionListener()
+     chooseAnnotations.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
      });
      sequenceDetails.setText(MessageManager
              .getString("label.sequence_details"));
-     sequenceDetails.addActionListener(new java.awt.event.ActionListener()
+     sequenceDetails.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
      });
      sequenceSelDetails.setText(MessageManager
              .getString("label.sequence_details"));
-     sequenceSelDetails
-             .addActionListener(new java.awt.event.ActionListener()
-             {
-               @Override
-               public void actionPerformed(ActionEvent e)
-               {
-                 sequenceSelectionDetails_actionPerformed();
-               }
-             });
-     PIDColour.setFocusPainted(false);
+     sequenceSelDetails.addActionListener(new ActionListener()
+     {
+       @Override
+       public void actionPerformed(ActionEvent e)
+       {
+         sequenceSelectionDetails_actionPerformed();
+       }
+     });
      unGroupMenuItem
              .setText(MessageManager.getString("action.remove_group"));
-     unGroupMenuItem.addActionListener(new java.awt.event.ActionListener()
+     unGroupMenuItem.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
      });
      createGroupMenuItem.setText(MessageManager
              .getString("action.create_group"));
-     createGroupMenuItem
-             .addActionListener(new java.awt.event.ActionListener()
-             {
-               @Override
-               public void actionPerformed(ActionEvent e)
-               {
-                 createGroupMenuItem_actionPerformed();
-               }
-             });
-     outline.setText(MessageManager.getString("action.border_colour"));
-     outline.addActionListener(new java.awt.event.ActionListener()
+     createGroupMenuItem.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
        {
-         outline_actionPerformed();
+         createGroupMenuItem_actionPerformed();
        }
      });
-     nucleotideMenuItem
-             .setText(MessageManager.getString("label.nucleotide"));
-     nucleotideMenuItem.addActionListener(new ActionListener()
+     outline.setText(MessageManager.getString("action.border_colour"));
+     outline.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
        {
-         nucleotideMenuItem_actionPerformed();
+         outline_actionPerformed();
        }
      });
-     colourMenu.setText(MessageManager.getString("label.group_colour"));
      showBoxes.setText(MessageManager.getString("action.boxes"));
      showBoxes.setState(true);
      showBoxes.addActionListener(new ActionListener()
        }
      });
      displayNonconserved.setText(MessageManager
-             .getString("label.show_non_conversed"));
+             .getString("label.show_non_conserved"));
      displayNonconserved.setState(true);
      displayNonconserved.addActionListener(new ActionListener()
      {
          sequenceFeature_actionPerformed();
        }
      });
-     textColour.setText(MessageManager.getString("label.text_colour"));
-     textColour.addActionListener(new ActionListener()
-     {
-       @Override
-       public void actionPerformed(ActionEvent e)
-       {
-         textColour_actionPerformed();
-       }
-     });
      jMenu1.setText(MessageManager.getString("label.group"));
      pdbStructureDialog.setText(MessageManager
              .getString("label.show_pdbstruct_dialog"));
          hideInsertions_actionPerformed(e);
        }
      });
 -    /*
 -     * annotationMenuItem.setText("By Annotation");
 -     * annotationMenuItem.addActionListener(new ActionListener() { public void
 -     * actionPerformed(ActionEvent actionEvent) {
 -     * annotationMenuItem_actionPerformed(actionEvent); } });
 -     */
 +
      groupMenu.add(sequenceSelDetails);
      add(groupMenu);
      add(sequenceMenu);
      sequenceMenu.add(sequenceName);
      sequenceMenu.add(sequenceDetails);
      sequenceMenu.add(makeReferenceSeq);
-     colourMenu.add(textColour);
-     colourMenu.add(noColourmenuItem);
-     colourMenu.add(clustalColour);
-     colourMenu.add(BLOSUM62Colour);
-     colourMenu.add(PIDColour);
-     colourMenu.add(zappoColour);
-     colourMenu.add(taylorColour);
-     colourMenu.add(hydrophobicityColour);
-     colourMenu.add(helixColour);
-     colourMenu.add(strandColour);
-     colourMenu.add(turnColour);
-     colourMenu.add(buriedColour);
-     colourMenu.add(nucleotideMenuItem);
-     if (ap.getAlignment().isNucleotide())
-     {
-       // JBPNote - commented since the colourscheme isn't functional
-       colourMenu.add(purinePyrimidineColour);
-     }
-     colourMenu.add(userDefinedColour);
  
-     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
-     {
-       java.util.Enumeration userColours = jalview.gui.UserDefinedColours
-               .getUserColourSchemes().keys();
+     initColourMenu();
+     buildColourMenu();
  
-       while (userColours.hasMoreElements())
-       {
-         JMenuItem item = new JMenuItem(userColours.nextElement().toString());
-         item.addActionListener(new ActionListener()
-         {
-           @Override
-           public void actionPerformed(ActionEvent evt)
-           {
-             userDefinedColour_actionPerformed(evt);
-           }
-         });
-         colourMenu.add(item);
-       }
-     }
-     colourMenu.addSeparator();
-     colourMenu.add(abovePIDColour);
-     colourMenu.add(conservationMenuItem);
      editMenu.add(copy);
      editMenu.add(cut);
      editMenu.add(editSequence);
      jMenu1.add(showColourText);
      jMenu1.add(outline);
      jMenu1.add(displayNonconserved);
-     noColourmenuItem.setText(MessageManager.getString("label.none"));
-     noColourmenuItem.addActionListener(new java.awt.event.ActionListener()
+   }
+   
+   /**
+    * Constructs the entries for the colour menu
+    */
+   protected void initColourMenu()
+   {
+     colourMenu.setText(MessageManager.getString("label.group_colour"));
+     textColour.setText(MessageManager.getString("label.text_colour"));
+     textColour.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
        {
-         noColourmenuItem_actionPerformed();
+         textColour_actionPerformed();
        }
      });
  
-     clustalColour.setText(MessageManager
-             .getString("label.clustalx_colours"));
-     clustalColour.addActionListener(new java.awt.event.ActionListener()
-     {
-       @Override
-       public void actionPerformed(ActionEvent e)
-       {
-         clustalColour_actionPerformed();
-       }
-     });
-     zappoColour.setText(MessageManager.getString("label.zappo"));
-     zappoColour.addActionListener(new java.awt.event.ActionListener()
-     {
-       @Override
-       public void actionPerformed(ActionEvent e)
-       {
-         zappoColour_actionPerformed();
-       }
-     });
-     taylorColour.setText(MessageManager.getString("label.taylor"));
-     taylorColour.addActionListener(new java.awt.event.ActionListener()
-     {
-       @Override
-       public void actionPerformed(ActionEvent e)
-       {
-         taylorColour_actionPerformed();
-       }
-     });
-     hydrophobicityColour.setText(MessageManager
-             .getString("label.hydrophobicity"));
-     hydrophobicityColour
-             .addActionListener(new java.awt.event.ActionListener()
-             {
-               @Override
-               public void actionPerformed(ActionEvent e)
-               {
-                 hydrophobicityColour_actionPerformed();
-               }
-             });
-     helixColour.setText(MessageManager.getString("label.helix_propensity"));
-     helixColour.addActionListener(new java.awt.event.ActionListener()
-     {
-       @Override
-       public void actionPerformed(ActionEvent e)
-       {
-         helixColour_actionPerformed();
-       }
-     });
-     strandColour.setText(MessageManager
-             .getString("label.strand_propensity"));
-     strandColour.addActionListener(new java.awt.event.ActionListener()
-     {
-       @Override
-       public void actionPerformed(ActionEvent e)
-       {
-         strandColour_actionPerformed();
-       }
-     });
-     turnColour.setText(MessageManager.getString("label.turn_propensity"));
-     turnColour.addActionListener(new java.awt.event.ActionListener()
-     {
-       @Override
-       public void actionPerformed(ActionEvent e)
-       {
-         turnColour_actionPerformed();
-       }
-     });
-     buriedColour.setText(MessageManager.getString("label.buried_index"));
-     buriedColour.addActionListener(new java.awt.event.ActionListener()
-     {
-       @Override
-       public void actionPerformed(ActionEvent e)
-       {
-         buriedColour_actionPerformed();
-       }
-     });
      abovePIDColour.setText(MessageManager
-             .getString("label.above_identity_percentage"));
-     abovePIDColour.addActionListener(new java.awt.event.ActionListener()
+             .getString("label.above_identity_threshold"));
+     abovePIDColour.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
        {
-         abovePIDColour_actionPerformed();
+         abovePIDColour_actionPerformed(abovePIDColour.isSelected());
        }
      });
-     userDefinedColour.setText(MessageManager
-             .getString("action.user_defined"));
-     userDefinedColour.addActionListener(new java.awt.event.ActionListener()
+     modifyPID.setText(MessageManager
+             .getString("label.modify_identity_threshold"));
+     modifyPID.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
        {
-         userDefinedColour_actionPerformed(e);
+         modifyPID_actionPerformed();
        }
      });
-     PIDColour
-             .setText(MessageManager.getString("label.percentage_identity"));
-     PIDColour.addActionListener(new java.awt.event.ActionListener()
+     conservationMenuItem.setText(MessageManager
+             .getString("action.by_conservation"));
+     conservationMenuItem.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
        {
-         PIDColour_actionPerformed();
+         conservationMenuItem_actionPerformed(conservationMenuItem
+                 .isSelected());
        }
      });
-     BLOSUM62Colour.setText(MessageManager.getString("label.blosum62"));
-     BLOSUM62Colour.addActionListener(new java.awt.event.ActionListener()
+     modifyConservation.setText(MessageManager
+             .getString("label.modify_conservation_threshold"));
+     modifyConservation.addActionListener(new ActionListener()
      {
        @Override
        public void actionPerformed(ActionEvent e)
        {
-         BLOSUM62Colour_actionPerformed();
+         modifyConservation_actionPerformed();
        }
      });
-     purinePyrimidineColour.setText(MessageManager
-             .getString("label.purine_pyrimidine"));
-     purinePyrimidineColour
-             .addActionListener(new java.awt.event.ActionListener()
-             {
-               @Override
-               public void actionPerformed(ActionEvent e)
-               {
-                 purinePyrimidineColour_actionPerformed();
-               }
-             });
+   }
  
-     /*
-      * covariationColour.addActionListener(new java.awt.event.ActionListener() {
-      * public void actionPerformed(ActionEvent e) {
-      * covariationColour_actionPerformed(); } });
-      */
+   /**
+    * Builds the group colour sub-menu, including any user-defined colours which
+    * were loaded at startup or during the Jalview session
+    */
+   protected void buildColourMenu()
+   {
+     SequenceGroup sg = ap.av.getSelectionGroup();
+     if (sg == null)
+     {
+       /*
+        * popup menu with no sequence group scope
+        */
+       return;
+     }
+     colourMenu.removeAll();
+     colourMenu.add(textColour);
+     colourMenu.addSeparator();
  
-     conservationMenuItem.setText(MessageManager
-             .getString("label.conservation"));
-     conservationMenuItem
-             .addActionListener(new java.awt.event.ActionListener()
-             {
-               @Override
-               public void actionPerformed(ActionEvent e)
-               {
-                 conservationMenuItem_actionPerformed();
-               }
-             });
+     ColourMenuHelper.addMenuItems(colourMenu, this, sg, false);
+     colourMenu.addSeparator();
+     colourMenu.add(conservationMenuItem);
+     colourMenu.add(modifyConservation);
+     colourMenu.add(abovePIDColour);
+     colourMenu.add(modifyPID);
+   }
+   protected void modifyConservation_actionPerformed()
+   {
+     SequenceGroup sg = getGroup();
+     if (sg.cs != null)
+     {
+       SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());
+       SliderPanel.showConservationSlider();
+     }
+   }
+   protected void modifyPID_actionPerformed()
+   {
+     SequenceGroup sg = getGroup();
+     if (sg.cs != null)
+     {
+       // int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup()
+       // .getName());
+       // sg.cs.setThreshold(threshold, ap.av.isIgnoreGapsConsensus());
+       SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup()
+               .getName());
+       SliderPanel.showPIDSlider();
+     }
    }
  
    /**
       * Temporary store to hold distinct calcId / type pairs for the tooltip.
       * Using TreeMap means calcIds are shown in alphabetical order.
       */
-     Map<String, String> tipEntries = new TreeMap<String, String>();
+     SortedMap<String, String> tipEntries = new TreeMap<String, String>();
      final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<SequenceI, List<AlignmentAnnotation>>();
      AlignmentI al = this.ap.av.getAlignment();
      AlignmentUtils.findAddableReferenceAnnotations(forSequences,
      PaintRefresher.Refresh(this, ap.av.getSequenceSetId());
    }
  
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void clustalColour_actionPerformed()
-   {
-     SequenceGroup sg = getGroup();
-     sg.cs = new ClustalxColourScheme(sg, ap.av.getHiddenRepSequences());
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void zappoColour_actionPerformed()
-   {
-     getGroup().cs = new ZappoColourScheme();
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void taylorColour_actionPerformed()
-   {
-     getGroup().cs = new TaylorColourScheme();
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void hydrophobicityColour_actionPerformed()
-   {
-     getGroup().cs = new HydrophobicColourScheme();
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void helixColour_actionPerformed()
-   {
-     getGroup().cs = new HelixColourScheme();
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void strandColour_actionPerformed()
-   {
-     getGroup().cs = new StrandColourScheme();
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void turnColour_actionPerformed()
-   {
-     getGroup().cs = new TurnColourScheme();
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void buriedColour_actionPerformed()
-   {
-     getGroup().cs = new BuriedColourScheme();
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   public void nucleotideMenuItem_actionPerformed()
-   {
-     getGroup().cs = new NucleotideColourScheme();
-     refresh();
-   }
-   protected void purinePyrimidineColour_actionPerformed()
-   {
-     getGroup().cs = new PurinePyrimidineColourScheme();
-     refresh();
-   }
    /*
     * protected void covariationColour_actionPerformed() { getGroup().cs = new
     * CovariationColourScheme(sequence.getAnnotation()[0]); refresh(); }
    /**
     * DOCUMENT ME!
     * 
+    * @param selected
+    * 
     * @param e
     *          DOCUMENT ME!
     */
-   protected void abovePIDColour_actionPerformed()
+   public void abovePIDColour_actionPerformed(boolean selected)
    {
      SequenceGroup sg = getGroup();
      if (sg.cs == null)
        return;
      }
  
-     if (abovePIDColour.isSelected())
+     if (selected)
      {
        sg.cs.setConsensus(AAFrequency.calculate(
                sg.getSequences(ap.av.getHiddenRepSequences()),
                sg.getStartRes(), sg.getEndRes() + 1));
  
-       int threshold = SliderPanel.setPIDSliderSource(ap, sg.cs, getGroup()
+       int threshold = SliderPanel.setPIDSliderSource(ap,
+               sg.getGroupColourScheme(), getGroup()
                .getName());
  
        sg.cs.setThreshold(threshold, ap.av.isIgnoreGapsConsensus());
      // remove PIDColouring
      {
        sg.cs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
+       SliderPanel.hidePIDSlider();
      }
+     modifyPID.setEnabled(selected);
  
      refresh();
    }
  
    /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void userDefinedColour_actionPerformed(ActionEvent e)
-   {
-     SequenceGroup sg = getGroup();
-     if (e.getSource().equals(userDefinedColour))
-     {
-       new UserDefinedColours(ap, sg);
-     }
-     else
-     {
-       UserColourScheme udc = (UserColourScheme) UserDefinedColours
-               .getUserColourSchemes().get(e.getActionCommand());
-       sg.cs = udc;
-     }
-     refresh();
-   }
-   /**
     * Open a panel where the user can choose which types of sequence annotation
     * to show or hide.
     * 
     * @param e
     *          DOCUMENT ME!
     */
-   protected void PIDColour_actionPerformed()
-   {
-     SequenceGroup sg = getGroup();
-     sg.cs = new PIDColourScheme();
-     sg.cs.setConsensus(AAFrequency.calculate(
-             sg.getSequences(ap.av.getHiddenRepSequences()),
-             sg.getStartRes(), sg.getEndRes() + 1));
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void BLOSUM62Colour_actionPerformed()
-   {
-     SequenceGroup sg = getGroup();
-     sg.cs = new Blosum62ColourScheme();
-     sg.cs.setConsensus(AAFrequency.calculate(
-             sg.getSequences(ap.av.getHiddenRepSequences()),
-             sg.getStartRes(), sg.getEndRes() + 1));
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void noColourmenuItem_actionPerformed()
-   {
-     getGroup().cs = null;
-     refresh();
-   }
-   /**
-    * DOCUMENT ME!
-    * 
-    * @param e
-    *          DOCUMENT ME!
-    */
-   protected void conservationMenuItem_actionPerformed()
+   public void conservationMenuItem_actionPerformed(boolean selected)
    {
      SequenceGroup sg = getGroup();
      if (sg.cs == null)
        return;
      }
  
-     if (conservationMenuItem.isSelected())
+     if (selected)
      {
        // JBPNote: Conservation name shouldn't be i18n translated
        Conservation c = new Conservation("Group", sg.getSequences(ap.av
  
        c.calculate();
        c.verdict(false, ap.av.getConsPercGaps());
        sg.cs.setConservation(c);
  
-       SliderPanel.setConservationSlider(ap, sg.cs, sg.getName());
+       SliderPanel.setConservationSlider(ap, sg.getGroupColourScheme(),
+               sg.getName());
        SliderPanel.showConservationSlider();
      }
      else
      // remove ConservationColouring
      {
        sg.cs.setConservation(null);
+       SliderPanel.hideConservationSlider();
      }
+     modifyConservation.setEnabled(selected);
  
      refresh();
    }
  
 -  public void annotationMenuItem_actionPerformed(ActionEvent actionEvent)
 -  {
 -    SequenceGroup sg = getGroup();
 -    if (sg == null)
 -    {
 -      return;
 -    }
 -
 -    AnnotationColourGradient acg = new AnnotationColourGradient(
 -            sequence.getAnnotation()[0], null,
 -            AnnotationColourGradient.NO_THRESHOLD);
 -
 -    acg.setPredefinedColours(true);
 -    sg.setColourScheme(acg);
 -
 -    refresh();
 -  }
 -
    /**
     * DOCUMENT ME!
     * 
      // or we simply trust the user wants
      // wysiwig behaviour
  
-     FileFormatI fileFormat = FileFormat.forName(e.getActionCommand());
+     FileFormatI fileFormat = FileFormats.getInstance().forName(e.getActionCommand());
      cap.setText(new FormatAdapter(ap).formatSequences(fileFormat, ap, true));
    }
  
      }
    }
  
+   /**
+    * Action on user selecting an item from the colour menu (that does not have
+    * its bespoke action handler)
+    * 
+    * @return
+    */
+   @Override
+   public void changeColour_actionPerformed(String colourSchemeName)
+   {
+     SequenceGroup sg = getGroup();
+     if (ResidueColourScheme.USER_DEFINED.equals(colourSchemeName))
+     {
+       /*
+        * open a panel to load or configure a user-defined colour scheme
+        */
+       new UserDefinedColours(ap, sg);
+     }
+     else
+     {
+       /*
+        * switch to the chosen colour scheme (or null for None)
+        */
+       ColourSchemeI colourScheme = ColourSchemes.getInstance().getColourScheme(
+               colourSchemeName, sg, ap.av.getHiddenRepSequences());
+       sg.setColourScheme(colourScheme);
+       if (colourScheme instanceof Blosum62ColourScheme
+               || colourScheme instanceof PIDColourScheme)
+       {
+         sg.cs.setConsensus(AAFrequency.calculate(
+                 sg.getSequences(ap.av.getHiddenRepSequences()),
+                 sg.getStartRes(), sg.getEndRes() + 1));
+       }
+     }
+     refresh();
+   }
  }
   */
  package jalview.schemes;
  
- import java.awt.Color;
- import java.util.IdentityHashMap;
- import java.util.Map;
  import jalview.datamodel.AlignmentAnnotation;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.AnnotatedCollectionI;
@@@ -31,6 -27,10 +27,12 @@@ import jalview.datamodel.Annotation
  import jalview.datamodel.GraphLine;
  import jalview.datamodel.SequenceCollectionI;
  import jalview.datamodel.SequenceI;
++import jalview.renderer.AnnotationRenderer;
++import jalview.util.Comparison;
+ import java.awt.Color;
+ import java.util.IdentityHashMap;
+ import java.util.Map;
  
  public class AnnotationColourGradient extends FollowerColourScheme
  {
  
    public static final int ABOVE_THRESHOLD = 1;
  
 -  public AlignmentAnnotation annotation;
 +  private final AlignmentAnnotation annotation;
  
 -  int aboveAnnotationThreshold = -1;
 +  private final int aboveAnnotationThreshold;
  
-   private boolean thresholdIsMinMax = false;
+   public boolean thresholdIsMinMax = false;
  
 -  GraphLine annotationThreshold;
 +  private GraphLine annotationThreshold;
  
 -  float r1, g1, b1, rr, gg, bb;
 +  private int redMin;
 +
 +  private int greenMin;
 +
 +  private int blueMin;
 +
 +  private int redRange;
 +
 +  private int greenRange;
 +
 +  private int blueRange;
  
    private boolean predefinedColours = false;
  
     */
    private boolean noGradient = false;
  
 -  IdentityHashMap<SequenceI, AlignmentAnnotation> seqannot = null;
 +  private IdentityHashMap<SequenceI, AlignmentAnnotation> seqannot = null;
  
    @Override
-   public ColourSchemeI applyTo(AnnotatedCollectionI sg,
+   public ColourSchemeI getInstance(AnnotatedCollectionI sg,
            Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
    {
      AnnotationColourGradient acg = new AnnotationColourGradient(annotation,
-             colourScheme, aboveAnnotationThreshold);
+             getColourScheme(), aboveAnnotationThreshold);
      acg.thresholdIsMinMax = thresholdIsMinMax;
      acg.annotationThreshold = (annotationThreshold == null) ? null
              : new GraphLine(annotationThreshold);
 -    acg.r1 = r1;
 -    acg.g1 = g1;
 -    acg.b1 = b1;
 -    acg.rr = rr;
 -    acg.gg = gg;
 -    acg.bb = bb;
 +    acg.redMin = redMin;
 +    acg.greenMin = greenMin;
 +    acg.blueMin = blueMin;
 +    acg.redRange = redRange;
 +    acg.greenRange = greenRange;
 +    acg.blueRange = blueRange;
      acg.predefinedColours = predefinedColours;
      acg.seqAssociated = seqAssociated;
      acg.noGradient = noGradient;
    {
      if (originalColour instanceof AnnotationColourGradient)
      {
-       colourScheme = ((AnnotationColourGradient) originalColour).colourScheme;
+       setColourScheme(((AnnotationColourGradient) originalColour)
+               .getColourScheme());
      }
      else
      {
-       colourScheme = originalColour;
+       setColourScheme(originalColour);
      }
  
      this.annotation = annotation;
        annotationThreshold = annotation.threshold;
      }
      // clear values so we don't get weird black bands...
 -    r1 = 254;
 -    g1 = 254;
 -    b1 = 254;
 -    rr = 0;
 -    gg = 0;
 -    bb = 0;
 +    redMin = 254;
 +    greenMin = 254;
 +    blueMin = 254;
 +    redRange = 0;
 +    greenRange = 0;
 +    blueRange = 0;
  
      noGradient = true;
      checkLimits();
        annotationThreshold = annotation.threshold;
      }
  
 -    r1 = minColour.getRed();
 -    g1 = minColour.getGreen();
 -    b1 = minColour.getBlue();
 +    redMin = minColour.getRed();
 +    greenMin = minColour.getGreen();
 +    blueMin = minColour.getBlue();
  
 -    rr = maxColour.getRed() - r1;
 -    gg = maxColour.getGreen() - g1;
 -    bb = maxColour.getBlue() - b1;
 +    redRange = maxColour.getRed() - redMin;
 +    greenRange = maxColour.getGreen() - greenMin;
 +    blueRange = maxColour.getBlue() - blueMin;
  
      noGradient = false;
      checkLimits();
  
    float aamin = 0f, aamax = 0f;
  
 -  public String getAnnotation()
 +  public AlignmentAnnotation getAnnotation()
    {
 -    return annotation.label;
 +    return annotation;
    }
  
    public int getAboveThreshold()
  
    public Color getMinColour()
    {
 -    return new Color((int) r1, (int) g1, (int) b1);
 +    return new Color(redMin, greenMin, blueMin);
    }
  
    public Color getMaxColour()
    {
 -    return new Color((int) (r1 + rr), (int) (g1 + gg), (int) (b1 + bb));
 +    return new Color(redMin + redRange, greenMin + greenRange, blueMin
 +            + blueRange);
    }
  
    /**
    }
  
    /**
--   * DOCUMENT ME!
++   * Returns the colour for a given character and position in a sequence
     * 
--   * @param n
--   *          DOCUMENT ME!
++   * @param c
++   *          the residue character
     * @param j
--   *          DOCUMENT ME!
--   * 
--   * @return DOCUMENT ME!
++   *          the aligned position
++   * @param seq
++   *          the sequence
++   * @return
     */
    @Override
    public Color findColour(char c, int j, SequenceI seq)
    {
--    Color currentColour = Color.white;
 -    AlignmentAnnotation annotation = (seqAssociated && seqannot != null ? seqannot
++    /*
++     * locate the annotation we are configured to colour by
++     */
 +    AlignmentAnnotation ann = (seqAssociated && seqannot != null ? seqannot
              .get(seq) : this.annotation);
-     if (ann == null)
 -    if (annotation == null)
++
++    /*
++     * if gap or no annotation at position, no colour (White)
++     */
++    if (ann == null || ann.annotations == null
++            || j >= ann.annotations.length || ann.annotations[j] == null
++            || Comparison.isGap(c))
      {
--      return currentColour;
++      return Color.white;
      }
-     if ((threshold == 0) || aboveThreshold(c, j))
 -    // if ((threshold == 0) || aboveThreshold(c, j))
 -    // {
 -    if (annotation.annotations != null && j < annotation.annotations.length
 -            && annotation.annotations[j] != null
 -            && !jalview.util.Comparison.isGap(c))
++
++    Annotation aj = ann.annotations[j];
++    // 'use original colours' => colourScheme != null
++    // -> look up colour to be used
++    // predefined colours => preconfigured shading
++    // -> only use original colours reference if thresholding enabled &
++    // minmax exists
++    // annotation.hasIcons => null or black colours replaced with glyph
++    // colours
++    // -> reuse original colours if present
++    // -> if thresholding enabled then return colour on non-whitespace glyph
++
++    /*
++     * if threshold applies, and annotation fails the test - no colour (white)
++     */
++    if (annotationThreshold != null)
      {
-       if (ann.annotations != null && j < ann.annotations.length
-               && ann.annotations[j] != null
-               && !jalview.util.Comparison.isGap(c))
 -      Annotation aj = annotation.annotations[j];
 -      // 'use original colours' => colourScheme != null
 -      // -> look up colour to be used
 -      // predefined colours => preconfigured shading
 -      // -> only use original colours reference if thresholding enabled &
 -      // minmax exists
 -      // annotation.hasIcons => null or black colours replaced with glyph
 -      // colours
 -      // -> reuse original colours if present
 -      // -> if thresholding enabled then return colour on non-whitespace glyph
 -
 -      if (aboveAnnotationThreshold == NO_THRESHOLD
 -              || (annotationThreshold != null && (aboveAnnotationThreshold == ABOVE_THRESHOLD ? aj.value >= annotationThreshold.value
 -                      : aj.value <= annotationThreshold.value)))
++      if ((aboveAnnotationThreshold == ABOVE_THRESHOLD && aj.value >= annotationThreshold.value)
++              || (aboveAnnotationThreshold == BELOW_THRESHOLD && aj.value > annotationThreshold.value))
        {
-         Annotation aj = ann.annotations[j];
-         // 'use original colours' => colourScheme != null
-         // -> look up colour to be used
-         // predefined colours => preconfigured shading
-         // -> only use original colours reference if thresholding enabled &
-         // minmax exists
-         // annotation.hasIcons => null or black colours replaced with glyph
-         // colours
-         // -> reuse original colours if present
-         // -> if thresholding enabled then return colour on non-whitespace glyph
-         if (aboveAnnotationThreshold == NO_THRESHOLD
-                 || (annotationThreshold != null && (aboveAnnotationThreshold == ABOVE_THRESHOLD ? aj.value >= annotationThreshold.value
-                         : aj.value <= annotationThreshold.value)))
 -        if (predefinedColours && aj.colour != null
 -                && !aj.colour.equals(Color.black))
 -        {
 -          currentColour = aj.colour;
 -        }
 -        else if (annotation.hasIcons
 -                && annotation.graph == AlignmentAnnotation.NO_GRAPH)
++        return Color.white;
++      }
++    }
++
++    /*
++     * If 'use original colours' then return the colour of the annotation
++     * at the aligned position - computed using the background colour scheme
++     */
++    if (predefinedColours && aj.colour != null
++            && !aj.colour.equals(Color.black))
++    {
++      return aj.colour;
++    }
++
++    Color result = Color.white;
++    if (ann.hasIcons && ann.graph == AlignmentAnnotation.NO_GRAPH)
++    {
++      /*
++       * secondary structure symbol colouring
++       */
++      if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.'
++              && aj.secondaryStructure != '-')
++      {
++        if (getColourScheme() != null)
          {
-           if (predefinedColours && aj.colour != null
-                   && !aj.colour.equals(Color.black))
-           {
-             currentColour = aj.colour;
-           }
-           else if (ann.hasIcons
-                   && ann.graph == AlignmentAnnotation.NO_GRAPH)
-           {
-             if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.'
-                     && aj.secondaryStructure != '-')
-             {
-               if (colourScheme != null)
-               {
-                 currentColour = colourScheme.findColour(c, j, seq);
-               }
-               else
-               {
-                 if (ann.isRNA())
-                 {
-                   currentColour = ColourSchemeProperty.rnaHelices[(int) aj.value];
-                 }
-                 else
-                 {
-                   currentColour = ann.annotations[j].secondaryStructure == 'H' ? jalview.renderer.AnnotationRenderer.HELIX_COLOUR
-                           : ann.annotations[j].secondaryStructure == 'E' ? jalview.renderer.AnnotationRenderer.SHEET_COLOUR
-                                   : jalview.renderer.AnnotationRenderer.STEM_COLOUR;
-                 }
-               }
-             }
-             else
-             {
-               //
-               return Color.white;
-             }
-           }
-           else if (noGradient)
 -          if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.'
 -                  && aj.secondaryStructure != '-')
 -          {
 -            if (getColourScheme() != null)
 -            {
 -              currentColour = getColourScheme().findColour(c, j, seq, null,
 -                      0f);
 -            }
 -            else
 -            {
 -              if (annotation.isRNA())
 -              {
 -                currentColour = ColourSchemeProperty.rnaHelices[(int) aj.value];
 -              }
 -              else
 -              {
 -                currentColour = annotation.annotations[j].secondaryStructure == 'H' ? jalview.renderer.AnnotationRenderer.HELIX_COLOUR
 -                        : annotation.annotations[j].secondaryStructure == 'E' ? jalview.renderer.AnnotationRenderer.SHEET_COLOUR
 -                                : jalview.renderer.AnnotationRenderer.STEM_COLOUR;
 -              }
 -            }
 -          }
 -          else
 -          {
 -            //
 -            return Color.white;
 -          }
++          result = getColourScheme().findColour(c, j, seq, null, 0f);
+         }
 -        else if (noGradient)
++        else
+         {
 -          if (getColourScheme() != null)
++          if (ann.isRNA())
            {
-             if (colourScheme != null)
-             {
-               currentColour = colourScheme.findColour(c, j, seq);
-             }
-             else
-             {
-               if (aj.colour != null)
-               {
-                 currentColour = aj.colour;
-               }
-             }
 -            currentColour = getColourScheme().findColour(c, j, seq, null,
 -                    0f);
++            result = ColourSchemeProperty.rnaHelices[(int) aj.value];
            }
            else
            {
-             currentColour = shadeCalculation(ann, j);
 -            if (aj.colour != null)
 -            {
 -              currentColour = aj.colour;
 -            }
++            result = ann.annotations[j].secondaryStructure == 'H' ? AnnotationRenderer.HELIX_COLOUR
++                    : ann.annotations[j].secondaryStructure == 'E' ? AnnotationRenderer.SHEET_COLOUR
++                            : AnnotationRenderer.STEM_COLOUR;
            }
          }
-         if (conservationColouring)
 -        else
++      }
++      else
++      {
++        return Color.white;
++      }
++    }
++    else if (noGradient)
++    {
++      if (getColourScheme() != null)
++      {
++        result = getColourScheme().findColour(c, j, seq, null, 0f);
++      }
++      else
++      {
++        if (aj.colour != null)
          {
-           currentColour = applyConservation(currentColour, j);
 -          currentColour = shadeCalculation(annotation, j);
++          result = aj.colour;
          }
        }
 -      // if (conservationColouring)
 -      // {
 -      // currentColour = applyConservation(currentColour, j);
 -      // }
      }
-     return currentColour;
 -    // }
 -    return currentColour;
++    else
++    {
++      result = shadeCalculation(ann, j);
++    }
++
++    return result;
    }
  
 -  private Color shadeCalculation(AlignmentAnnotation annotation, int j)
 +  /**
 +   * Returns a graduated colour for the annotation at the given column. If there
 +   * is a threshold value, and it is used as the top/bottom of the colour range,
 +   * and the value satisfies the threshold condition, then a colour
 +   * proportionate to the range from the threshold is calculated. For all other
 +   * cases, a colour proportionate to the annotation's min-max range is
 +   * calulated. Note that thresholding is _not_ done here (a colour is computed
 +   * even if threshold is not passed).
 +   * 
 +   * @param ann
 +   * @param col
 +   * @return
 +   */
 +  Color shadeCalculation(AlignmentAnnotation ann, int col)
    {
 -
 -    // calculate a shade
      float range = 1f;
 -    if (thresholdIsMinMax
 -            && annotation.threshold != null
 +    float value = ann.annotations[col].value;
 +    if (thresholdIsMinMax && ann.threshold != null
              && aboveAnnotationThreshold == ABOVE_THRESHOLD
 -            && annotation.annotations[j].value >= annotation.threshold.value)
 +            && value >= ann.threshold.value)
      {
 -      range = (annotation.annotations[j].value - annotation.threshold.value)
 -              / (annotation.graphMax - annotation.threshold.value);
 +      range = (value - ann.threshold.value)
 +              / (ann.graphMax - ann.threshold.value);
      }
 -    else if (thresholdIsMinMax && annotation.threshold != null
 +    else if (thresholdIsMinMax && ann.threshold != null
              && aboveAnnotationThreshold == BELOW_THRESHOLD
 -            && annotation.annotations[j].value >= annotation.graphMin)
 +            && value <= ann.threshold.value)
      {
 -      range = (annotation.annotations[j].value - annotation.graphMin)
 -              / (annotation.threshold.value - annotation.graphMin);
 +      range = (value - ann.graphMin) / (ann.threshold.value - ann.graphMin);
      }
      else
      {
 -      if (annotation.graphMax != annotation.graphMin)
 +      if (ann.graphMax != ann.graphMin)
        {
 -        range = (annotation.annotations[j].value - annotation.graphMin)
 -                / (annotation.graphMax - annotation.graphMin);
 +        range = (value - ann.graphMin) / (ann.graphMax - ann.graphMin);
        }
        else
        {
        }
      }
  
 -    int dr = (int) (rr * range + r1), dg = (int) (gg * range + g1), db = (int) (bb
 -            * range + b1);
 +    int dr = (int) (redRange * range + redMin);
 +    int dg = (int) (greenRange * range + greenMin);
 +    int db = (int) (blueRange * range + blueMin);
  
      return new Color(dr, dg, db);
 -
    }
  
    public boolean isPredefinedColours()
      seqAssociated = sassoc;
    }
  
 +  public boolean isThresholdIsMinMax()
 +  {
 +    return thresholdIsMinMax;
 +  }
 +
-   public void setThresholdIsMinMax(boolean thresholdIsMinMax)
++  public void setThresholdIsMinMax(boolean minMax)
++  {
++    this.thresholdIsMinMax = minMax;
++  }
++
+   @Override
+   public String getSchemeName()
+   {
+     return "Annotation";
+   }
+   @Override
+   public boolean isSimple()
    {
-     this.thresholdIsMinMax = thresholdIsMinMax;
+     return false;
    }
  }