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