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