d4446309b48d8224ea21bb64abc72401fe57f0cd
[jalview.git] / src / jalview / appletgui / SequenceRenderer.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.appletgui;
19
20 import jalview.datamodel.AlignmentAnnotation;
21 import jalview.datamodel.SequenceGroup;
22 import jalview.datamodel.SequenceI;
23 import jalview.schemes.ColourSchemeI;
24
25 import java.awt.Color;
26 import java.awt.Font;
27 import java.awt.FontMetrics;
28 import java.awt.Graphics;
29
30 public class SequenceRenderer implements jalview.api.SequenceRenderer
31 {
32   AlignViewport av;
33
34   FontMetrics fm;
35
36   boolean renderGaps = true;
37
38   SequenceGroup currentSequenceGroup = null;
39
40   SequenceGroup[] allGroups = null;
41
42   Color resBoxColour;
43
44   Graphics graphics;
45
46   boolean forOverview = false;
47
48   public SequenceRenderer(AlignViewport av)
49   {
50     this.av = av;
51   }
52
53   /**
54    * DOCUMENT ME!
55    * 
56    * @param b
57    *          DOCUMENT ME!
58    */
59   public void prepare(Graphics g, boolean renderGaps)
60   {
61     graphics = g;
62     fm = g.getFontMetrics();
63
64     this.renderGaps = renderGaps;
65   }
66
67   public Color getResidueBoxColour(SequenceI seq, int i)
68   {
69     allGroups = av.getAlignment().findAllGroups(seq);
70
71     if (inCurrentSequenceGroup(i))
72     {
73       if (currentSequenceGroup.getDisplayBoxes())
74       {
75         getBoxColour(currentSequenceGroup.cs, seq, i);
76       }
77     }
78     else if (av.getShowBoxes())
79     {
80       getBoxColour(av.getGlobalColourScheme(), seq, i);
81     }
82
83     return resBoxColour;
84   }
85
86   void getBoxColour(ColourSchemeI cs, SequenceI seq, int i)
87   {
88     if (cs != null)
89     {
90       resBoxColour = cs.findColour(seq.getCharAt(i), i, seq);
91     }
92     else if (forOverview
93             && !jalview.util.Comparison.isGap(seq.getCharAt(i)))
94     {
95       resBoxColour = Color.lightGray;
96     }
97     else
98     {
99       resBoxColour = Color.white;
100     }
101
102   }
103
104   public Color findSequenceColour(SequenceI seq, int i)
105   {
106     allGroups = av.getAlignment().findAllGroups(seq);
107     drawBoxes(seq, i, i, 0);
108     return resBoxColour;
109   }
110
111   public void drawSequence(SequenceI seq, SequenceGroup[] sg, int start,
112           int end, int y1)
113   {
114     if (seq == null)
115     {
116       return;
117     }
118
119     allGroups = sg;
120
121     drawBoxes(seq, start, end, y1);
122
123     if (av.validCharWidth)
124     {
125       drawText(seq, start, end, y1);
126     }
127   }
128
129   public void drawBoxes(SequenceI seq, int start, int end, int y1)
130   {
131     int i = start;
132     int length = seq.getLength();
133
134     int curStart = -1;
135     int curWidth = av.charWidth;
136
137     Color tempColour = null;
138     while (i <= end)
139     {
140       resBoxColour = Color.white;
141       if (i < length)
142       {
143         if (inCurrentSequenceGroup(i))
144         {
145           if (currentSequenceGroup.getDisplayBoxes())
146           {
147             getBoxColour(currentSequenceGroup.cs, seq, i);
148           }
149         }
150         else if (av.getShowBoxes())
151         {
152           getBoxColour(av.getGlobalColourScheme(), seq, i);
153         }
154       }
155
156       if (resBoxColour != tempColour)
157       {
158         if (tempColour != null)
159         {
160           graphics.fillRect(av.charWidth * (curStart - start), y1,
161                   curWidth, av.charHeight);
162         }
163         graphics.setColor(resBoxColour);
164
165         curStart = i;
166         curWidth = av.charWidth;
167         tempColour = resBoxColour;
168
169       }
170       else
171       {
172         curWidth += av.charWidth;
173       }
174
175       i++;
176     }
177
178     graphics.fillRect(av.charWidth * (curStart - start), y1, curWidth,
179             av.charHeight);
180   }
181
182   public void drawText(SequenceI seq, int start, int end, int y1)
183   {
184     Font boldFont = null;
185     boolean bold = false;
186     if (av.upperCasebold)
187     {
188       boldFont = new Font(av.getFont().getName(), Font.BOLD, av.charHeight);
189
190       graphics.setFont(av.getFont());
191     }
192
193     y1 += av.charHeight - av.charHeight / 5; // height/5 replaces pady
194
195     int charOffset = 0;
196
197     // Need to find the sequence position here.
198     if (end + 1 >= seq.getLength())
199     {
200       end = seq.getLength() - 1;
201     }
202
203     char s = ' ';
204
205     for (int i = start; i <= end; i++)
206     {
207       graphics.setColor(Color.black);
208
209       s = seq.getCharAt(i);
210       if (!renderGaps && jalview.util.Comparison.isGap(s))
211       {
212         continue;
213       }
214
215       if (inCurrentSequenceGroup(i))
216       {
217         if (!currentSequenceGroup.getDisplayText())
218         {
219           continue;
220         }
221
222         if (currentSequenceGroup.getColourText())
223         {
224           getBoxColour(currentSequenceGroup.cs, seq, i);
225           graphics.setColor(resBoxColour.darker());
226         }
227         if (currentSequenceGroup.getShowNonconserved())
228         {
229           // cheat - use this if we have a consensus for each group: s =
230           // getDisplayChar(currentSequenceGroup.getConsensus(), i, s, '.');
231           s = getDisplayChar(av.getAlignmentConsensusAnnotation(), i, s,
232                   '.');
233         }
234       }
235       else
236       {
237         if (!av.getShowText())
238         {
239           continue;
240         }
241
242         if (av.getColourText())
243         {
244           getBoxColour(av.getGlobalColourScheme(), seq, i);
245           if (av.getShowBoxes())
246           {
247             graphics.setColor(resBoxColour.darker());
248           }
249           else
250           {
251             graphics.setColor(resBoxColour);
252           }
253         }
254         if (av.getShowUnconserved())
255         {
256           s = getDisplayChar(av.getAlignmentConsensusAnnotation(), i, s,
257                   '.');
258
259         }
260       }
261
262       if (av.upperCasebold)
263       {
264         fm = graphics.getFontMetrics();
265         if ('A' <= s && s <= 'Z')
266         {
267           if (!bold)
268           {
269
270             graphics.setFont(boldFont);
271           }
272           bold = true;
273         }
274         else if (bold)
275         {
276           graphics.setFont(av.font);
277           bold = false;
278         }
279
280       }
281
282       charOffset = (av.charWidth - fm.charWidth(s)) / 2;
283       graphics.drawString(String.valueOf(s), charOffset + av.charWidth
284               * (i - start), y1);
285     }
286
287   }
288
289   private char getDisplayChar(AlignmentAnnotation consensus, int position,
290           char s, char c)
291   {
292     char conschar = consensus.annotations[position].displayCharacter
293             .charAt(0);
294     if (conschar != '-' && s == conschar)
295     {
296       s = c;
297     }
298     return s;
299   }
300
301   boolean inCurrentSequenceGroup(int res)
302   {
303     if (allGroups == null)
304     {
305       return false;
306     }
307
308     for (int i = 0; i < allGroups.length; i++)
309     {
310       if (allGroups[i].getStartRes() <= res
311               && allGroups[i].getEndRes() >= res)
312       {
313         currentSequenceGroup = allGroups[i];
314         return true;
315       }
316     }
317
318     return false;
319   }
320
321   public void drawHighlightedText(SequenceI seq, int start, int end,
322           int x1, int y1)
323   {
324     int pady = av.charHeight / 5;
325     int charOffset = 0;
326     graphics.setColor(Color.black);
327     graphics.fillRect(x1, y1, av.charWidth * (end - start + 1),
328             av.charHeight);
329     graphics.setColor(Color.white);
330
331     char s = '~';
332     // Need to find the sequence position here.
333     if (av.validCharWidth)
334     {
335       for (int i = start; i <= end; i++)
336       {
337         if (i < seq.getLength())
338         {
339           s = seq.getCharAt(i);
340         }
341
342         charOffset = (av.charWidth - fm.charWidth(s)) / 2;
343         graphics.drawString(String.valueOf(s), charOffset + x1
344                 + av.charWidth * (i - start), y1 + av.charHeight - pady);
345       }
346     }
347   }
348
349   public void drawCursor(SequenceI seq, int res, int x1, int y1)
350   {
351     int pady = av.charHeight / 5;
352     int charOffset = 0;
353     graphics.setColor(Color.black);
354     graphics.fillRect(x1, y1, av.charWidth, av.charHeight);
355     graphics.setColor(Color.white);
356
357     graphics.setColor(Color.white);
358
359     char s = seq.getCharAt(res);
360     if (av.validCharWidth)
361     {
362
363       charOffset = (av.charWidth - fm.charWidth(s)) / 2;
364       graphics.drawString(String.valueOf(s), charOffset + x1,
365               (y1 + av.charHeight) - pady);
366     }
367   }
368
369 }