From 2888e7307e1f7c8239234941498cb86e8c65ab36 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Mon, 13 Mar 2017 16:42:23 +0000 Subject: [PATCH] JAL-2438 FeatureColourFinder refactored from FeatureRenderer, fr not cloned for structure viewers --- src/MCview/AppletPDBCanvas.java | 8 +- src/MCview/PDBCanvas.java | 6 +- src/jalview/api/FeatureRenderer.java | 19 +- src/jalview/api/SequenceRenderer.java | 4 +- src/jalview/appletgui/AppletJmolBinding.java | 20 +- src/jalview/appletgui/ExtJmol.java | 6 +- src/jalview/appletgui/OverviewPanel.java | 5 +- src/jalview/appletgui/SeqCanvas.java | 2 +- src/jalview/appletgui/SequenceRenderer.java | 10 +- src/jalview/ext/jmol/JalviewJmolBinding.java | 15 +- src/jalview/ext/jmol/JmolCommands.java | 12 +- src/jalview/ext/rbvi/chimera/ChimeraCommands.java | 38 +- .../ext/rbvi/chimera/JalviewChimeraBinding.java | 26 +- src/jalview/ext/varna/VarnaCommands.java | 11 +- src/jalview/gui/AppJmolBinding.java | 36 +- src/jalview/gui/FeatureRenderer.java | 4 +- src/jalview/gui/JalviewChimeraBindingModel.java | 14 +- src/jalview/gui/OverviewPanel.java | 18 +- src/jalview/gui/SeqCanvas.java | 2 +- src/jalview/gui/SequenceRenderer.java | 10 +- src/jalview/io/JSONFile.java | 5 +- .../javascript/MouseOverStructureListener.java | 4 +- .../renderer/seqfeatures/FeatureColourFinder.java | 79 ++++ .../renderer/seqfeatures/FeatureRenderer.java | 483 +++++++++++--------- .../structures/models/AAStructureBindingModel.java | 28 +- .../seqfeatures/FeatureRendererModel.java | 2 +- test/jalview/ext/jmol/JmolCommandsTest.java | 3 +- .../ext/rbvi/chimera/ChimeraCommandsTest.java | 3 +- .../models/AAStructureBindingModelTest.java | 17 +- 29 files changed, 508 insertions(+), 382 deletions(-) create mode 100644 src/jalview/renderer/seqfeatures/FeatureColourFinder.java diff --git a/src/MCview/AppletPDBCanvas.java b/src/MCview/AppletPDBCanvas.java index aac796c..1602cb4 100644 --- a/src/MCview/AppletPDBCanvas.java +++ b/src/MCview/AppletPDBCanvas.java @@ -28,6 +28,7 @@ import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.io.DataSourceType; import jalview.io.StructureFile; +import jalview.renderer.seqfeatures.FeatureColourFinder; import jalview.structure.AtomSpec; import jalview.structure.StructureListener; import jalview.structure.StructureMapping; @@ -577,6 +578,8 @@ public class AppletPDBCanvas extends Panel implements MouseListener, showFeatures = true; } + FeatureColourFinder finder = new FeatureColourFinder(fr); + PDBChain chain; if (bysequence && pdb != null) { @@ -607,7 +610,7 @@ public class AppletPDBCanvas extends Panel implements MouseListener, tmp.startCol = sr.getResidueBoxColour(sequence[s], pos); if (showFeatures) { - tmp.startCol = fr.findFeatureColour(tmp.startCol, + tmp.startCol = finder.findFeatureColour(tmp.startCol, sequence[s], pos); } } @@ -618,11 +621,10 @@ public class AppletPDBCanvas extends Panel implements MouseListener, tmp.endCol = sr.getResidueBoxColour(sequence[s], pos); if (showFeatures) { - tmp.endCol = fr.findFeatureColour(tmp.endCol, + tmp.endCol = finder.findFeatureColour(tmp.endCol, sequence[s], pos); } } - } } } diff --git a/src/MCview/PDBCanvas.java b/src/MCview/PDBCanvas.java index 292de91..ae58758 100644 --- a/src/MCview/PDBCanvas.java +++ b/src/MCview/PDBCanvas.java @@ -28,6 +28,7 @@ import jalview.gui.FeatureRenderer; import jalview.gui.SequenceRenderer; import jalview.io.DataSourceType; import jalview.io.StructureFile; +import jalview.renderer.seqfeatures.FeatureColourFinder; import jalview.structure.AtomSpec; import jalview.structure.StructureListener; import jalview.structure.StructureMapping; @@ -546,6 +547,7 @@ public class PDBCanvas extends JPanel implements MouseListener, showFeatures = true; } + FeatureColourFinder finder = new FeatureColourFinder(fr); PDBChain chain; if (bysequence && pdb != null) { @@ -576,7 +578,7 @@ public class PDBCanvas extends JPanel implements MouseListener, tmp.startCol = sr.getResidueBoxColour(sequence[s], pos); if (showFeatures) { - tmp.startCol = fr.findFeatureColour(tmp.startCol, + tmp.startCol = finder.findFeatureColour(tmp.startCol, sequence[s], pos); } } @@ -587,7 +589,7 @@ public class PDBCanvas extends JPanel implements MouseListener, tmp.endCol = sr.getResidueBoxColour(sequence[s], pos); if (showFeatures) { - tmp.endCol = fr.findFeatureColour(tmp.endCol, + tmp.endCol = finder.findFeatureColour(tmp.endCol, sequence[s], pos); } } diff --git a/src/jalview/api/FeatureRenderer.java b/src/jalview/api/FeatureRenderer.java index f54231e..b1813a6 100644 --- a/src/jalview/api/FeatureRenderer.java +++ b/src/jalview/api/FeatureRenderer.java @@ -24,6 +24,7 @@ import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import java.awt.Color; +import java.awt.Graphics; import java.util.List; import java.util.Map; @@ -46,9 +47,10 @@ public interface FeatureRenderer * - sequence providing features * @param r * - column position + * @param g * @return */ - Color findFeatureColour(Color col, SequenceI sequenceI, int r); + Color findFeatureColour(Color col, SequenceI sequenceI, int r, Graphics g); /** * trigger the feature discovery process for a newly created feature renderer. @@ -170,4 +172,19 @@ public interface FeatureRenderer */ void setVisible(String featureType); + /** + * Sets the transparency value, between 0 (full transparency) and 1 (no + * transparency) + * + * @param value + */ + void setTransparency(float value); + + /** + * Returns the transparency value, between 0 (full transparency) and 1 (no + * transparency) + * + * @return + */ + float getTransparency(); } diff --git a/src/jalview/api/SequenceRenderer.java b/src/jalview/api/SequenceRenderer.java index d708902..5e772a4 100644 --- a/src/jalview/api/SequenceRenderer.java +++ b/src/jalview/api/SequenceRenderer.java @@ -21,6 +21,7 @@ package jalview.api; import jalview.datamodel.SequenceI; +import jalview.renderer.seqfeatures.FeatureColourFinder; import java.awt.Color; @@ -29,6 +30,7 @@ public interface SequenceRenderer Color getResidueBoxColour(SequenceI sequenceI, int r); - Color getResidueColour(SequenceI seq, int position, FeatureRenderer fr); + Color getResidueColour(SequenceI seq, int position, + FeatureColourFinder finder); } diff --git a/src/jalview/appletgui/AppletJmolBinding.java b/src/jalview/appletgui/AppletJmolBinding.java index f938cad..8ddff52 100644 --- a/src/jalview/appletgui/AppletJmolBinding.java +++ b/src/jalview/appletgui/AppletJmolBinding.java @@ -54,21 +54,15 @@ class AppletJmolBinding extends JalviewJmolBinding public jalview.api.FeatureRenderer getFeatureRenderer( AlignmentViewPanel alignment) { - AlignmentPanel ap = (AlignmentPanel) alignment; - if (appletJmolBinding.ap.av.isShowSequenceFeatures()) + AlignmentPanel alignPanel = (AlignmentPanel) alignment; + if (alignPanel.av.isShowSequenceFeatures()) { - if (appletJmolBinding.fr == null) - { - appletJmolBinding.fr = new jalview.appletgui.FeatureRenderer( - appletJmolBinding.ap.av); - } - - appletJmolBinding.fr - .transferSettings(appletJmolBinding.ap.seqPanel.seqCanvas - .getFeatureRenderer()); + return alignPanel.getFeatureRenderer(); + } + else + { + return null; } - - return appletJmolBinding.fr; } @Override diff --git a/src/jalview/appletgui/ExtJmol.java b/src/jalview/appletgui/ExtJmol.java index 189fe88..b369318 100644 --- a/src/jalview/appletgui/ExtJmol.java +++ b/src/jalview/appletgui/ExtJmol.java @@ -82,10 +82,10 @@ public class ExtJmol extends JalviewJmolBinding @Override public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment) { - AlignmentPanel ap = (AlignmentPanel) alignment; - if (ap.av.isShowSequenceFeatures()) + AlignmentPanel alignPanel = (AlignmentPanel) alignment; + if (alignPanel.av.isShowSequenceFeatures()) { - return ap.getFeatureRenderer(); + return alignPanel.getFeatureRenderer(); } else { diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index 9b2be4c..8427c77 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -21,6 +21,7 @@ package jalview.appletgui; import jalview.datamodel.AlignmentI; +import jalview.renderer.seqfeatures.FeatureColourFinder; import java.awt.Color; import java.awt.Dimension; @@ -303,6 +304,8 @@ public class OverviewPanel extends Panel implements Runnable, .hasHiddenColumns(); boolean hiddenRow = false; AlignmentI alignment = av.getAlignment(); + + FeatureColourFinder finder = new FeatureColourFinder(fr); for (row = 0; row <= sequencesHeight; row++) { if (resizeAgain) @@ -353,7 +356,7 @@ public class OverviewPanel extends Panel implements Runnable, if (av.isShowSequenceFeatures()) { - color = fr.findFeatureColour(color, seq, lastcol); + color = finder.findFeatureColour(color, seq, lastcol); } } else diff --git a/src/jalview/appletgui/SeqCanvas.java b/src/jalview/appletgui/SeqCanvas.java index 5d6bb07..5ab3459 100755 --- a/src/jalview/appletgui/SeqCanvas.java +++ b/src/jalview/appletgui/SeqCanvas.java @@ -625,7 +625,7 @@ public class SeqCanvas extends Panel if (av.isShowSequenceFeatures()) { fr.drawSequence(g, nextSeq, startRes, endRes, offset - + ((i - startSeq) * avcharHeight)); + + ((i - startSeq) * avcharHeight), false); } // / Highlight search Results once all sequences have been drawn diff --git a/src/jalview/appletgui/SequenceRenderer.java b/src/jalview/appletgui/SequenceRenderer.java index 86d1f98..b5586c9 100755 --- a/src/jalview/appletgui/SequenceRenderer.java +++ b/src/jalview/appletgui/SequenceRenderer.java @@ -20,10 +20,10 @@ */ package jalview.appletgui; -import jalview.api.FeatureRenderer; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.renderer.ResidueShaderI; +import jalview.renderer.seqfeatures.FeatureColourFinder; import java.awt.Color; import java.awt.Font; @@ -96,20 +96,20 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer * * @param seq * @param position - * @param fr + * @param finder * @return */ @Override public Color getResidueColour(final SequenceI seq, int position, - FeatureRenderer fr) + FeatureColourFinder finder) { // TODO replace 8 or so code duplications with calls to this method // (refactored as needed) Color col = getResidueBoxColour(seq, position); - if (fr != null) + if (finder != null) { - col = fr.findFeatureColour(col, seq, position); + col = finder.findFeatureColour(col, seq, position); } return col; } diff --git a/src/jalview/ext/jmol/JalviewJmolBinding.java b/src/jalview/ext/jmol/JalviewJmolBinding.java index 82e188f..19e8b67 100644 --- a/src/jalview/ext/jmol/JalviewJmolBinding.java +++ b/src/jalview/ext/jmol/JalviewJmolBinding.java @@ -20,7 +20,7 @@ */ package jalview.ext.jmol; -import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.datamodel.AlignmentI; @@ -499,17 +499,15 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel /** * @param files * @param sr - * @param fr - * @param viewport + * @param viewPanel * @return */ @Override protected StructureMappingcommandSet[] getColourBySequenceCommands( - String[] files, SequenceRenderer sr, FeatureRenderer fr, - AlignViewportI viewport) + String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel) { return JmolCommands.getColourBySequenceCommand(getSsm(), files, - getSequence(), sr, fr, viewport); + getSequence(), sr, viewPanel); } /** @@ -1184,10 +1182,7 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel if (notifyLoaded) { FeatureRenderer fr = getFeatureRenderer(null); - if (fr != null) - { - fr.featuresAdded(); - } + fr.featuresAdded(); refreshGUI(); loadNotifiesHandled++; } diff --git a/src/jalview/ext/jmol/JmolCommands.java b/src/jalview/ext/jmol/JmolCommands.java index a809cae..a1ff3c5 100644 --- a/src/jalview/ext/jmol/JmolCommands.java +++ b/src/jalview/ext/jmol/JmolCommands.java @@ -21,11 +21,13 @@ package jalview.ext.jmol; import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; import jalview.datamodel.SequenceI; +import jalview.renderer.seqfeatures.FeatureColourFinder; import jalview.structure.StructureMapping; import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; @@ -53,9 +55,12 @@ public class JmolCommands */ public static StructureMappingcommandSet[] getColourBySequenceCommand( StructureSelectionManager ssm, String[] files, - SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr, - AlignViewportI viewport) + SequenceI[][] sequence, SequenceRenderer sr, + AlignmentViewPanel viewPanel) { + FeatureRenderer fr = viewPanel.getFeatureRenderer(); + FeatureColourFinder finder = new FeatureColourFinder(fr); + AlignViewportI viewport = viewPanel.getAlignViewport(); ColumnSelection cs = viewport.getColumnSelection(); AlignmentI al = viewport.getAlignment(); List cset = new ArrayList(); @@ -101,7 +106,8 @@ public class JmolCommands if (fr != null) { - col = fr.findFeatureColour(col, sequence[pdbfnum][s], r); + col = finder + .findFeatureColour(col, sequence[pdbfnum][s], r); } /* diff --git a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java index e665982..1d8b944 100644 --- a/src/jalview/ext/rbvi/chimera/ChimeraCommands.java +++ b/src/jalview/ext/rbvi/chimera/ChimeraCommands.java @@ -21,12 +21,14 @@ package jalview.ext.rbvi.chimera; import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; +import jalview.renderer.seqfeatures.FeatureColourFinder; import jalview.structure.StructureMapping; import jalview.structure.StructureMappingcommandSet; import jalview.structure.StructureSelectionManager; @@ -59,16 +61,16 @@ public class ChimeraCommands * @param sequence * @param sr * @param fr - * @param viewport + * @param viewPanel * @return */ public static StructureMappingcommandSet[] getColourBySequenceCommand( StructureSelectionManager ssm, String[] files, - SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr, - AlignViewportI viewport) + SequenceI[][] sequence, SequenceRenderer sr, + AlignmentViewPanel viewPanel) { Map colourMap = buildColoursMap(ssm, files, - sequence, sr, fr, viewport); + sequence, sr, viewPanel); List colourCommands = buildColourCommands(colourMap); @@ -186,9 +188,12 @@ public class ChimeraCommands */ protected static Map buildColoursMap( StructureSelectionManager ssm, String[] files, - SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr, - AlignViewportI viewport) + SequenceI[][] sequence, SequenceRenderer sr, + AlignmentViewPanel viewPanel) { + FeatureRenderer fr = viewPanel.getFeatureRenderer(); + FeatureColourFinder finder = new FeatureColourFinder(fr); + AlignViewportI viewport = viewPanel.getAlignViewport(); ColumnSelection cs = viewport.getColumnSelection(); AlignmentI al = viewport.getAlignment(); Map colourMap = new LinkedHashMap(); @@ -228,7 +233,7 @@ public class ChimeraCommands continue; } - Color colour = sr.getResidueColour(seq, r, fr); + Color colour = sr.getResidueColour(seq, r, finder); /* * darker colour for hidden regions @@ -310,16 +315,15 @@ public class ChimeraCommands * @param ssm * @param files * @param seqs - * @param fr - * @param alignment + * @param viewPanel * @return */ public static StructureMappingcommandSet getSetAttributeCommandsForFeatures( StructureSelectionManager ssm, String[] files, - SequenceI[][] seqs, FeatureRenderer fr, AlignmentI alignment) + SequenceI[][] seqs, AlignmentViewPanel viewPanel) { Map> featureMap = buildFeaturesMap( - ssm, files, seqs, fr, alignment); + ssm, files, seqs, viewPanel); List commands = buildSetAttributeCommands(featureMap); @@ -339,22 +343,28 @@ public class ChimeraCommands * @param ssm * @param files * @param seqs - * @param fr - * @param alignment + * @param viewPanel * @return */ protected static Map> buildFeaturesMap( StructureSelectionManager ssm, String[] files, - SequenceI[][] seqs, FeatureRenderer fr, AlignmentI alignment) + SequenceI[][] seqs, AlignmentViewPanel viewPanel) { Map> theMap = new LinkedHashMap>(); + FeatureRenderer fr = viewPanel.getFeatureRenderer(); + if (fr == null) + { + return theMap; + } + List visibleFeatures = fr.getDisplayedFeatureTypes(); if (visibleFeatures.isEmpty()) { return theMap; } + AlignmentI alignment = viewPanel.getAlignment(); for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++) { StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); diff --git a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index 9a570fc..fad3137 100644 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@ -20,9 +20,7 @@ */ package jalview.ext.rbvi.chimera; -import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; -import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.api.structures.JalviewStructureDisplayI; import jalview.bin.Cache; @@ -175,11 +173,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel { getSsm().addStructureViewerListener(this); // ssm.addSelectionListener(this); - FeatureRenderer fr = getFeatureRenderer(null); - if (fr != null) - { - fr.featuresAdded(); - } refreshGUI(); } return true; @@ -699,17 +692,15 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel /** * @param files * @param sr - * @param fr - * @param viewport + * @param viewPanel * @return */ @Override protected StructureMappingcommandSet[] getColourBySequenceCommands( - String[] files, SequenceRenderer sr, FeatureRenderer fr, - AlignViewportI viewport) + String[] files, SequenceRenderer sr, AlignmentViewPanel viewPanel) { return ChimeraCommands.getColourBySequenceCommand(getSsm(), files, - getSequence(), sr, fr, viewport); + getSequence(), sr, viewPanel); } /** @@ -1110,15 +1101,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel { // TODO refactor as required to pull up to an interface AlignmentI alignment = avp.getAlignment(); - FeatureRenderer fr = getFeatureRenderer(avp); - - /* - * fr is null if feature display is turned off - */ - if (fr == null) - { - return 0; - } String[] files = getPdbFile(); if (files == null) @@ -1128,7 +1110,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel StructureMappingcommandSet commandSet = ChimeraCommands .getSetAttributeCommandsForFeatures(getSsm(), files, - getSequence(), fr, alignment); + getSequence(), avp); String[] commands = commandSet.commands; if (commands.length > 10) { diff --git a/src/jalview/ext/varna/VarnaCommands.java b/src/jalview/ext/varna/VarnaCommands.java index a41e10e..617dc8f 100644 --- a/src/jalview/ext/varna/VarnaCommands.java +++ b/src/jalview/ext/varna/VarnaCommands.java @@ -20,10 +20,10 @@ */ package jalview.ext.varna; -import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.datamodel.AlignmentI; import jalview.datamodel.SequenceI; +import jalview.renderer.seqfeatures.FeatureColourFinder; import jalview.structure.StructureMapping; import jalview.structure.StructureSelectionManager; @@ -47,7 +47,8 @@ public class VarnaCommands */ public static String[] getColourBySequenceCommand( StructureSelectionManager ssm, String[] files, - SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr, + SequenceI[][] sequence, SequenceRenderer sr, + FeatureColourFinder fr, AlignmentI alignment) { ArrayList str = new ArrayList(); @@ -58,7 +59,9 @@ public class VarnaCommands StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]); if (mapping == null || mapping.length < 1) + { continue; + } int lastPos = -1; for (int s = 0; s < sequence[pdbfnum].length; s++) @@ -79,14 +82,18 @@ public class VarnaCommands int pos = mapping[m].getPDBResNum(asp.findPosition(r)); if (pos < 1 || pos == lastPos) + { continue; + } lastPos = pos; Color col = sr.getResidueBoxColour(sequence[pdbfnum][s], r); if (fr != null) + { col = fr.findFeatureColour(col, sequence[pdbfnum][s], r); + } String newSelcom = (mapping[m].getChain() != " " ? ":" + mapping[m].getChain() : "") + "/" diff --git a/src/jalview/gui/AppJmolBinding.java b/src/jalview/gui/AppJmolBinding.java index 75e0c5e..f822358 100644 --- a/src/jalview/gui/AppJmolBinding.java +++ b/src/jalview/gui/AppJmolBinding.java @@ -40,8 +40,6 @@ public class AppJmolBinding extends JalviewJmolBinding { private AppJmol appJmolWindow; - private FeatureRenderer fr = null; - public AppJmolBinding(AppJmol appJmol, StructureSelectionManager sSm, PDBEntry[] pdbentry, SequenceI[][] sequenceIs, DataSourceType protocol) { @@ -50,26 +48,6 @@ public class AppJmolBinding extends JalviewJmolBinding } @Override - public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment) - { - AlignmentPanel ap = (alignment == null) ? appJmolWindow - .getAlignmentPanel() : (AlignmentPanel) alignment; - if (ap.av.isShowSequenceFeatures()) - { - if (fr == null) - { - fr = (jalview.gui.FeatureRenderer) ap.cloneFeatureRenderer(); - } - else - { - ap.updateFeatureRenderer(fr); - } - } - - return fr; - } - - @Override public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment) { return new SequenceRenderer(((AlignmentPanel) alignment).av); @@ -215,4 +193,18 @@ public class AppJmolBinding extends JalviewJmolBinding { return appJmolWindow; } + + @Override + public jalview.api.FeatureRenderer getFeatureRenderer( + AlignmentViewPanel alignment) + { + AlignmentPanel ap = (alignment == null) ? appJmolWindow + .getAlignmentPanel() : (AlignmentPanel) alignment; + if (ap.av.isShowSequenceFeatures()) + { + return ap.av.getAlignPanel().getSeqPanel().seqCanvas.fr; + } + + return null; + } } diff --git a/src/jalview/gui/FeatureRenderer.java b/src/jalview/gui/FeatureRenderer.java index ed6a3c5..86b8eba 100644 --- a/src/jalview/gui/FeatureRenderer.java +++ b/src/jalview/gui/FeatureRenderer.java @@ -46,7 +46,6 @@ import java.util.Comparator; import javax.swing.JColorChooser; import javax.swing.JComboBox; import javax.swing.JLabel; -import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSpinner; @@ -61,8 +60,7 @@ import javax.swing.SwingConstants; * @version $Revision$ */ public class FeatureRenderer extends - jalview.renderer.seqfeatures.FeatureRenderer implements - jalview.api.FeatureRenderer + jalview.renderer.seqfeatures.FeatureRenderer { Color resBoxColour; diff --git a/src/jalview/gui/JalviewChimeraBindingModel.java b/src/jalview/gui/JalviewChimeraBindingModel.java index a1f05bd..c9b35d8 100644 --- a/src/jalview/gui/JalviewChimeraBindingModel.java +++ b/src/jalview/gui/JalviewChimeraBindingModel.java @@ -34,9 +34,6 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding { private ChimeraViewFrame cvf; - private FeatureRenderer fr = null; - - public JalviewChimeraBindingModel(ChimeraViewFrame chimeraViewFrame, StructureSelectionManager ssm, PDBEntry[] pdbentry, SequenceI[][] sequenceIs, DataSourceType protocol) @@ -52,17 +49,10 @@ public class JalviewChimeraBindingModel extends JalviewChimeraBinding : (AlignmentPanel) alignment; if (ap.av.isShowSequenceFeatures()) { - if (fr == null) - { - fr = (jalview.gui.FeatureRenderer) ap.cloneFeatureRenderer(); - } - else - { - ap.updateFeatureRenderer(fr); - } + return ap.getSeqPanel().seqCanvas.fr; } - return fr; + return null; } @Override diff --git a/src/jalview/gui/OverviewPanel.java b/src/jalview/gui/OverviewPanel.java index 1c48690..7fdb610 100755 --- a/src/jalview/gui/OverviewPanel.java +++ b/src/jalview/gui/OverviewPanel.java @@ -21,6 +21,7 @@ package jalview.gui; import jalview.renderer.AnnotationRenderer; +import jalview.renderer.seqfeatures.FeatureColourFinder; import java.awt.Color; import java.awt.Dimension; @@ -289,7 +290,7 @@ public class OverviewPanel extends JPanel implements Runnable float sampleRow = (float) alheight / (float) sequencesHeight; int lastcol = -1, lastrow = -1; - int color = Color.white.getRGB(); + Color color = Color.white; int row, col; jalview.datamodel.SequenceI seq; final boolean hasHiddenRows = av.hasHiddenRows(), hasHiddenCols = av @@ -298,6 +299,9 @@ public class OverviewPanel extends JPanel implements Runnable // get hidden row and hidden column map once at beginning. // clone featureRenderer settings to avoid race conditions... if state is // updated just need to refresh again + + FeatureColourFinder finder = new FeatureColourFinder(fr); + for (row = 0; row < sequencesHeight; row++) { if (resizeAgain) @@ -358,7 +362,7 @@ public class OverviewPanel extends JPanel implements Runnable if ((int) (col * sampleCol) == lastcol && (int) (row * sampleRow) == lastrow) { - miniMe.setRGB(col, row, color); + miniMe.setRGB(col, row, color.getRGB()); continue; } @@ -366,26 +370,26 @@ public class OverviewPanel extends JPanel implements Runnable if (seq.getLength() > lastcol) { - color = sr.getResidueBoxColour(seq, lastcol).getRGB(); + color = sr.getResidueBoxColour(seq, lastcol); if (av.isShowSequenceFeatures()) { - color = fr.findFeatureColour(color, seq, lastcol); + color = finder.findFeatureColour(color, seq, lastcol); } } else { - color = -1; // White + color = Color.WHITE; } if (hiddenRow || (hasHiddenCols && !av.getColumnSelection().isVisible( lastcol))) { - color = new Color(color).darker().darker().getRGB(); + color = color.darker().darker(); } - miniMe.setRGB(col, row, color); + miniMe.setRGB(col, row, color.getRGB()); } } diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index d015292..97889af 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -733,7 +733,7 @@ public class SeqCanvas extends JComponent if (av.isShowSequenceFeatures()) { fr.drawSequence(g, nextSeq, startRes, endRes, offset - + ((i - startSeq) * charHeight)); + + ((i - startSeq) * charHeight), false); } // / Highlight search Results once all sequences have been drawn diff --git a/src/jalview/gui/SequenceRenderer.java b/src/jalview/gui/SequenceRenderer.java index 95c3261..764ef3f 100755 --- a/src/jalview/gui/SequenceRenderer.java +++ b/src/jalview/gui/SequenceRenderer.java @@ -20,10 +20,10 @@ */ package jalview.gui; -import jalview.api.FeatureRenderer; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.renderer.ResidueShaderI; +import jalview.renderer.seqfeatures.FeatureColourFinder; import jalview.util.Comparison; import java.awt.Color; @@ -111,20 +111,20 @@ public class SequenceRenderer implements jalview.api.SequenceRenderer * * @param seq * @param position - * @param fr + * @param finder * @return */ @Override public Color getResidueColour(final SequenceI seq, int position, - FeatureRenderer fr) + FeatureColourFinder finder) { // TODO replace 8 or so code duplications with calls to this method // (refactored as needed) Color col = getResidueBoxColour(seq, position); - if (fr != null) + if (finder != null) { - col = fr.findFeatureColour(col, seq, position); + col = finder.findFeatureColour(col, seq, position); } return col; } diff --git a/src/jalview/io/JSONFile.java b/src/jalview/io/JSONFile.java index 27ebe5a..053a65e 100644 --- a/src/jalview/io/JSONFile.java +++ b/src/jalview/io/JSONFile.java @@ -46,6 +46,7 @@ import jalview.json.binding.biojson.v1.ColourSchemeMapper; import jalview.json.binding.biojson.v1.SequenceFeaturesPojo; import jalview.json.binding.biojson.v1.SequenceGrpPojo; import jalview.json.binding.biojson.v1.SequencePojo; +import jalview.renderer.seqfeatures.FeatureColourFinder; import jalview.schemes.JalviewColourScheme; import jalview.schemes.ResidueColourScheme; import jalview.util.ColorUtils; @@ -328,6 +329,8 @@ public class JSONFile extends AlignFile implements ComplexAlignFile return sequenceFeaturesPojo; } + FeatureColourFinder finder = new FeatureColourFinder(fr); + for (SequenceI seq : sqs) { SequenceI dataSetSequence = seq.getDatasetSequence(); @@ -350,7 +353,7 @@ public class JSONFile extends AlignFile implements ComplexAlignFile String.valueOf(seq.hashCode())); String featureColour = (fr == null) ? null : jalview.util.Format - .getHexString(fr.findFeatureColour(Color.white, seq, + .getHexString(finder.findFeatureColour(Color.white, seq, seq.findIndex(sf.getBegin()))); jsonFeature.setXstart(seq.findIndex(sf.getBegin()) - 1); jsonFeature.setXend(seq.findIndex(sf.getEnd())); diff --git a/src/jalview/javascript/MouseOverStructureListener.java b/src/jalview/javascript/MouseOverStructureListener.java index 6d366d0..7580222 100644 --- a/src/jalview/javascript/MouseOverStructureListener.java +++ b/src/jalview/javascript/MouseOverStructureListener.java @@ -221,8 +221,8 @@ public class MouseOverStructureListener extends JSFunctionExec implements ArrayList ccomands = new ArrayList(); ArrayList pdbfn = new ArrayList(); StructureMappingcommandSet[] colcommands = JmolCommands - .getColourBySequenceCommand(ssm, modelSet, sequence, sr, fr, - ((AlignmentViewPanel) source).getAlignViewport()); + .getColourBySequenceCommand(ssm, modelSet, sequence, sr, + (AlignmentViewPanel) source); if (colcommands == null) { return; diff --git a/src/jalview/renderer/seqfeatures/FeatureColourFinder.java b/src/jalview/renderer/seqfeatures/FeatureColourFinder.java new file mode 100644 index 0000000..5055ed5 --- /dev/null +++ b/src/jalview/renderer/seqfeatures/FeatureColourFinder.java @@ -0,0 +1,79 @@ +package jalview.renderer.seqfeatures; + +import jalview.api.FeaturesDisplayedI; +import jalview.datamodel.SequenceI; +import jalview.viewmodel.seqfeatures.FeatureRendererModel; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; + +/** + * A helper class to find feature colour using an associated FeatureRenderer + * + * @author gmcarstairs + * + */ +public class FeatureColourFinder +{ + /* + * the class we delegate feature finding to + */ + private jalview.api.FeatureRenderer featureRenderer; + + /* + * a 1-pixel image on which features can be drawn, for the case where + * transparency allows 'see-through' of multiple feature colours + */ + private BufferedImage offscreenImage; + + /** + * Constructor + * + * @param fr + */ + public FeatureColourFinder(jalview.api.FeatureRenderer fr) + { + featureRenderer = fr; + offscreenImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + } + + /** + * Answers the feature colour to show for the given sequence and column + * position. This delegates to the FeatureRenderer to find the colour, which + * will depend on feature location, visibility, ordering, and whether or not + * transparency is applied. For feature rendering with transparency, this + * class provides a dummy 'offscreen' graphics context where multiple feature + * colours can be overlaid and the combined colour read back. + * + * @param defaultColour + * @param seq + * @param column + * @return + */ + public Color findFeatureColour(Color defaultColour, SequenceI seq, + int column) + { + if (!((FeatureRendererModel) featureRenderer).hasRenderOrder()) + { + return defaultColour; + } + + FeaturesDisplayedI displayed = featureRenderer.getFeaturesDisplayed(); + if (displayed == null || displayed.getVisibleFeatureCount() == 0) + { + return defaultColour; // nothing to see here folks + } + + Graphics g = featureRenderer.getTransparency() == 1f ? null + : offscreenImage.getGraphics(); + + Color c = featureRenderer.findFeatureColour(defaultColour, seq, column, + g); + if (c != null && g != null) + { + c = new Color(offscreenImage.getRGB(0, 0)); + } + return c == null ? defaultColour : c; + } +} diff --git a/src/jalview/renderer/seqfeatures/FeatureRenderer.java b/src/jalview/renderer/seqfeatures/FeatureRenderer.java index 9e0089f..de3b201 100644 --- a/src/jalview/renderer/seqfeatures/FeatureRenderer.java +++ b/src/jalview/renderer/seqfeatures/FeatureRenderer.java @@ -23,6 +23,7 @@ package jalview.renderer.seqfeatures; import jalview.api.AlignViewportI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; +import jalview.util.Comparison; import jalview.viewmodel.seqfeatures.FeatureRendererModel; import java.awt.AlphaComposite; @@ -34,24 +35,16 @@ import java.awt.image.BufferedImage; public class FeatureRenderer extends FeatureRendererModel { - - FontMetrics fm; - - int charOffset; - - boolean offscreenRender = false; + private static final AlphaComposite NO_TRANSPARENCY = AlphaComposite + .getInstance(AlphaComposite.SRC_OVER, 1.0f); protected SequenceI lastSeq; - char s; - - int i; - - int av_charHeight, av_charWidth; + BufferedImage offscreenImage; - boolean av_validCharWidth, av_isShowSeqFeatureHeight; + private volatile SequenceFeature[] lastSequenceFeatures; - private Integer currentColour; + int sfSize; /** * Constructor given a viewport @@ -63,141 +56,174 @@ public class FeatureRenderer extends FeatureRendererModel this.av = viewport; } - protected void updateAvConfig() + /** + * Renders the sequence using the given feature colour between the given start + * and end columns. Returns true if at least one column is drawn, else false + * (the feature range does not overlap the start and end positions). + * + * @param g + * @param seq + * @param featureStart + * @param featureEnd + * @param featureColour + * @param start + * @param end + * @param y1 + * @param colourOnly + * @return + */ + boolean renderFeature(Graphics g, SequenceI seq, int featureStart, + int featureEnd, Color featureColour, int start, int end, int y1, + boolean colourOnly) { - av_charHeight = av.getCharHeight(); - av_charWidth = av.getCharWidth(); - av_validCharWidth = av.isValidCharWidth(); - av_isShowSeqFeatureHeight = av.isShowSequenceFeaturesHeight(); - } + int charHeight = av.getCharHeight(); + int charWidth = av.getCharWidth(); + boolean validCharWidth = av.isValidCharWidth(); - void renderFeature(Graphics g, SequenceI seq, int fstart, int fend, - Color featureColour, int start, int end, int y1) - { - updateAvConfig(); - if (((fstart <= end) && (fend >= start))) + if (featureStart > end || featureEnd < start) { - if (fstart < start) - { // fix for if the feature we have starts before the sequence start, - fstart = start; // but the feature end is still valid!! - } - - if (fend >= end) - { - fend = end; - } - int pady = (y1 + av_charHeight) - av_charHeight / 5; - for (i = fstart; i <= fend; i++) - { - s = seq.getCharAt(i); + return false; + } - if (jalview.util.Comparison.isGap(s)) - { - continue; - } + if (featureStart < start) + { + featureStart = start; + } + if (featureEnd >= end) + { + featureEnd = end; + } + int pady = (y1 + charHeight) - charHeight / 5; - g.setColor(featureColour); + FontMetrics fm = g.getFontMetrics(); + for (int i = featureStart; i <= featureEnd; i++) + { + char s = seq.getCharAt(i); - g.fillRect((i - start) * av_charWidth, y1, av_charWidth, - av_charHeight); + if (Comparison.isGap(s)) + { + continue; + } - if (offscreenRender || !av_validCharWidth) - { - continue; - } + g.setColor(featureColour); - g.setColor(Color.white); - charOffset = (av_charWidth - fm.charWidth(s)) / 2; - g.drawString(String.valueOf(s), charOffset - + (av_charWidth * (i - start)), pady); + g.fillRect((i - start) * charWidth, y1, charWidth, + charHeight); + if (colourOnly || !validCharWidth) + { + continue; } + + g.setColor(Color.white); + int charOffset = (charWidth - fm.charWidth(s)) / 2; + g.drawString(String.valueOf(s), charOffset + + (charWidth * (i - start)), pady); } + return true; } - void renderScoreFeature(Graphics g, SequenceI seq, int fstart, int fend, - Color featureColour, int start, int end, int y1, byte[] bs) + /** + * Renders the sequence using the given SCORE feature colour between the given + * start and end columns. Returns true if at least one column is drawn, else + * false (the feature range does not overlap the start and end positions). + * + * @param g + * @param seq + * @param fstart + * @param fend + * @param featureColour + * @param start + * @param end + * @param y1 + * @param bs + * @param colourOnly + * @return + */ + boolean renderScoreFeature(Graphics g, SequenceI seq, int fstart, + int fend, Color featureColour, int start, int end, int y1, + byte[] bs, boolean colourOnly) { - updateAvConfig(); - if (((fstart <= end) && (fend >= start))) + if (fstart > end || fend < start) { - if (fstart < start) - { // fix for if the feature we have starts before the sequence start, - fstart = start; // but the feature end is still valid!! - } + return false; + } - if (fend >= end) + if (fstart < start) + { // fix for if the feature we have starts before the sequence start, + fstart = start; // but the feature end is still valid!! + } + + if (fend >= end) + { + fend = end; + } + int charHeight = av.getCharHeight(); + int pady = (y1 + charHeight) - charHeight / 5; + int ystrt = 0, yend = charHeight; + if (bs[0] != 0) + { + // signed - zero is always middle of residue line. + if (bs[1] < 128) { - fend = end; - } - int pady = (y1 + av_charHeight) - av_charHeight / 5; - int ystrt = 0, yend = av_charHeight; - if (bs[0] != 0) - { - // signed - zero is always middle of residue line. - 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 = charHeight * (128 - bs[1]) / 512; + ystrt = charHeight - yend / 2; } else { - yend = av_charHeight * bs[1] / 255; - ystrt = av_charHeight - yend; - + ystrt = charHeight / 2; + yend = charHeight * (bs[1] - 128) / 512; } - for (i = fstart; i <= fend; i++) - { - s = seq.getCharAt(i); + } + else + { + yend = charHeight * bs[1] / 255; + ystrt = charHeight - yend; - if (jalview.util.Comparison.isGap(s)) - { - continue; - } + } - g.setColor(featureColour); - int x = (i - start) * av_charWidth; - g.drawRect(x, y1, av_charWidth, av_charHeight); - g.fillRect(x, y1 + ystrt, av_charWidth, yend); + FontMetrics fm = g.getFontMetrics(); + int charWidth = av.getCharWidth(); - if (offscreenRender || !av_validCharWidth) - { - continue; - } + for (int i = fstart; i <= fend; i++) + { + char s = seq.getCharAt(i); - g.setColor(Color.black); - charOffset = (av_charWidth - fm.charWidth(s)) / 2; - g.drawString(String.valueOf(s), charOffset - + (av_charWidth * (i - start)), pady); + if (Comparison.isGap(s)) + { + continue; } - } - } - BufferedImage offscreenImage; + g.setColor(featureColour); + int x = (i - start) * charWidth; + g.drawRect(x, y1, charWidth, charHeight); + g.fillRect(x, y1 + ystrt, charWidth, yend); - @Override - public Color findFeatureColour(Color initialCol, SequenceI seq, int res) - { - return new Color(findFeatureColour(initialCol.getRGB(), seq, res)); + if (colourOnly || !av.isValidCharWidth()) + { + continue; + } + + g.setColor(Color.black); + int charOffset = (charWidth - fm.charWidth(s)) / 2; + g.drawString(String.valueOf(s), charOffset + + (charWidth * (i - start)), pady); + } + return true; } /** * This is used by Structure Viewers and the Overview Window to get the - * feature colour of the rendered sequence, returned as an RGB value + * feature colour of the rendered sequence * * @param defaultColour * @param seq * @param column * @return */ - public synchronized int findFeatureColour(int defaultColour, - final SequenceI seq, int column) + @Override + public Color findFeatureColour(Color defaultColour, SequenceI seq, + int column, Graphics g) { if (!av.isShowSequenceFeatures()) { @@ -231,60 +257,29 @@ public class FeatureRenderer extends FeatureRendererModel return defaultColour; } - if (jalview.util.Comparison.isGap(lastSeq.getCharAt(column))) + if (Comparison.isGap(lastSeq.getCharAt(column))) { - return Color.white.getRGB(); + return Color.white; } - // Only bother making an offscreen image if transparency is applied - if (transparency != 1.0f && offscreenImage == null) + Color renderedColour = null; + if (transparency == 1.0f) { - offscreenImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); - } - - currentColour = null; - // TODO: non-threadsafe - each rendering thread needs its own instance of - // the feature renderer - or this should be synchronized. - offscreenRender = true; - - if (offscreenImage != null) - { - offscreenImage.setRGB(0, 0, defaultColour); - drawSequence(offscreenImage.getGraphics(), lastSeq, column, column, 0); - - return offscreenImage.getRGB(0, 0); + renderedColour = findFeatureColour(seq, seq.findPosition(column)); } else { - drawSequence(null, lastSeq, lastSeq.findPosition(column), -1, -1); - - if (currentColour == null) - { - return defaultColour; - } - else - { - return currentColour.intValue(); - } + renderedColour = drawSequence(g, lastSeq, column, column, 0, true); } - + return renderedColour == null ? defaultColour : renderedColour; } - private volatile SequenceFeature[] lastSequenceFeatures; - - int sfSize; - - int sfindex; - - int spos; - - int epos; - /** - * Draws the sequence on the graphics context, or just determines the colour - * that would be drawn (if flag offscreenrender is true). + * Draws the sequence features on the graphics context, or just determines the + * colour that would be drawn (if flag offscreenrender is true). * * @param g + * the graphics context to draw on (may be null if colourOnly==true) * @param seq * @param start * start column (or sequence position in offscreenrender mode) @@ -292,19 +287,19 @@ public class FeatureRenderer extends FeatureRendererModel * end column (not used in offscreenrender mode) * @param y1 * vertical offset at which to draw on the graphics + * @param colourOnly + * if true, only do enough to determine the colour for the position, + * do not draw the character + * @return */ - public synchronized void drawSequence(Graphics g, final SequenceI seq, - int start, int end, int y1) + public synchronized Color drawSequence(final Graphics g, + final SequenceI seq, int start, int end, int y1, + boolean colourOnly) { SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures(); if (sequenceFeatures == null || sequenceFeatures.length == 0) { - return; - } - - if (g != null) - { - fm = g.getFontMetrics(); + return null; } updateFeatures(); @@ -316,20 +311,25 @@ public class FeatureRenderer extends FeatureRendererModel lastSequenceFeatures = sequenceFeatures; } - if (transparency != 1 && g != null) + if (transparency != 1f && g != null) { Graphics2D g2 = (Graphics2D) g; g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, transparency)); } - if (!offscreenRender) - { - spos = lastSeq.findPosition(start); - epos = lastSeq.findPosition(end); - } + int startPos = lastSeq.findPosition(start); + int endPos = lastSeq.findPosition(end); sfSize = lastSequenceFeatures.length; + Color drawnColour = null; + + /* + * iterate over features in ordering of their rendering; + * if drawing a range of columns, use render order to ensure last is on top + * if drawing a single column (as in findFeatureColour), with no + * transparency, work backwards to find the topmost rendered feature colour + */ for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++) { String type = renderOrder[renderIndex]; @@ -340,7 +340,7 @@ public class FeatureRenderer extends FeatureRendererModel // loop through all features in sequence to find // current feature to render - for (sfindex = 0; sfindex < sfSize; sfindex++) + for (int sfindex = 0; sfindex < sfSize; sfindex++) { final SequenceFeature sequenceFeature = lastSequenceFeatures[sfindex]; if (!sequenceFeature.type.equals(type)) @@ -358,9 +358,8 @@ public class FeatureRenderer extends FeatureRendererModel * unless doing offscreenRender (to the Overview window or a * structure viewer) which is not limited */ - if (!offscreenRender - && (sequenceFeature.getBegin() > epos || sequenceFeature - .getEnd() < spos)) + if (sequenceFeature.getBegin() > endPos + || sequenceFeature.getEnd() < startPos) { continue; } @@ -368,58 +367,46 @@ public class FeatureRenderer extends FeatureRendererModel Color featureColour = getColour(sequenceFeature); boolean isContactFeature = sequenceFeature.isContactFeature(); - if (offscreenRender && offscreenImage == null) + if (isContactFeature) { - /* - * offscreen mode with no image (image is only needed if transparency - * is applied to feature colours) - just check feature is rendered at - * the requested position (start == sequence position in this mode) - */ - boolean featureIsAtPosition = sequenceFeature.begin <= start - && sequenceFeature.end >= start; - if (isContactFeature) - { - featureIsAtPosition = sequenceFeature.begin == start - || sequenceFeature.end == start; - } - if (featureIsAtPosition) - { - // 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(featureColour.getRGB()); - // used to be retreived from av.featuresDisplayed - // currentColour = av.featuresDisplayed - // .get(sequenceFeatures[sfindex].type); - - } - } - else if (isContactFeature) - { - renderFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1, + boolean drawn = renderFeature(g, seq, + seq.findIndex(sequenceFeature.begin) - 1, seq.findIndex(sequenceFeature.begin) - 1, featureColour, - start, end, y1); - renderFeature(g, seq, seq.findIndex(sequenceFeature.end) - 1, + start, end, y1, colourOnly); + drawn |= renderFeature(g, seq, + seq.findIndex(sequenceFeature.end) - 1, seq.findIndex(sequenceFeature.end) - 1, featureColour, - start, end, y1); - + start, end, y1, colourOnly); + if (drawn) + { + drawnColour = featureColour; + } } else if (showFeature(sequenceFeature)) { - if (av_isShowSeqFeatureHeight + if (av.isShowSequenceFeaturesHeight() && !Float.isNaN(sequenceFeature.score)) { - renderScoreFeature(g, seq, + boolean drawn = renderScoreFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1, - seq.findIndex(sequenceFeature.end) - 1, - featureColour, start, end, y1, - normaliseScore(sequenceFeature)); + seq.findIndex(sequenceFeature.end) - 1, featureColour, + start, end, y1, normaliseScore(sequenceFeature), + colourOnly); + if (drawn) + { + drawnColour = featureColour; + } } else { - renderFeature(g, seq, seq.findIndex(sequenceFeature.begin) - 1, - seq.findIndex(sequenceFeature.end) - 1, - featureColour, start, end, y1); + boolean drawn = renderFeature(g, seq, + seq.findIndex(sequenceFeature.begin) - 1, + seq.findIndex(sequenceFeature.end) - 1, featureColour, + start, end, y1, colourOnly); + if (drawn) + { + drawnColour = featureColour; + } } } } @@ -427,10 +414,19 @@ public class FeatureRenderer extends FeatureRendererModel if (transparency != 1.0f && g != null) { + /* + * get colour as rendered including transparency + * and reset transparency + */ + if (offscreenImage != null && drawnColour != null) + { + drawnColour = new Color(offscreenImage.getRGB(0, 0)); + } Graphics2D g2 = (Graphics2D) g; - g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, - 1.0f)); + g2.setComposite(NO_TRANSPARENCY); } + + return drawnColour; } /** @@ -462,4 +458,69 @@ public class FeatureRenderer extends FeatureRendererModel lastSeq = null; findAllFeatures(); } + + /** + * Returns the sequence feature colour rendered at the given sequence + * position, or null if none found. The feature of highest render order (i.e. + * on top) is found, subject to both feature type and feature group being + * visible, and its colour returned. + * + * @param seq + * @param pos + * @return + */ + Color findFeatureColour(SequenceI seq, int pos) + { + SequenceFeature[] sequenceFeatures = seq.getSequenceFeatures(); + if (sequenceFeatures == null || sequenceFeatures.length == 0) + { + return null; + } + + // updateFeatures(); + + /* + * inspect features in reverse renderOrder (the last in the array is + * displayed on top) until we find one that is rendered at the position + */ + for (int renderIndex = renderOrder.length - 1; renderIndex >= 0; renderIndex--) + { + String type = renderOrder[renderIndex]; + if (!showFeatureOfType(type)) + { + continue; + } + + for (int sfindex = 0; sfindex < sequenceFeatures.length; sfindex++) + { + SequenceFeature sequenceFeature = sequenceFeatures[sfindex]; + if (!sequenceFeature.type.equals(type)) + { + continue; + } + + if (featureGroupNotShown(sequenceFeature)) + { + continue; + } + + boolean featureIsAtPosition = sequenceFeature.begin <= pos + && sequenceFeature.end >= pos; + if (sequenceFeature.isContactFeature()) + { + featureIsAtPosition = sequenceFeature.begin == pos + || sequenceFeature.end == pos; + } + if (featureIsAtPosition) + { + return getColour(sequenceFeature); + } + } + } + + /* + * no displayed feature found at position + */ + return null; + } } diff --git a/src/jalview/structures/models/AAStructureBindingModel.java b/src/jalview/structures/models/AAStructureBindingModel.java index 7d57886..82ba2d7 100644 --- a/src/jalview/structures/models/AAStructureBindingModel.java +++ b/src/jalview/structures/models/AAStructureBindingModel.java @@ -20,9 +20,7 @@ */ package jalview.structures.models; -import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; -import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; import jalview.api.StructureSelectionManagerProvider; import jalview.api.structures.JalviewStructureDisplayI; @@ -724,18 +722,7 @@ public abstract class AAStructureBindingModel extends public abstract void setBackgroundColour(Color col); protected abstract StructureMappingcommandSet[] getColourBySequenceCommands( - String[] files, SequenceRenderer sr, FeatureRenderer fr, - AlignViewportI alignViewportI); - - /** - * returns the current featureRenderer that should be used to colour the - * structures - * - * @param alignment - * - * @return - */ - public abstract FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment); + String[] files, SequenceRenderer sr, AlignmentViewPanel avp); /** * returns the current sequenceRenderer that should be used to colour the @@ -773,16 +760,8 @@ public abstract class AAStructureBindingModel extends SequenceRenderer sr = getSequenceRenderer(alignmentv); - FeatureRenderer fr = null; - boolean showFeatures = alignmentv.getAlignViewport() - .isShowSequenceFeatures(); - if (showFeatures) - { - fr = getFeatureRenderer(alignmentv); - } - StructureMappingcommandSet[] colourBySequenceCommands = getColourBySequenceCommands( - files, sr, fr, alignmentv.getAlignViewport()); + files, sr, alignmentv); colourBySequence(colourBySequenceCommands); } @@ -790,4 +769,7 @@ public abstract class AAStructureBindingModel extends { return fileLoadingError != null && fileLoadingError.length() > 0; } + + protected abstract jalview.api.FeatureRenderer getFeatureRenderer( + AlignmentViewPanel alignment); } diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index 8468329..085743f 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -822,7 +822,7 @@ public abstract class FeatureRendererModel implements * @return list of groups */ @Override - public List getGroups(boolean visible) + public List getGroups(boolean visible) { if (featureGroups != null) { diff --git a/test/jalview/ext/jmol/JmolCommandsTest.java b/test/jalview/ext/jmol/JmolCommandsTest.java index 89da196..2c23311 100644 --- a/test/jalview/ext/jmol/JmolCommandsTest.java +++ b/test/jalview/ext/jmol/JmolCommandsTest.java @@ -58,7 +58,6 @@ public class JmolCommandsTest // need some mappings! StructureMappingcommandSet[] commands = JmolCommands - .getColourBySequenceCommand(ssm, files, seqs, sr, null, - af.getViewport()); + .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel); } } diff --git a/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java b/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java index d351171..49a951e 100644 --- a/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java +++ b/test/jalview/ext/rbvi/chimera/ChimeraCommandsTest.java @@ -202,8 +202,7 @@ public class ChimeraCommandsTest ssm.addStructureMapping(sm2); StructureMappingcommandSet[] commands = ChimeraCommands - .getColourBySequenceCommand(ssm, files, seqs, sr, null, - af.getViewport()); + .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel); assertEquals(1, commands.length); assertEquals(1, commands[0].commands.length); String theCommand = commands[0].commands[0]; diff --git a/test/jalview/structures/models/AAStructureBindingModelTest.java b/test/jalview/structures/models/AAStructureBindingModelTest.java index c92daea..30f9e68 100644 --- a/test/jalview/structures/models/AAStructureBindingModelTest.java +++ b/test/jalview/structures/models/AAStructureBindingModelTest.java @@ -24,7 +24,6 @@ import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertTrue; -import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; @@ -184,14 +183,7 @@ public class AAStructureBindingModelTest @Override protected StructureMappingcommandSet[] getColourBySequenceCommands( - String[] files, SequenceRenderer sr, FeatureRenderer fr, - AlignViewportI viewport) - { - return null; - } - - @Override - public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment) + String[] files, SequenceRenderer sr, AlignmentViewPanel avp) { return null; } @@ -218,6 +210,13 @@ public class AAStructureBindingModelTest public void colourByCharge() { } + + @Override + protected FeatureRenderer getFeatureRenderer( + AlignmentViewPanel alignment) + { + return null; + } }; } -- 1.7.10.2