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