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