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