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