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