<= fastPaints hidden columns
[jalview.git] / src / jalview / gui / SeqCanvas.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 java.awt.*;\r
24 import java.awt.image.*;\r
25 \r
26 import javax.swing.*;\r
27 \r
28 \r
29 /**\r
30  * DOCUMENT ME!\r
31  *\r
32  * @author $author$\r
33  * @version $Revision$\r
34  */\r
35 public class SeqCanvas extends JComponent\r
36 {\r
37     FeatureRenderer fr;\r
38     SequenceRenderer sr;\r
39     BufferedImage img;\r
40     Graphics2D gg;\r
41     int imgWidth;\r
42     int imgHeight;\r
43     AlignViewport av;\r
44     SearchResults searchResults = null;\r
45     boolean fastPaint = false;\r
46     int LABEL_WEST;\r
47     int LABEL_EAST;\r
48 \r
49     /**\r
50      * Creates a new SeqCanvas object.\r
51      *\r
52      * @param av DOCUMENT ME!\r
53      */\r
54     public SeqCanvas(AlignViewport av)\r
55     {\r
56         this.av = av;\r
57         fr = new FeatureRenderer(av);\r
58         sr = new SequenceRenderer(av);\r
59         setLayout(new BorderLayout());\r
60         PaintRefresher.Register(this, av.alignment);\r
61         setBackground(Color.white);\r
62     }\r
63 \r
64     MCview.PDBCanvas pdbCanvas;\r
65     public SequenceRenderer getSequenceRenderer()\r
66     {\r
67       return sr;\r
68     }\r
69 \r
70     public FeatureRenderer getFeatureRenderer()\r
71     {\r
72       return fr;\r
73     }\r
74 \r
75     public void setPDBCanvas(MCview.PDBCanvas pc)\r
76     {\r
77       pdbCanvas = pc;\r
78     }\r
79 \r
80     public AlignViewport getViewport()\r
81     {\r
82       return av;\r
83     }\r
84 \r
85 \r
86     /**\r
87      * DOCUMENT ME!\r
88      *\r
89      * @param g DOCUMENT ME!\r
90      * @param startx DOCUMENT ME!\r
91      * @param endx DOCUMENT ME!\r
92      * @param ypos DOCUMENT ME!\r
93      */\r
94     void drawNorthScale(Graphics g, int startx, int endx, int ypos)\r
95     {\r
96         int scalestartx = startx - (startx % 10) + 10;\r
97 \r
98         g.setColor(Color.black);\r
99 \r
100         // NORTH SCALE\r
101         for (int i = scalestartx; i < endx; i += 10)\r
102         {\r
103             String string = String.valueOf(av.getColumnSelection().adjustForHiddenColumns(i));\r
104             g.drawString(string, (i - startx - 1) * av.charWidth,\r
105                 ypos - (av.charHeight / 2));\r
106 \r
107             g.drawLine(((i - startx - 1) * av.charWidth) + (av.charWidth / 2),\r
108                 (ypos + 2) - (av.charHeight / 2),\r
109                 ((i - startx - 1) * av.charWidth) + (av.charWidth / 2), ypos -\r
110                 2);\r
111         }\r
112     }\r
113 \r
114     /**\r
115      * DOCUMENT ME!\r
116      *\r
117      * @param g DOCUMENT ME!\r
118      * @param startx DOCUMENT ME!\r
119      * @param endx DOCUMENT ME!\r
120      * @param ypos DOCUMENT ME!\r
121      */\r
122     void drawWestScale(Graphics g, int startx, int endx, int ypos)\r
123     {\r
124         FontMetrics fm = getFontMetrics(av.getFont());\r
125         ypos += av.charHeight;\r
126 \r
127         // EAST SCALE\r
128         for (int i = 0; i < av.alignment.getHeight(); i++)\r
129         {\r
130             SequenceI seq = av.alignment.getSequenceAt(i);\r
131             int index = startx;\r
132             int value = -1;\r
133 \r
134             while (index < endx)\r
135             {\r
136                 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))\r
137                 {\r
138                     index++;\r
139 \r
140                     continue;\r
141                 }\r
142 \r
143                 value = av.alignment.getSequenceAt(i).findPosition(index);\r
144 \r
145                 break;\r
146             }\r
147 \r
148             if (value != -1)\r
149             {\r
150                 int x = LABEL_WEST - fm.stringWidth(String.valueOf(value))-av.charWidth/2;\r
151                 g.drawString(value + "", x,\r
152                     (ypos + (i * av.charHeight)) - (av.charHeight / 5));\r
153             }\r
154         }\r
155     }\r
156 \r
157     /**\r
158      * DOCUMENT ME!\r
159      *\r
160      * @param g DOCUMENT ME!\r
161      * @param startx DOCUMENT ME!\r
162      * @param endx DOCUMENT ME!\r
163      * @param ypos DOCUMENT ME!\r
164      */\r
165     void drawEastScale(Graphics g, int startx, int endx, int ypos)\r
166     {\r
167         ypos += av.charHeight;\r
168 \r
169         // EAST SCALE\r
170         for (int i = 0; i < av.alignment.getHeight(); i++)\r
171         {\r
172             SequenceI seq = av.alignment.getSequenceAt(i);\r
173             int index = endx;\r
174             int value = -1;\r
175 \r
176             while (index > startx)\r
177             {\r
178                 if (jalview.util.Comparison.isGap(seq.getCharAt(index)))\r
179                 {\r
180                     index--;\r
181 \r
182                     continue;\r
183                 }\r
184 \r
185                 value = av.alignment.getSequenceAt(i).findPosition(index);\r
186 \r
187                 break;\r
188             }\r
189 \r
190             if (value != -1)\r
191             {\r
192                 g.drawString(String.valueOf(value), 0,\r
193                     (ypos + (i * av.charHeight)) - (av.charHeight / 5));\r
194             }\r
195         }\r
196     }\r
197 \r
198     /**\r
199      * DOCUMENT ME!\r
200      *\r
201      * @param horizontal DOCUMENT ME!\r
202      * @param vertical DOCUMENT ME!\r
203      */\r
204     public void fastPaint(int horizontal, int vertical)\r
205     {\r
206         if (gg == null)\r
207         {\r
208             return;\r
209         }\r
210 \r
211         fastPaint = true;\r
212 \r
213         gg.copyArea(horizontal * av.charWidth,\r
214                     vertical * av.charHeight,\r
215                     imgWidth,\r
216                     imgHeight,\r
217                     -horizontal * av.charWidth,\r
218                     -vertical * av.charHeight);\r
219 \r
220         int sr = av.startRes;\r
221         int er = av.endRes;\r
222         int ss = av.startSeq;\r
223         int es = av.endSeq;\r
224         int transX = 0;\r
225         int transY = 0;\r
226 \r
227         if (horizontal > 0) // scrollbar pulled right, image to the left\r
228         {\r
229             er ++;\r
230             transX = (er - sr - horizontal) * av.charWidth;\r
231             sr = er - horizontal;\r
232         }\r
233         else if (horizontal < 0)\r
234         {\r
235             er = sr - horizontal-1;\r
236         }\r
237         else if (vertical > 0) // scroll down\r
238         {\r
239             ss = es - vertical;\r
240 \r
241             if (ss < av.startSeq)\r
242             { // ie scrolling too fast, more than a page at a time\r
243                 ss = av.startSeq;\r
244             }\r
245             else\r
246             {\r
247                 transY = imgHeight - (vertical * av.charHeight);\r
248             }\r
249         }\r
250         else if (vertical < 0)\r
251         {\r
252             es = ss - vertical;\r
253 \r
254             if (es > av.endSeq)\r
255             {\r
256                 es = av.endSeq;\r
257             }\r
258         }\r
259 \r
260         gg.translate(transX, transY);\r
261         drawPanel(gg, sr, er, ss, es, 0);\r
262         gg.translate(-transX, -transY);\r
263 \r
264         repaint();\r
265     }\r
266 \r
267     /**\r
268      * Definitions of startx and endx (hopefully):\r
269      * SMJS This is what I'm working towards!\r
270      *   startx is the first residue (starting at 0) to display.\r
271      *   endx   is the last residue to display (starting at 0).\r
272      *   starty is the first sequence to display (starting at 0).\r
273      *   endy   is the last sequence to display (starting at 0).\r
274      * NOTE 1: The av limits are set in setFont in this class and\r
275      * in the adjustment listener in SeqPanel when the scrollbars move.\r
276      */\r
277 \r
278     // Set this to false to force a full panel paint\r
279     public void paintComponent(Graphics g)\r
280     {\r
281         super.paintComponent(g);\r
282 \r
283         sr.renderGaps(av.renderGaps);\r
284 \r
285         if ( img != null && (fastPaint\r
286              || (getVisibleRect().width != g.getClipBounds().width)\r
287              || (getVisibleRect().height != g.getClipBounds().height)))\r
288         {\r
289             g.drawImage(img, 0, 0, this);\r
290             fastPaint = false;\r
291             return;\r
292         }\r
293 \r
294 \r
295         // this draws the whole of the alignment\r
296         imgWidth = getWidth();\r
297         imgHeight = getHeight();\r
298 \r
299         imgWidth -= (imgWidth % av.charWidth);\r
300         imgHeight -= (imgHeight % av.charHeight);\r
301 \r
302         if ((imgWidth < 1) || (imgHeight < 1))\r
303         {\r
304             return;\r
305         }\r
306 \r
307         img = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);\r
308         gg = (Graphics2D) img.getGraphics();\r
309         gg.setFont(av.getFont());\r
310 \r
311         if (av.antiAlias)\r
312           gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
313                               RenderingHints.VALUE_ANTIALIAS_ON);\r
314 \r
315         gg.setColor(Color.white);\r
316         gg.fillRect(0, 0, imgWidth, imgHeight);\r
317 \r
318 \r
319         if (av.getWrapAlignment())\r
320         {\r
321             drawWrappedPanel(gg, getWidth(), getHeight(), av.startRes);\r
322         }\r
323         else\r
324         {\r
325             drawPanel(gg, av.startRes, av.endRes, av.startSeq, av.endSeq, 0);\r
326         }\r
327 \r
328         g.drawImage(img, 0, 0, this);\r
329 \r
330         if (pdbCanvas != null)\r
331         {\r
332          pdbCanvas.updateSeqColours();\r
333         }\r
334 \r
335     }\r
336 \r
337     /**\r
338      * DOCUMENT ME!\r
339      *\r
340      * @param cwidth DOCUMENT ME!\r
341      *\r
342      * @return DOCUMENT ME!\r
343      */\r
344     public int getWrappedCanvasWidth(int cwidth)\r
345     {\r
346         FontMetrics fm = getFontMetrics(av.getFont());\r
347 \r
348         LABEL_EAST = 0;\r
349         LABEL_WEST = 0;\r
350 \r
351         if (av.scaleRightWrapped)\r
352         {\r
353             LABEL_EAST = fm.stringWidth(getMask());\r
354         }\r
355 \r
356         if (av.scaleLeftWrapped)\r
357         {\r
358             LABEL_WEST = fm.stringWidth(getMask());\r
359         }\r
360 \r
361         return (cwidth - LABEL_EAST - LABEL_WEST) / av.charWidth;\r
362     }\r
363 \r
364 \r
365     /**\r
366      * Generates a string of zeroes.\r
367      * @return String\r
368      */\r
369     String getMask()\r
370     {\r
371       String mask = "00";\r
372       for (int i = av.alignment.getWidth(); i > 0; i /= 10)\r
373       {\r
374         mask += "0";\r
375       }\r
376       return mask;\r
377     }\r
378 \r
379     /**\r
380      * DOCUMENT ME!\r
381      *\r
382      * @param g DOCUMENT ME!\r
383      * @param canvasWidth DOCUMENT ME!\r
384      * @param canvasHeight DOCUMENT ME!\r
385      * @param startRes DOCUMENT ME!\r
386      */\r
387     public void drawWrappedPanel(Graphics g, int canvasWidth, int canvasHeight,\r
388         int startRes)\r
389     {\r
390 \r
391         AlignmentI al = av.getAlignment();\r
392 \r
393         FontMetrics fm = getFontMetrics(av.getFont());\r
394 \r
395         int LABEL_EAST = 0;\r
396 \r
397         if (av.scaleRightWrapped)\r
398         {\r
399             LABEL_EAST = fm.stringWidth(getMask());\r
400         }\r
401 \r
402         int LABEL_WEST = 0;\r
403 \r
404         if (av.scaleLeftWrapped)\r
405         {\r
406             LABEL_WEST = fm.stringWidth(getMask());\r
407         }\r
408 \r
409         int hgap = av.charHeight;\r
410         if(av.scaleAboveWrapped)\r
411           hgap += av.charHeight;\r
412 \r
413         int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / av.charWidth;\r
414         int cHeight = av.getAlignment().getHeight() * av.charHeight;\r
415 \r
416         av.setWrappedWidth(cWidth);\r
417 \r
418         av.endRes = av.startRes + cWidth;\r
419 \r
420 \r
421         int endx = (startRes + cWidth) - 1;\r
422         int ypos = hgap;\r
423 \r
424 \r
425         while ((ypos <= canvasHeight) && (startRes < av.alignment.getWidth()))\r
426         {\r
427             g.setFont(av.getFont());\r
428             g.setColor(Color.black);\r
429 \r
430             if (av.scaleLeftWrapped)\r
431             {\r
432                 drawWestScale(g, startRes, endx, ypos);\r
433             }\r
434 \r
435             if (av.scaleRightWrapped)\r
436             {\r
437                 g.translate(canvasWidth - LABEL_EAST, 0);\r
438                 drawEastScale(g, startRes, endx, ypos);\r
439                 g.translate(-(canvasWidth - LABEL_EAST), 0);\r
440             }\r
441 \r
442             g.translate(LABEL_WEST, 0);\r
443 \r
444             if (av.scaleAboveWrapped)\r
445             {\r
446                 drawNorthScale(g, startRes, endx, ypos);\r
447             }\r
448 \r
449             // When printing we have an extra clipped region,\r
450             // the Printable page which we need to account for here\r
451             Shape clip = g.getClip();\r
452 \r
453             if (clip == null)\r
454             {\r
455                 g.setClip(0, 0, cWidth * av.charWidth, canvasHeight);\r
456             }\r
457             else\r
458             {\r
459                 g.setClip(0, (int) clip.getBounds().getY(),\r
460                     cWidth * av.charWidth, (int) clip.getBounds().getHeight());\r
461             }\r
462 \r
463             if (av.vconsensus!=null && av.alignment.getWidth() >= av.vconsensus.size())\r
464             {\r
465               endx = av.vconsensus.size() - 2;\r
466             }\r
467 \r
468 \r
469             drawPanel(g, startRes, endx, 0, al.getHeight(), ypos);\r
470 \r
471             if(av.showAnnotation)\r
472             {\r
473               g.translate(0, cHeight + ypos + 3);\r
474               if(annotations==null)\r
475                 annotations = new AnnotationPanel(av);\r
476 \r
477               annotations.drawComponent( (Graphics2D) g, startRes, endx + 1);\r
478               g.translate(0, -cHeight - ypos);\r
479             }\r
480             g.setClip(clip);\r
481             g.translate(-LABEL_WEST, 0);\r
482 \r
483             ypos += cHeight+getAnnotationHeight()+hgap;\r
484             if(av.showAnnotation)\r
485               ypos -= 3;\r
486 \r
487             startRes += cWidth;\r
488             endx = (startRes + cWidth) - 1;\r
489 \r
490             if (endx > al.getWidth())\r
491             {\r
492                 endx = al.getWidth();\r
493             }\r
494         }\r
495     }\r
496 \r
497     AnnotationPanel annotations;\r
498     int getAnnotationHeight()\r
499     {\r
500       if(!av.showAnnotation)\r
501         return 0;\r
502 \r
503       if(annotations==null)\r
504         annotations = new AnnotationPanel(av);\r
505 \r
506       return annotations.adjustPanelHeight();\r
507     }\r
508 \r
509     /**\r
510      * DOCUMENT ME!\r
511      *\r
512      * @param g1 DOCUMENT ME!\r
513      * @param x1 DOCUMENT ME!\r
514      * @param x2 DOCUMENT ME!\r
515      * @param y1 DOCUMENT ME!\r
516      * @param y2 DOCUMENT ME!\r
517      * @param startx DOCUMENT ME!\r
518      * @param starty DOCUMENT ME!\r
519      * @param offset DOCUMENT ME!\r
520      */\r
521 \r
522     float aaRatio = 2f/3f;\r
523     public void increaseAARatio()\r
524     {\r
525       aaRatio += .025;\r
526       if(aaRatio>1)\r
527         aaRatio = 1;\r
528 \r
529       repaint();\r
530     }\r
531 \r
532     public void decreaseAARation()\r
533     {\r
534       aaRatio -= .025;\r
535       if(aaRatio<0)\r
536         aaRatio = 0;\r
537 \r
538       repaint();\r
539     }\r
540 \r
541 \r
542     void drawPanel(Graphics g1, int startRes, int endRes,\r
543                     int startSeq, int endSeq, int offset)\r
544     {\r
545       if(!av.hasHiddenColumns)\r
546       {\r
547         draw(g1, startRes, endRes, startSeq, endSeq, offset);\r
548       }\r
549       else\r
550       {\r
551         java.util.Vector regions = av.getColumnSelection().getHiddenColumns();\r
552 \r
553         int screenY = 0;\r
554         int blockStart = startRes;\r
555         int blockEnd = endRes;\r
556 \r
557         for (int i = 0; i < regions.size(); i++)\r
558         {\r
559           int[] region = (int[]) regions.elementAt(i);\r
560           int hideStart = region[0];\r
561           int hideEnd = region[1];\r
562 \r
563           if (hideStart <= blockStart)\r
564           {\r
565             blockStart += (hideEnd - hideStart) + 1;\r
566             continue;\r
567           }\r
568 \r
569           blockEnd = hideStart - 1;\r
570 \r
571           g1.translate(screenY * av.charWidth, 0);\r
572 \r
573           draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);\r
574 \r
575           g1.setColor(Color.blue);\r
576           g1.drawLine( (blockEnd - blockStart + 1) * av.charWidth - 1,\r
577                       startSeq + offset,\r
578                       (blockEnd - blockStart + 1) * av.charWidth - 1,\r
579                       startSeq + (endSeq - startSeq) * av.charHeight + offset);\r
580           g1.drawLine( (blockEnd - blockStart + 1) * av.charWidth,\r
581                       startSeq + offset,\r
582                       (blockEnd - blockStart + 1) * av.charWidth,\r
583                       startSeq + (endSeq - startSeq) * av.charHeight + offset);\r
584 \r
585           g1.translate( -screenY * av.charWidth, 0);\r
586           screenY += blockEnd - blockStart + 1;\r
587           blockStart = hideEnd + 1;\r
588         }\r
589 \r
590         if (screenY <= (endRes - startRes))\r
591         {\r
592           blockEnd = blockStart + (endRes - startRes) - screenY;\r
593           g1.translate(screenY * av.charWidth, 0);\r
594           draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);\r
595           g1.translate( -screenY * av.charWidth, 0);\r
596         }\r
597       }\r
598 \r
599     }\r
600 \r
601 \r
602 \r
603 \r
604     //int startRes, int endRes, int startSeq, int endSeq, int x, int y,\r
605     // int x1, int x2, int y1, int y2, int startx, int starty,\r
606     void draw(Graphics g1,\r
607                    int startRes, int endRes,\r
608                    int startSeq, int endSeq,\r
609                    int offset)\r
610    {\r
611       Graphics2D g = (Graphics2D) g1;\r
612       g.setFont(av.getFont());\r
613 \r
614       SequenceI nextSeq;\r
615 \r
616         /// First draw the sequences\r
617         /////////////////////////////\r
618         for (int i = startSeq; i < endSeq; i++)\r
619         {\r
620             nextSeq = av.alignment.getSequenceAt(i);\r
621 \r
622             sr.drawSequence(g, nextSeq, av.alignment.findAllGroups(nextSeq),\r
623                             startRes, endRes,\r
624                             offset + ( (i - startSeq) * av.charHeight));\r
625 \r
626             if (av.showSequenceFeatures)\r
627             {\r
628                 fr.drawSequence(g1, nextSeq, startRes, endRes,\r
629                     offset + ((i - startSeq) * av.charHeight), av.charWidth,\r
630                     av.charHeight);\r
631             }\r
632 \r
633             /// Highlight search Results once all sequences have been drawn\r
634             //////////////////////////////////////////////////////////\r
635             if (searchResults != null)\r
636             {\r
637               int[] visibleResults = searchResults.getResults(nextSeq, startRes, endRes);\r
638               if (visibleResults != null)\r
639                 for (int r = 0; r < visibleResults.length; r += 2)\r
640                 {\r
641                   sr.drawHighlightedText(nextSeq, visibleResults[r],\r
642                                          visibleResults[r + 1],\r
643                                          (visibleResults[r] - startRes) * av.charWidth,\r
644                                          offset + ( (i - startSeq) * av.charHeight),\r
645                                          av.charWidth, av.charHeight);\r
646                 }\r
647             }\r
648           }\r
649 \r
650         //\r
651         /////////////////////////////////////\r
652         // Now outline any areas if necessary\r
653         /////////////////////////////////////\r
654         SequenceGroup group = av.getSelectionGroup();\r
655 \r
656         int sx = -1;\r
657         int sy = -1;\r
658         int ex = -1;\r
659         int groupIndex = -1;\r
660 \r
661         if ((group == null) && (av.alignment.getGroups().size() > 0))\r
662         {\r
663             group = (SequenceGroup) av.alignment.getGroups().elementAt(0);\r
664             groupIndex = 0;\r
665         }\r
666 \r
667         if (group != null)\r
668         {\r
669             do\r
670             {\r
671                 int oldY = -1;\r
672                 int i = 0;\r
673                 boolean inGroup = false;\r
674                 int top = -1;\r
675                 int bottom = -1;\r
676 \r
677                 for (i = startSeq; i < endSeq; i++)\r
678                 {\r
679                     sx = (group.getStartRes() - startRes) * av.charWidth;\r
680                     sy = offset + ((i - startSeq) * av.charHeight);\r
681                     ex = (((group.getEndRes() + 1) - group.getStartRes()) * av.charWidth) -\r
682                         1;\r
683 \r
684                     if(sx+ex<0 || sx>imgWidth)\r
685                     {\r
686                       continue;\r
687                     }\r
688 \r
689                     if ( (sx <= (endRes-startRes)*av.charWidth) &&\r
690                             group.sequences.contains(av.alignment.getSequenceAt(\r
691                                     i)))\r
692                     {\r
693                         if ((bottom == -1) &&\r
694                                 !group.sequences.contains(\r
695                                     av.alignment.getSequenceAt(i + 1)))\r
696                         {\r
697                             bottom = sy + av.charHeight;\r
698                         }\r
699 \r
700                         if (!inGroup)\r
701                         {\r
702                             if (((top == -1) && (i == 0)) ||\r
703                                     !group.sequences.contains(\r
704                                         av.alignment.getSequenceAt(i - 1)))\r
705                             {\r
706                                 top = sy;\r
707                             }\r
708 \r
709                             oldY = sy;\r
710                             inGroup = true;\r
711 \r
712                             if (group == av.getSelectionGroup())\r
713                             {\r
714                                 g.setStroke(new BasicStroke(1,\r
715                                         BasicStroke.CAP_BUTT,\r
716                                         BasicStroke.JOIN_ROUND, 3f,\r
717                                         new float[] { 5f, 3f }, 0f));\r
718                                 g.setColor(Color.RED);\r
719                             }\r
720                             else\r
721                             {\r
722                                 g.setStroke(new BasicStroke());\r
723                                 g.setColor(group.getOutlineColour());\r
724                             }\r
725                         }\r
726                     }\r
727                     else\r
728                     {\r
729                       if (inGroup)\r
730                       {\r
731                         if (sx >= 0 && sx < imgWidth)\r
732                           g.drawLine(sx, oldY, sx, sy);\r
733 \r
734                         if (sx + ex < imgWidth)\r
735                           g.drawLine(sx + ex, oldY, sx + ex, sy);\r
736 \r
737                         if (sx < 0)\r
738                         {\r
739                           ex += sx;\r
740                           sx = 0;\r
741                         }\r
742 \r
743                         if (sx + ex > imgWidth)\r
744                           ex = imgWidth;\r
745 \r
746                         else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)\r
747                           ex = (endRes - startRes + 1) * av.charWidth;\r
748 \r
749                         if (top != -1)\r
750                         {\r
751                           g.drawLine(sx, top, sx + ex, top);\r
752                           top = -1;\r
753                         }\r
754 \r
755                         if (bottom != -1)\r
756                         {\r
757                           g.drawLine(sx, bottom, sx + ex, bottom);\r
758                           bottom = -1;\r
759                         }\r
760 \r
761                         inGroup = false;\r
762                         }\r
763                     }\r
764                 }\r
765 \r
766                 if (inGroup)\r
767                 {\r
768                   sy = offset + ( (i - startSeq) * av.charHeight);\r
769                   if (sx >= 0 && sx < imgWidth)\r
770                     g.drawLine(sx, oldY, sx, sy);\r
771 \r
772                   if (sx + ex < imgWidth)\r
773                     g.drawLine(sx + ex, oldY, sx + ex, sy);\r
774 \r
775                   if (sx < 0)\r
776                   {\r
777                     ex += sx;\r
778                     sx = 0;\r
779                   }\r
780 \r
781                   if (sx + ex > imgWidth)\r
782                     ex = imgWidth;\r
783                   else if (sx + ex >= (endRes - startRes + 1) * av.charWidth)\r
784                     ex = (endRes - startRes + 1) * av.charWidth;\r
785 \r
786                   if (top != -1)\r
787                   {\r
788                     g.drawLine(sx, top, sx + ex, top);\r
789                     top = -1;\r
790                   }\r
791 \r
792                   if (bottom != -1)\r
793                   {\r
794                     g.drawLine(sx, bottom - 1, sx + ex, bottom - 1);\r
795                     bottom = -1;\r
796                   }\r
797 \r
798                     inGroup = false;\r
799                 }\r
800 \r
801                 groupIndex++;\r
802 \r
803                 if (groupIndex >= av.alignment.getGroups().size())\r
804                 {\r
805                     break;\r
806                 }\r
807 \r
808                 group = (SequenceGroup) av.alignment.getGroups().elementAt(groupIndex);\r
809             }\r
810             while (groupIndex < av.alignment.getGroups().size());\r
811         }\r
812     }\r
813 \r
814     /**\r
815      * DOCUMENT ME!\r
816      *\r
817      * @param results DOCUMENT ME!\r
818      */\r
819     public void highlightSearchResults(SearchResults results)\r
820     {\r
821         img = null;\r
822 \r
823         searchResults = results;\r
824 \r
825         repaint();\r
826     }\r
827 }\r