Merge branch 'Release_2_8_1_Branch' into JAL-1372_referenceseq
[jalview.git] / src / jalview / appletgui / SequenceRenderer.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
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     boolean srep = av.isDisplayReferenceSeq();
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           s = getDisplayChar(srep, i, s,
231                   '.');
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(srep, i, s,
256                   '.');
257
258         }
259       }
260
261       if (av.upperCasebold)
262       {
263         fm = graphics.getFontMetrics();
264         if ('A' <= s && s <= 'Z')
265         {
266           if (!bold)
267           {
268
269             graphics.setFont(boldFont);
270           }
271           bold = true;
272         }
273         else if (bold)
274         {
275           graphics.setFont(av.font);
276           bold = false;
277         }
278
279       }
280
281       charOffset = (av.charWidth - fm.charWidth(s)) / 2;
282       graphics.drawString(String.valueOf(s), charOffset + av.charWidth
283               * (i - start), y1);
284     }
285
286   }
287
288   private char getDisplayChar(final boolean usesrep, int position,
289           char s, char c)
290   {
291     // TODO - use currentSequenceGroup rather than alignemnt 
292     // currentSequenceGroup.getConsensus()
293     char conschar = (usesrep) ? av.getAlignment().getSeqrep().getCharAt(position) : av.getAlignmentConsensusAnnotation().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 }