/*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
- * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
+ * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
+ * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
import javax.swing.*;
import jalview.datamodel.*;
+import jalview.schemes.GraduatedColor;
/**
* DOCUMENT ME!
AlignViewport av;
Color resBoxColour;
+
/**
* global transparency for feature
*/
/**
* show scores as heights
*/
- protected boolean varyHeight=false;
+ protected boolean varyHeight = false;
synchronized public void drawSequence(Graphics g, SequenceI seq,
int start, int end, int y1)
if (sequenceFeatures[sfindex].begin <= start
&& sequenceFeatures[sfindex].end >= start)
{
- currentColour = av.featuresDisplayed
- .get(sequenceFeatures[sfindex].type);
+ // this is passed out to the overview and other sequence renderers (e.g. molecule viewer) to get displayed colour for rendered sequence
+ currentColour = new Integer(getColour(sequenceFeatures[sfindex]).getRGB());
+ // used to be retreived from av.featuresDisplayed
+ // currentColour = av.featuresDisplayed
+ // .get(sequenceFeatures[sfindex].type);
+
+
}
}
else if (sequenceFeatures[sfindex].type.equals("disulfide bond"))
seq,
seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
seq.findIndex(sequenceFeatures[sfindex].begin) - 1,
- new Color(((Integer) av.featuresDisplayed
- .get(sequenceFeatures[sfindex].type)).intValue()),
+ getColour(sequenceFeatures[sfindex])
+ //new Color(((Integer) av.featuresDisplayed
+ // .get(sequenceFeatures[sfindex].type)).intValue())
+ ,
start, end, y1);
renderFeature(
g,
seq,
seq.findIndex(sequenceFeatures[sfindex].end) - 1,
seq.findIndex(sequenceFeatures[sfindex].end) - 1,
- new Color(((Integer) av.featuresDisplayed
- .get(sequenceFeatures[sfindex].type)).intValue()),
+ getColour(sequenceFeatures[sfindex])
+ //new Color(((Integer) av.featuresDisplayed
+ // .get(sequenceFeatures[sfindex].type)).intValue())
+ ,
start, end, y1);
}
else
- if (av.showSeqFeaturesHeight && sequenceFeatures[sfindex].score!=Float.NaN)
- {
- renderScoreFeature(g, seq, seq
- .findIndex(sequenceFeatures[sfindex].begin) - 1, seq
- .findIndex(sequenceFeatures[sfindex].end) - 1,
- getColour(sequenceFeatures[sfindex].type), start, end, y1, normaliseScore(sequenceFeatures[sfindex]));
- } else
- {
- renderFeature(g, seq, seq
- .findIndex(sequenceFeatures[sfindex].begin) - 1, seq
- .findIndex(sequenceFeatures[sfindex].end) - 1,
- getColour(sequenceFeatures[sfindex].type), start, end, y1);
- }
+ if (showFeature(sequenceFeatures[sfindex]))
+ {
+ if (av.showSeqFeaturesHeight
+ && sequenceFeatures[sfindex].score != Float.NaN)
+ {
+ renderScoreFeature(g, seq, seq
+ .findIndex(sequenceFeatures[sfindex].begin) - 1,
+ seq.findIndex(sequenceFeatures[sfindex].end) - 1,
+ getColour(sequenceFeatures[sfindex]), start, end,
+ y1, normaliseScore(sequenceFeatures[sfindex]));
+ }
+ else
+ {
+ renderFeature(g, seq, seq
+ .findIndex(sequenceFeatures[sfindex].begin) - 1,
+ seq.findIndex(sequenceFeatures[sfindex].end) - 1,
+ getColour(sequenceFeatures[sfindex]), start, end,
+ y1);
+ }
+ }
}
1.0f));
}
}
+
Hashtable minmax = new Hashtable();
+
/**
* normalise a score against the max/min bounds for the feature type.
+ *
* @param sequenceFeature
- * @return byte[] { signed, normalised signed (-127 to 127) or unsigned (0-255) value.
+ * @return byte[] { signed, normalised signed (-127 to 127) or unsigned
+ * (0-255) value.
*/
private final byte[] normaliseScore(SequenceFeature sequenceFeature)
{
- float[] mm = (float[]) minmax.get(sequenceFeature.type);
- final byte[] r=new byte[] { 0, (byte) 255};
- if (mm!=null)
+ float[] mm = ((float[][]) minmax.get(sequenceFeature.type))[0];
+ final byte[] r = new byte[]
+ { 0, (byte) 255 };
+ if (mm != null)
{
- if (r[0]!=0 || mm[0]<0.0)
+ if (r[0] != 0 || mm[0] < 0.0)
+ {
+ r[0] = 1;
+ r[1] = (byte) ((int) 128.0 + 127.0 * (sequenceFeature.score / mm[1]));
+ }
+ else
{
- r[0]=1;
- r[1]=(byte) ((int) 128.0+127.0*(sequenceFeature.score/mm[1]));
- } else {
- r[1]=(byte) ((int) 255.0*(sequenceFeature.score/mm[1]));
+ r[1] = (byte) ((int) 255.0 * (sequenceFeature.score / mm[1]));
}
}
return r;
}
}
}
+
void renderScoreFeature(Graphics g, SequenceI seq, int fstart, int fend,
Color featureColour, int start, int end, int y1, byte[] bs)
{
fend = end;
}
int pady = (y1 + av.charHeight) - av.charHeight / 5;
- int ystrt = 0,yend=av.charHeight;
- if (bs[0]!=0)
+ int ystrt = 0, yend = av.charHeight;
+ if (bs[0] != 0)
{
// signed - zero is always middle of residue line.
- if (bs[1]<128)
+ if (bs[1] < 128)
{
- yend = av.charHeight*(128-bs[1])/512;
- ystrt = av.charHeight-yend/2;
- } else {
- ystrt = av.charHeight/2;
- yend = av.charHeight*(bs[1]-128)/512;
+ yend = av.charHeight * (128 - bs[1]) / 512;
+ ystrt = av.charHeight - yend / 2;
+ }
+ else
+ {
+ ystrt = av.charHeight / 2;
+ yend = av.charHeight * (bs[1] - 128) / 512;
}
- } else {
- yend = av.charHeight*bs[1]/255;
- ystrt = av.charHeight-yend;
+ }
+ else
+ {
+ yend = av.charHeight * bs[1] / 255;
+ ystrt = av.charHeight - yend;
}
for (i = fstart; i <= fend; i++)
}
g.setColor(featureColour);
- int x=(i-start)*av.charWidth;
+ int x = (i - start) * av.charWidth;
g.drawRect(x, y1, av.charWidth, av.charHeight);
- g.fillRect(x, y1+ystrt, av.charWidth,
- yend);
+ g.fillRect(x, y1 + ystrt, av.charWidth, yend);
if (offscreenRender || !av.validCharWidth)
{
}
}
}
- if (minmax==null)
+ if (minmax == null)
{
minmax = new Hashtable();
}
{
allfeatures.addElement(features[index].getType());
}
- if (features[index].score!=Float.NaN)
- {
- float[] mm = (float[]) minmax.get(features[index].getType());
- if (mm==null)
+ if (features[index].score != Float.NaN)
+ {
+ int nonpos= features[index].getBegin()>=1 ? 0 : 1;
+ float[][] mm = (float[][]) minmax.get(features[index].getType());
+ if (mm == null)
{
- mm = new float[] { features[index].score,features[index].score};
+ mm = new float[][] {null, null };
minmax.put(features[index].getType(), mm);
- } else {
- if (mm[0]>features[index].score)
+ }
+ if (mm[nonpos]==null)
+ {
+ mm[nonpos] = new float[] { features[index].score, features[index].score };
+
+ }
+ else
+ {
+ if (mm[nonpos][0] > features[index].score)
{
- mm[0] = features[index].score;
+ mm[nonpos][0] = features[index].score;
}
- if (mm[1]<features[index].score)
+ if (mm[nonpos][1] < features[index].score)
{
- mm[1] = features[index].score;
+ mm[nonpos][1] = features[index].score;
}
}
}
* types, in the order given by getOrder or the order given in allFeatures.
* Note. this operates directly on the featureOrder hash for efficiency. TODO:
* eliminate the float storage for computing/recalling the persistent ordering
- *
+ * New Cability: updates min/max for colourscheme range if its dynamic
* @param allFeatures
*/
private void updateRenderOrder(Vector allFeatures)
Vector allfeatures = new Vector(allFeatures);
String[] oldRender = renderOrder;
renderOrder = new String[allfeatures.size()];
+ Object mmrange,fc=null;
boolean initOrders = (featureOrder == null);
int opos = 0;
if (oldRender != null && oldRender.length > 0)
renderOrder[opos++] = oldRender[j]; // existing features always
// appear below new features
allfeatures.removeElement(oldRender[j]);
+ if (minmax!=null)
+ {
+ mmrange = minmax.get(oldRender[j]);
+ if (mmrange!=null)
+ {
+ fc = featureColours.get(oldRender[j]);
+ if (fc!=null && fc instanceof GraduatedColor && ((GraduatedColor)fc).isAutoScale())
+ {
+ ((GraduatedColor) fc).updateBounds(((float[][])mmrange)[0][0],((float[][])mmrange)[0][1]);
+ }
+ }
}
}
}
+ }
}
if (allfeatures.size() == 0)
{
while (en.hasMoreElements())
{
newf[i] = en.nextElement().toString();
+ if (minmax!=null)
+ {
+ // update from new features minmax if necessary
+ mmrange = minmax.get(newf[i]);
+ if (mmrange!=null)
+ {
+ fc = featureColours.get(newf[i]);
+ if (fc!=null && fc instanceof GraduatedColor && ((GraduatedColor)fc).isAutoScale())
+ {
+ ((GraduatedColor) fc).updateBounds(((float[][])mmrange)[0][0],((float[][])mmrange)[0][1]);
+ }
+ }
+ }
if (initOrders || !featureOrder.containsKey(newf[i]))
{
int denom = initOrders ? allfeatures.size() : featureOrder.size();
i--;
}
if (iSize > 1 && sort)
+ {
jalview.util.QuickSort.sort(sortOrder, newf);
+ }
sortOrder = null;
System.arraycopy(newf, 0, renderOrder, opos, newf.length);
}
-
- public Color getColour(String featureType)
- {
- if (!featureColours.containsKey(featureType))
+ /**
+ * get a feature style object for the given type string.
+ * Creates a java.awt.Color for a featureType with no existing
+ * colourscheme.
+ * TODO: replace return type with object implementing standard abstract colour/style interface
+ * @param featureType
+ * @return java.awt.Color or GraduatedColor
+ */
+ public Object getFeatureStyle(String featureType) {
+ Object fc = featureColours.get(featureType);
+ if (fc == null)
{
jalview.schemes.UserColourScheme ucs = new jalview.schemes.UserColourScheme();
Color col = ucs.createColourFromName(featureType);
- featureColours.put(featureType, col);
- return col;
+ featureColours.put(featureType, fc = col);
+ }
+ return fc;
+ }
+ /**
+ * return a nominal colour for this feature
+ * @param featureType
+ * @return standard color, or maximum colour for graduated colourscheme
+ */
+ public Color getColour(String featureType)
+ {
+ Object fc = getFeatureStyle(featureType);
+
+ if (fc instanceof Color)
+ {
+ return (Color) fc;
+ }
+ else
+ {
+ if (fc instanceof GraduatedColor)
+ {
+ return ((GraduatedColor) fc).getMaxColor();
+ }
+ }
+ throw new Error("Implementation Error: Unrecognised render object "+fc.getClass()+" for features of type "+featureType);
+ }
+
+ /**
+ * calculate the render colour for a specific feature using current feature settings.
+ *
+ * @param feature
+ * @return render colour for the given feature
+ */
+ public Color getColour(SequenceFeature feature)
+ {
+ Object fc = getFeatureStyle(feature.getType());
+ if (fc instanceof Color)
+ {
+ return (Color) fc;
}
else
- return (Color) featureColours.get(featureType);
+ {
+ if (fc instanceof GraduatedColor)
+ {
+ return ((GraduatedColor) fc).findColor(feature);
+ }
+ }
+ throw new Error("Implementation Error: Unrecognised render object "+fc.getClass()+" for features of type "+feature.getType());
+ }
+ private boolean showFeature(SequenceFeature sequenceFeature)
+ {
+ Object fc = getFeatureStyle(sequenceFeature.type);
+ if (fc instanceof GraduatedColor)
+ {
+ return ((GraduatedColor) fc).isColored(sequenceFeature);
+ } else { return true; }
}
+ //// /////////////
+ //// Feature Editing Dialog
+ //// Will be refactored in next release.
+
static String lastFeatureAdded;
static String lastFeatureGroupAdded;
static String lastDescriptionAdded;
-
+ Object oldcol,fcol;
int featureIndex = 0;
boolean amendFeatures(final SequenceI[] sequences,
featureIndex = 0;
- JPanel bigPanel = new JPanel(new BorderLayout());
+ final JPanel bigPanel = new JPanel(new BorderLayout());
final JComboBox overlaps;
final JTextField name = new JTextField(25);
final JTextField source = new JTextField(25);
final JSpinner end = new JSpinner();
start.setPreferredSize(new Dimension(80, 20));
end.setPreferredSize(new Dimension(80, 20));
-
- final JPanel colour = new JPanel();
- colour.setBorder(BorderFactory.createEtchedBorder());
- colour.setMaximumSize(new Dimension(40, 10));
+ final FeatureRenderer me = this;
+ final JLabel colour = new JLabel();
+ colour.setOpaque(true);
+ //colour.setBorder(BorderFactory.createEtchedBorder());
+ colour.setMaximumSize(new Dimension(30, 16));
colour.addMouseListener(new MouseAdapter()
{
+ FeatureColourChooser fcc =null;
public void mousePressed(MouseEvent evt)
{
+ if (fcol instanceof Color)
+ {
Color col = JColorChooser.showDialog(Desktop.desktop,
- "Select Feature Colour", colour.getBackground());
+ "Select Feature Colour", ((Color)fcol));
if (col != null)
- colour.setBackground(col);
-
+ {
+ fcol = col;
+ updateColourButton(bigPanel,colour,col);
+ }
+ } else {
+
+ if (fcc==null) {
+ final String type = features[featureIndex].getType();
+ fcc = new FeatureColourChooser(me, type);
+ fcc.setRequestFocusEnabled(true);
+ fcc.requestFocus();
+
+ fcc.addActionListener(new ActionListener() {
+
+ public void actionPerformed(ActionEvent e)
+ {
+ fcol = fcc.getLastColour();
+ fcc = null;
+ setColour(type, fcol);
+ updateColourButton(bigPanel,colour,fcol);
+ }
+ }
+ );
+
+ }
+ }
}
});
-
JPanel tmp = new JPanel();
JPanel panel = new JPanel(new GridLayout(3, 1));
ap.seqPanel.seqCanvas.highlightSearchResults(highlight);
}
- Color col = getColour(name.getText());
+ Object col = getFeatureStyle(name.getText());
if (col == null)
{
col = new jalview.schemes.UserColourScheme()
.createColourFromName(name.getText());
}
-
- colour.setBackground(col);
+ oldcol = fcol = col;
+ updateColourButton(bigPanel, colour,col);
}
});
tmp.add(new JLabel("Colour: ", JLabel.RIGHT));
tmp.add(colour);
colour.setPreferredSize(new Dimension(150, 15));
-
+ colour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 9));
+ colour.setForeground(Color.black);
+ colour.setHorizontalAlignment(SwingConstants.CENTER);
+ colour.setVerticalAlignment(SwingConstants.CENTER);
+ colour.setHorizontalTextPosition(SwingConstants.CENTER);
+ colour.setVerticalTextPosition(SwingConstants.CENTER);
bigPanel.add(panel, BorderLayout.NORTH);
panel = new JPanel();
start.setValue(new Integer(features[0].getBegin()));
end.setValue(new Integer(features[0].getEnd()));
description.setText(features[0].getDescription());
- colour.setBackground(getColour(name.getText()));
-
+ updateColourButton(bigPanel, colour, (oldcol = fcol = getFeatureStyle(name.getText())));
Object[] options;
if (!newFeatures)
{
lastFeatureAdded = name.getText().trim();
lastFeatureGroupAdded = source.getText().trim();
lastDescriptionAdded = description.getText().replaceAll("\n", " ");
-
+ // TODO: determine if the null feature group is valid
if (lastFeatureGroupAdded.length() < 1)
lastFeatureGroupAdded = null;
}
sf.featureGroup = lastFeatureGroupAdded;
sf.description = lastDescriptionAdded;
- setColour(sf.type, colour.getBackground());
- av.featuresDisplayed.put(sf.type, new Integer(colour
- .getBackground().getRGB()));
+ setColour(sf.type, fcol);
+ av.featuresDisplayed.put(sf.type, getColour(sf.type));
try
{
featureGroups = new Hashtable();
featureGroups.put(lastFeatureGroupAdded, new Boolean(true));
}
-
- Color col = colour.getBackground();
- setColour(lastFeatureAdded, colour.getBackground());
- av.featuresDisplayed.put(lastFeatureAdded,
- new Integer(col.getRGB()));
+ setColour(lastFeatureAdded, fcol);
+ av.featuresDisplayed.put(lastFeatureAdded, getColour(lastFeatureAdded));
findAllFeatures(false);
return true;
}
- public void setColour(String featureType, Color col)
+ /**
+ * update the amend feature button dependent on the given style
+ * @param bigPanel
+ * @param col
+ * @param col2
+ */
+ protected void updateColourButton(JPanel bigPanel, JLabel colour, Object col2)
{
- featureColours.put(featureType, col);
+ colour.removeAll();
+ colour.setIcon(null);
+ colour.setToolTipText(null);
+ colour.setText("");
+
+ if (col2 instanceof Color) {
+ colour.setBackground((Color)col2);
+ } else {
+ colour.setBackground(bigPanel.getBackground());
+ colour.setForeground(Color.black);
+ FeatureSettings.renderGraduatedColor(colour, (GraduatedColor) col2);
+ //colour.setForeground(colour.getBackground());
+ }
+ }
+
+ public void setColour(String featureType, Object col)
+ {
+ // overwrite
+// Color _col = (col instanceof Color) ? ((Color) col) : (col instanceof GraduatedColor) ? ((GraduatedColor) col).getMaxColor() : null;
+// Object c = featureColours.get(featureType);
+// if (c == null || c instanceof Color || (c instanceof GraduatedColor && !((GraduatedColor)c).getMaxColor().equals(_col)))
+ {
+ featureColours.put(featureType, col);
+ }
}
public void setTransparency(float value)
for (int i = 0; i < data.length; i++)
{
String type = data[i][0].toString();
- setColour(type, (Color) data[i][1]);
+ setColour(type, data[i][1]); // todo : typesafety - feature color interface object
if (((Boolean) data[i][2]).booleanValue())
{
av.featuresDisplayed.put(type, new Integer(getColour(type)