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