25bcb6d5f8e7433f78354289affe9812aeac79a1
[jalview.git] / src / jalview / gui / SequenceRenderer.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3  * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.gui;
20
21 import java.awt.*;
22
23 import jalview.datamodel.*;
24 import jalview.schemes.*;
25
26 /**
27  * DOCUMENT ME!
28  *
29  * @author $author$
30  * @version $Revision$
31  */
32 public class SequenceRenderer
33 {
34   AlignViewport av;
35   FontMetrics fm;
36   boolean renderGaps = true;
37   SequenceGroup currentSequenceGroup = null;
38   SequenceGroup[] allGroups = null;
39   Color resBoxColour;
40   Graphics graphics;
41   boolean monospacedFont;
42   boolean forOverview = false;
43
44   /**
45    * Creates a new SequenceRenderer object.
46    *
47    * @param av DOCUMENT ME!
48    */
49   public SequenceRenderer(AlignViewport av)
50   {
51     this.av = av;
52   }
53
54   /**
55    * DOCUMENT ME!
56    *
57    * @param b DOCUMENT ME!
58    */
59   public void prepare(Graphics g, boolean renderGaps)
60   {
61     graphics = g;
62     fm = g.getFontMetrics();
63
64     // If EPS graphics, stringWidth will be a double, not an int
65     double dwidth = fm.getStringBounds("M", g).getWidth();
66
67     monospacedFont =
68         (dwidth == fm.getStringBounds("|", g).getWidth()
69          && (float) av.charWidth == dwidth);
70
71     this.renderGaps = renderGaps;
72   }
73
74   public Color getResidueBoxColour(SequenceI seq, int i)
75   {
76     allGroups = av.alignment.findAllGroups(seq);
77
78     if (inCurrentSequenceGroup(i))
79     {
80       if (currentSequenceGroup.getDisplayBoxes())
81       {
82         getBoxColour(currentSequenceGroup.cs, seq, i);
83       }
84     }
85     else if (av.getShowBoxes())
86     {
87       getBoxColour(av.globalColourScheme, seq, i);
88     }
89
90     return resBoxColour;
91   }
92
93   /**
94    * DOCUMENT ME!
95    *
96    * @param cs DOCUMENT ME!
97    * @param seq DOCUMENT ME!
98    * @param i DOCUMENT ME!
99    */
100   void getBoxColour(ColourSchemeI cs, SequenceI seq, int i)
101   {
102     if (cs != null)
103     {
104       resBoxColour = cs.findColour(seq.getCharAt(i), i);
105     }
106     else if (forOverview && !jalview.util.Comparison.isGap(seq.getCharAt(i)))
107     {
108       resBoxColour = Color.lightGray;
109     }
110     else
111     {
112       resBoxColour = Color.white;
113     }
114   }
115
116   /**
117    * DOCUMENT ME!
118    *
119    * @param g DOCUMENT ME!
120    * @param seq DOCUMENT ME!
121    * @param sg DOCUMENT ME!
122    * @param start DOCUMENT ME!
123    * @param end DOCUMENT ME!
124    * @param x1 DOCUMENT ME!
125    * @param y1 DOCUMENT ME!
126    * @param width DOCUMENT ME!
127    * @param height DOCUMENT ME!
128    */
129   public void drawSequence(SequenceI seq, SequenceGroup[] sg,
130                            int start, int end, int y1)
131   {
132     allGroups = sg;
133
134     drawBoxes(seq, start, end, y1);
135
136     if (av.validCharWidth)
137     {
138       drawText(seq, start, end, y1);
139     }
140   }
141
142   /**
143    * DOCUMENT ME!
144    *
145    * @param seq DOCUMENT ME!
146    * @param start DOCUMENT ME!
147    * @param end DOCUMENT ME!
148    * @param x1 DOCUMENT ME!
149    * @param y1 DOCUMENT ME!
150    * @param width DOCUMENT ME!
151    * @param height DOCUMENT ME!
152    */
153   public synchronized void drawBoxes(SequenceI seq, int start, int end, int y1)
154   {
155     int i = start;
156     int length = seq.getLength();
157
158     int curStart = -1;
159     int curWidth = av.charWidth;
160
161     Color tempColour = null;
162
163     while (i <= end)
164     {
165       resBoxColour = Color.white;
166
167       if (i < length)
168       {
169         if (inCurrentSequenceGroup(i))
170         {
171           if (currentSequenceGroup.getDisplayBoxes())
172           {
173             getBoxColour(currentSequenceGroup.cs, seq, i);
174           }
175         }
176         else if (av.getShowBoxes())
177         {
178           getBoxColour(av.globalColourScheme, seq, i);
179         }
180
181       }
182
183       if (resBoxColour != tempColour)
184       {
185         if (tempColour != null)
186         {
187           graphics.fillRect(av.charWidth * (curStart - start), y1,
188                             curWidth, av.charHeight);
189         }
190
191         graphics.setColor(resBoxColour);
192
193         curStart = i;
194         curWidth = av.charWidth;
195         tempColour = resBoxColour;
196       }
197       else
198       {
199         curWidth += av.charWidth;
200       }
201
202       i++;
203     }
204
205     graphics.fillRect(av.charWidth * (curStart - start), y1, curWidth,
206                       av.charHeight);
207
208   }
209
210   /**
211    * DOCUMENT ME!
212    *
213    * @param seq DOCUMENT ME!
214    * @param start DOCUMENT ME!
215    * @param end DOCUMENT ME!
216    * @param x1 DOCUMENT ME!
217    * @param y1 DOCUMENT ME!
218    * @param width DOCUMENT ME!
219    * @param height DOCUMENT ME!
220    */
221   public void drawText(SequenceI seq, int start, int end, int y1)
222   {
223     y1 += av.charHeight - av.charHeight / 5; // height/5 replaces pady
224     int charOffset = 0;
225     char s;
226
227     if (end + 1 >= seq.getLength())
228     {
229       end = seq.getLength() - 1;
230     }
231     graphics.setColor(av.textColour);
232
233     if (monospacedFont
234         && av.showText
235         && allGroups.length == 0
236         && !av.getColourText()
237         && av.thresholdTextColour == 0)
238     {
239       if (av.renderGaps)
240       {
241         graphics.drawString(seq.getSequenceAsString(start, end + 1), 0, y1);
242       }
243       else
244       {
245         char gap = av.getGapCharacter();
246         graphics.drawString(seq.getSequenceAsString(start, end + 1).replace(gap,
247             ' '), 0, y1);
248       }
249     }
250     else
251     {
252       boolean getboxColour = false;
253       for (int i = start; i <= end; i++)
254       {
255         graphics.setColor(av.textColour);
256         getboxColour = false;
257         s = seq.getCharAt(i);
258         if (!renderGaps && jalview.util.Comparison.isGap(s))
259         {
260           continue;
261         }
262
263         if (inCurrentSequenceGroup(i))
264         {
265           if (!currentSequenceGroup.getDisplayText())
266           {
267             continue;
268           }
269
270           if (currentSequenceGroup.thresholdTextColour > 0
271               || currentSequenceGroup.getColourText())
272           {
273             getboxColour = true;
274             getBoxColour(currentSequenceGroup.cs, seq, i);
275
276             if (currentSequenceGroup.getColourText())
277             {
278               graphics.setColor(resBoxColour.darker());
279             }
280
281             if (currentSequenceGroup.thresholdTextColour > 0)
282             {
283               if (resBoxColour.getRed() +
284                   resBoxColour.getBlue() +
285                   resBoxColour.getGreen() <
286                   currentSequenceGroup.thresholdTextColour)
287               {
288                 graphics.setColor(currentSequenceGroup.textColour2);
289               }
290             }
291           }
292           else
293           {
294             graphics.setColor(currentSequenceGroup.textColour);
295           }
296
297         }
298         else
299         {
300           if (!av.getShowText())
301           {
302             continue;
303           }
304
305           if (av.getColourText())
306           {
307             getboxColour = true;
308             getBoxColour(av.globalColourScheme, seq, i);
309
310             if (av.getShowBoxes())
311             {
312               graphics.setColor(resBoxColour.darker());
313             }
314             else
315             {
316               graphics.setColor(resBoxColour);
317             }
318           }
319
320           if (av.thresholdTextColour > 0)
321           {
322             if (!getboxColour)
323             {
324               getBoxColour(av.globalColourScheme, seq, i);
325             }
326
327             if (resBoxColour.getRed() +
328                 resBoxColour.getBlue() +
329                 resBoxColour.getGreen() < av.thresholdTextColour)
330             {
331               graphics.setColor(av.textColour2);
332             }
333           }
334
335         }
336
337         charOffset = (av.charWidth - fm.charWidth(s)) / 2;
338         graphics.drawString(String.valueOf(s),
339                             charOffset + av.charWidth * (i - start),
340                             y1);
341
342       }
343     }
344   }
345
346   /**
347    * DOCUMENT ME!
348    *
349    * @param res DOCUMENT ME!
350    *
351    * @return DOCUMENT ME!
352    */
353   boolean inCurrentSequenceGroup(int res)
354   {
355     if (allGroups == null)
356     {
357       return false;
358     }
359
360     for (int i = 0; i < allGroups.length; i++)
361     {
362       if ( (allGroups[i].getStartRes() <= res) &&
363           (allGroups[i].getEndRes() >= res))
364       {
365         currentSequenceGroup = allGroups[i];
366
367         return true;
368       }
369     }
370
371     return false;
372   }
373
374   /**
375    * DOCUMENT ME!
376    *
377    * @param seq DOCUMENT ME!
378    * @param start DOCUMENT ME!
379    * @param end DOCUMENT ME!
380    * @param x1 DOCUMENT ME!
381    * @param y1 DOCUMENT ME!
382    * @param width DOCUMENT ME!
383    * @param height DOCUMENT ME!
384    */
385   public void drawHighlightedText(SequenceI seq, int start, int end, int x1,
386                                   int y1)
387   {
388     int pady = av.charHeight / 5;
389     int charOffset = 0;
390     graphics.setColor(Color.BLACK);
391     graphics.fillRect(x1, y1, av.charWidth * (end - start + 1), av.charHeight);
392     graphics.setColor(Color.white);
393
394     char s = '~';
395
396     // Need to find the sequence position here.
397     if (av.validCharWidth)
398     {
399       for (int i = start; i <= end; i++)
400       {
401         if (i < seq.getLength())
402         {
403           s = seq.getCharAt(i);
404         }
405
406         charOffset = (av.charWidth - fm.charWidth(s)) / 2;
407         graphics.drawString(String.valueOf(s),
408                             charOffset + x1 + (av.charWidth * (i - start)),
409                             (y1 + av.charHeight) - pady);
410       }
411     }
412   }
413
414   public void drawCursor(SequenceI seq, int res, int x1, int y1)
415   {
416     int pady = av.charHeight / 5;
417     int charOffset = 0;
418     graphics.setColor(Color.black);
419     graphics.fillRect(x1, y1, av.charWidth, av.charHeight);
420
421     if (av.validCharWidth)
422     {
423       graphics.setColor(Color.white);
424
425       char s = seq.getCharAt(res);
426
427       charOffset = (av.charWidth - fm.charWidth(s)) / 2;
428       graphics.drawString(String.valueOf(s),
429                           charOffset + x1,
430                           (y1 + av.charHeight) - pady);
431     }
432
433   }
434 }