JAL-1065 - Visualize T-Coffee quality scores for an alignment
[jalview.git] / src / jalview / appletgui / SequenceRenderer.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3  * Copyright (C) 2011 J Procter, AM Waterhouse, 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.alignment.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.globalColourScheme, 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.getIndex());
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.alignment.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.consensus, i, s, '.');
232         }
233       }
234       else
235       {
236         if (!av.getShowText())
237         {
238           continue;
239         }
240
241         if (av.getColourText())
242         {
243           getBoxColour(av.getGlobalColourScheme(), seq, i);
244           if (av.getShowBoxes())
245           {
246             graphics.setColor(resBoxColour.darker());
247           }
248           else
249           {
250             graphics.setColor(resBoxColour);
251           }
252         }
253         if (av.getShowunconserved())
254         {
255           s = getDisplayChar(av.consensus, i, s, '.');
256
257         }
258       }
259
260       if (av.upperCasebold)
261       {
262         fm = graphics.getFontMetrics();
263         if ('A' <= s && s <= 'Z')
264         {
265           if (!bold)
266           {
267
268             graphics.setFont(boldFont);
269           }
270           bold = true;
271         }
272         else if (bold)
273         {
274           graphics.setFont(av.font);
275           bold = false;
276         }
277
278       }
279
280       charOffset = (av.charWidth - fm.charWidth(s)) / 2;
281       graphics.drawString(String.valueOf(s), charOffset + av.charWidth
282               * (i - start), y1);
283     }
284
285   }
286
287   private char getDisplayChar(AlignmentAnnotation consensus, int position,
288           char s, char c)
289   {
290     char conschar = consensus.annotations[position].displayCharacter
291             .charAt(0);
292     if (conschar != '-' && s == conschar)
293     {
294       s = c;
295     }
296     return s;
297   }
298
299   boolean inCurrentSequenceGroup(int res)
300   {
301     if (allGroups == null)
302     {
303       return false;
304     }
305
306     for (int i = 0; i < allGroups.length; i++)
307     {
308       if (allGroups[i].getStartRes() <= res
309               && allGroups[i].getEndRes() >= res)
310       {
311         currentSequenceGroup = allGroups[i];
312         return true;
313       }
314     }
315
316     return false;
317   }
318
319   public void drawHighlightedText(SequenceI seq, int start, int end,
320           int x1, int y1)
321   {
322     int pady = av.charHeight / 5;
323     int charOffset = 0;
324     graphics.setColor(Color.black);
325     graphics.fillRect(x1, y1, av.charWidth * (end - start + 1),
326             av.charHeight);
327     graphics.setColor(Color.white);
328
329     char s = '~';
330     // Need to find the sequence position here.
331     if (av.validCharWidth)
332     {
333       for (int i = start; i <= end; i++)
334       {
335         if (i < seq.getLength())
336         {
337           s = seq.getCharAt(i);
338         }
339
340         charOffset = (av.charWidth - fm.charWidth(s)) / 2;
341         graphics.drawString(String.valueOf(s), charOffset + x1
342                 + av.charWidth * (i - start), y1 + av.charHeight - pady);
343       }
344     }
345   }
346
347   public void drawCursor(SequenceI seq, int res, int x1, int y1)
348   {
349     int pady = av.charHeight / 5;
350     int charOffset = 0;
351     graphics.setColor(Color.black);
352     graphics.fillRect(x1, y1, av.charWidth, av.charHeight);
353     graphics.setColor(Color.white);
354
355     graphics.setColor(Color.white);
356
357     char s = seq.getCharAt(res);
358     if (av.validCharWidth)
359     {
360
361       charOffset = (av.charWidth - fm.charWidth(s)) / 2;
362       graphics.drawString(String.valueOf(s), charOffset + x1,
363               (y1 + av.charHeight) - pady);
364     }
365   }
366
367 }