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