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