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