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