b92d57be63a4c7b754205eb954b864d705ba2a5a
[jalview.git] / src / jalview / renderer / seqfeatures / FeatureColourFinder.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.renderer.seqfeatures;
22
23 import jalview.api.FeatureRenderer;
24 import jalview.api.FeaturesDisplayedI;
25 import jalview.datamodel.SequenceI;
26 import jalview.util.Platform;
27 import jalview.viewmodel.seqfeatures.FeatureRendererModel;
28
29 import java.awt.Color;
30 import java.awt.Graphics;
31 import java.awt.Graphics2D;
32 import java.awt.image.BufferedImage;
33
34 /**
35  * A helper class to find feature colour using an associated FeatureRenderer
36  * 
37  * @author gmcarstairs
38  *
39  */
40 public class FeatureColourFinder
41 {
42   /*
43    * the class we delegate feature finding to
44    */
45   private FeatureRenderer featureRenderer;
46
47   /*
48    * a 1-pixel image on which features can be drawn, for the case where
49    * transparency allows 'see-through' of multiple feature colours
50    */
51   private BufferedImage offscreenImage;
52
53   private Graphics goff;
54
55   /**
56    * Constructor
57    * 
58    * @param fr
59    */
60   public FeatureColourFinder(FeatureRenderer fr)
61   {
62     featureRenderer = fr;
63     offscreenImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
64     goff = offscreenImage.getGraphics();
65   }
66
67   /**
68    * Answers the feature colour to show for the given sequence and column
69    * position. This delegates to the FeatureRenderer to find the colour, which
70    * will depend on feature location, visibility, ordering, colour scheme, and
71    * whether or not transparency is applied. For feature rendering with
72    * transparency, this class provides a dummy 'offscreen' graphics context
73    * where multiple feature colours can be overlaid and the combined colour read
74    * back.
75    * <p>
76    * This method is not thread-safe when transparency is applied, since a shared
77    * BufferedImage would be used by all threads to hold the composite colour at
78    * a position. Each thread should use a separate instance of this class.
79    * 
80    * @param defaultColour
81    * @param seq
82    * @param column
83    *          alignment column position (0..)
84    * @return
85    */
86   public Color findFeatureColour(Color defaultColour, SequenceI seq,
87           int column)
88   {
89     if (noFeaturesDisplayed())
90     {
91       return defaultColour;
92     }
93
94     Graphics g = null;
95
96     /*
97      * if transparency applies, provide a notional 1x1 graphics context 
98      * that has been primed with the default colour
99      */
100     if (featureRenderer.getTransparency() != 1f)
101     {
102       g = goff;
103       if (defaultColour != null)
104       {
105         offscreenImage.setRGB(0, 0, defaultColour.getRGB());
106       }
107     }
108
109     Color c = featureRenderer.findFeatureColour(seq, column + 1, g);
110     if (c == null)
111     {
112       return defaultColour;
113     }
114
115     if (g != null)
116     {
117       c = new Color(offscreenImage.getRGB(0, 0));
118     }
119     return c;
120   }
121
122   /**
123    * Answers true if feature display is turned off, or there are no features
124    * configured to be visible
125    * 
126    * @return
127    */
128   public boolean noFeaturesDisplayed()
129   {
130     if (featureRenderer == null
131             || !featureRenderer.getViewport().isShowSequenceFeatures())
132     {
133       return true;
134     }
135
136     if (!((FeatureRendererModel) featureRenderer).hasRenderOrder())
137     {
138       return true;
139     }
140
141     FeaturesDisplayedI displayed = featureRenderer.getFeaturesDisplayed();
142     if (displayed == null || displayed.getVisibleFeatureCount() == 0)
143     {
144       return true;
145     }
146
147     return false;
148   }
149 }