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