Create new image only on resize, set fontMetrics on new image
[jalview.git] / src / jalview / gui / AnnotationPanel.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.event.*;\r
25 import java.awt.image.*;\r
26 \r
27 import java.util.*;\r
28 \r
29 import javax.swing.*;\r
30 \r
31 \r
32 /**\r
33  * DOCUMENT ME!\r
34  *\r
35  * @author $author$\r
36  * @version $Revision$\r
37  */\r
38 public class AnnotationPanel extends JPanel implements MouseListener,\r
39     MouseMotionListener, ActionListener, AdjustmentListener\r
40 {\r
41     static String HELIX = "Helix";\r
42     static String SHEET = "Sheet";\r
43     static String LABEL = "Label";\r
44     static String REMOVE = "Remove Annotation";\r
45     static String COLOUR = "Colour";\r
46     static Color HELIX_COLOUR = Color.red.darker();\r
47     static Color SHEET_COLOUR = Color.green.darker().darker();\r
48 \r
49     /** DOCUMENT ME!! */\r
50     public static int GRAPH_HEIGHT = 40;\r
51     AlignViewport av;\r
52     AlignmentPanel ap;\r
53     int activeRow = -1;\r
54     Vector activeRes;\r
55     BufferedImage image;\r
56     Graphics2D gg;\r
57     FontMetrics fm;\r
58     int imgWidth = 0;\r
59     boolean fastPaint = false;\r
60 \r
61     /**\r
62      * Creates a new AnnotationPanel object.\r
63      *\r
64      * @param ap DOCUMENT ME!\r
65      */\r
66     public AnnotationPanel(AlignmentPanel ap)\r
67     {\r
68         ToolTipManager.sharedInstance().registerComponent(this);\r
69         ToolTipManager.sharedInstance().setInitialDelay(0);\r
70         ToolTipManager.sharedInstance().setDismissDelay(10000);\r
71         this.ap = ap;\r
72         av = ap.av;\r
73         this.setLayout(null);\r
74         addMouseListener(this);\r
75         addMouseMotionListener(this);\r
76         ap.annotationScroller.getVerticalScrollBar().addAdjustmentListener(this);\r
77     }\r
78 \r
79     /**\r
80      * DOCUMENT ME!\r
81      *\r
82      * @param evt DOCUMENT ME!\r
83      */\r
84     public void adjustmentValueChanged(AdjustmentEvent evt)\r
85     {\r
86         ap.alabels.setScrollOffset(-evt.getValue());\r
87     }\r
88 \r
89     /**\r
90      * DOCUMENT ME!\r
91      */\r
92     public void adjustPanelHeight()\r
93     {\r
94         // setHeight of panels\r
95         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
96         int height = 0;\r
97 \r
98         if (aa != null)\r
99         {\r
100             for (int i = 0; i < aa.length; i++)\r
101             {\r
102                 if (!aa[i].visible)\r
103                 {\r
104                     continue;\r
105                 }\r
106 \r
107                 aa[i].height = 0;\r
108 \r
109                 if (aa[i].hasText)\r
110                 {\r
111                     aa[i].height += av.charHeight;\r
112                 }\r
113 \r
114                 if (aa[i].hasIcons)\r
115                 {\r
116                     aa[i].height += 16;\r
117                 }\r
118 \r
119                 if (aa[i].isGraph)\r
120                 {\r
121                     aa[i].height += GRAPH_HEIGHT;\r
122                 }\r
123 \r
124                 if (aa[i].height == 0)\r
125                 {\r
126                     aa[i].height = 20;\r
127                 }\r
128 \r
129                 height += aa[i].height;\r
130             }\r
131         }\r
132         else\r
133         {\r
134             height = 20;\r
135         }\r
136 \r
137         this.setPreferredSize(new Dimension(1, height));\r
138     }\r
139 \r
140     /**\r
141      * DOCUMENT ME!\r
142      *\r
143      * @param col DOCUMENT ME!\r
144      */\r
145     public void removeEditableColumn(int col)\r
146     {\r
147         if (activeRow == -1)\r
148         {\r
149             AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
150 \r
151             for (int j = 0; j < aa.length; j++)\r
152             {\r
153                 if (aa[j].editable)\r
154                 {\r
155                     activeRow = j;\r
156 \r
157                     break;\r
158                 }\r
159             }\r
160         }\r
161 \r
162         if ((activeRes != null) && activeRes.contains(String.valueOf(col)))\r
163         {\r
164             activeRes.removeElement(String.valueOf(col));\r
165         }\r
166 \r
167         repaint();\r
168     }\r
169 \r
170     /**\r
171      * DOCUMENT ME!\r
172      *\r
173      * @param col DOCUMENT ME!\r
174      */\r
175     public void addEditableColumn(int col)\r
176     {\r
177         if (activeRow == -1)\r
178         {\r
179             AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
180 \r
181             for (int j = 0; j < aa.length; j++)\r
182             {\r
183                 if (aa[j].editable)\r
184                 {\r
185                     activeRow = j;\r
186 \r
187                     break;\r
188                 }\r
189             }\r
190         }\r
191 \r
192         if (activeRes == null)\r
193         {\r
194             activeRes = new Vector();\r
195         }\r
196 \r
197         if (!activeRes.contains(String.valueOf(col)))\r
198         {\r
199             activeRes.addElement(String.valueOf(col));\r
200         }\r
201 \r
202         repaint();\r
203     }\r
204 \r
205     /**\r
206      * DOCUMENT ME!\r
207      *\r
208      * @param evt DOCUMENT ME!\r
209      */\r
210     public void actionPerformed(ActionEvent evt)\r
211     {\r
212         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
213         Annotation[] anot = aa[activeRow].annotations;\r
214 \r
215         if (evt.getActionCommand().equals(REMOVE))\r
216         {\r
217             for (int i = 0; i < activeRes.size(); i++)\r
218             {\r
219                 anot[Integer.parseInt(activeRes.get(i).toString())] = null;\r
220                 anot[Integer.parseInt(activeRes.get(i).toString())] = null;\r
221             }\r
222         }\r
223         else if (evt.getActionCommand().equals(LABEL))\r
224         {\r
225             String label = JOptionPane.showInputDialog(this, "Enter Label ",\r
226                     "Enter label", JOptionPane.QUESTION_MESSAGE);\r
227 \r
228             if (label == null)\r
229             {\r
230                 return;\r
231             }\r
232 \r
233             if ((label.length() > 0) && !aa[activeRow].hasText)\r
234             {\r
235                 aa[activeRow].hasText = true;\r
236             }\r
237 \r
238             for (int i = 0; i < activeRes.size(); i++)\r
239             {\r
240                 int index = Integer.parseInt(activeRes.get(i).toString());\r
241 \r
242                 if (anot[index] == null)\r
243                 {\r
244                     anot[index] = new Annotation(label, "", ' ', 0);\r
245                 }\r
246 \r
247                 anot[index].displayCharacter = label;\r
248             }\r
249         }\r
250         else if (evt.getActionCommand().equals(COLOUR))\r
251         {\r
252             Color col = JColorChooser.showDialog(this,\r
253                     "Choose foreground colour", Color.black);\r
254 \r
255             for (int i = 0; i < activeRes.size(); i++)\r
256             {\r
257                 int index = Integer.parseInt(activeRes.get(i).toString());\r
258 \r
259                 if (anot[index] == null)\r
260                 {\r
261                     anot[index] = new Annotation("", "", ' ', 0);\r
262                 }\r
263 \r
264                 anot[index].colour = col;\r
265             }\r
266         }\r
267         else // HELIX OR SHEET\r
268         {\r
269             char type = 0;\r
270             String symbol = "\u03B1";\r
271 \r
272             if (evt.getActionCommand().equals(HELIX))\r
273             {\r
274                 type = 'H';\r
275             }\r
276             else if (evt.getActionCommand().equals(SHEET))\r
277             {\r
278                 type = 'E';\r
279                 symbol = "\u03B2";\r
280             }\r
281 \r
282             if (!aa[activeRow].hasIcons)\r
283             {\r
284                 aa[activeRow].hasIcons = true;\r
285             }\r
286 \r
287             String label = JOptionPane.showInputDialog("Enter a label for the structure?",\r
288                     symbol);\r
289 \r
290             if (label == null)\r
291             {\r
292                 return;\r
293             }\r
294 \r
295             if ((label.length() > 0) && !aa[activeRow].hasText)\r
296             {\r
297                 aa[activeRow].hasText = true;\r
298             }\r
299 \r
300             for (int i = 0; i < activeRes.size(); i++)\r
301             {\r
302                 int index = Integer.parseInt(activeRes.get(i).toString());\r
303 \r
304                 if (anot[index] == null)\r
305                 {\r
306                     anot[index] = new Annotation(label, "", type, 0);\r
307                 }\r
308 \r
309                 anot[index].secondaryStructure = type;\r
310                 anot[index].displayCharacter = label;\r
311             }\r
312         }\r
313 \r
314         adjustPanelHeight();\r
315         activeRes = null;\r
316         repaint();\r
317 \r
318         return;\r
319     }\r
320 \r
321     /**\r
322      * DOCUMENT ME!\r
323      *\r
324      * @param evt DOCUMENT ME!\r
325      */\r
326     public void mousePressed(MouseEvent evt)\r
327     {\r
328         int height = 0;\r
329         activeRow = -1;\r
330 \r
331         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
332 \r
333         for (int i = 0; i < aa.length; i++)\r
334         {\r
335             height += aa[i].height;\r
336 \r
337             if (evt.getY() < height)\r
338             {\r
339                 if (aa[i].editable)\r
340                 {\r
341                     activeRow = i;\r
342                 }\r
343                 else\r
344                 {\r
345                     activeRes = null;\r
346                 }\r
347 \r
348                 break;\r
349             }\r
350         }\r
351 \r
352         if (SwingUtilities.isRightMouseButton(evt))\r
353         {\r
354             if (activeRes == null)\r
355             {\r
356                 return;\r
357             }\r
358 \r
359             JPopupMenu pop = new JPopupMenu("Structure type");\r
360             JMenuItem item = new JMenuItem(HELIX);\r
361             item.addActionListener(this);\r
362             pop.add(item);\r
363             item = new JMenuItem(SHEET);\r
364             item.addActionListener(this);\r
365             pop.add(item);\r
366             item = new JMenuItem(LABEL);\r
367             item.addActionListener(this);\r
368             pop.add(item);\r
369             item = new JMenuItem(COLOUR);\r
370             item.addActionListener(this);\r
371             pop.add(item);\r
372             item = new JMenuItem(REMOVE);\r
373             item.addActionListener(this);\r
374             pop.add(item);\r
375             pop.show(this, evt.getX(), evt.getY());\r
376 \r
377             return;\r
378         }\r
379 \r
380         if (aa == null)\r
381         {\r
382             return;\r
383         }\r
384 \r
385         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
386 \r
387         if (evt.isControlDown() || evt.isAltDown())\r
388         {\r
389             addEditableColumn(res);\r
390         }\r
391         else if (evt.isShiftDown())\r
392         {\r
393             if (activeRes == null)\r
394             {\r
395                 activeRes = new Vector();\r
396             }\r
397             else\r
398             {\r
399                 int start = Integer.parseInt(activeRes.get(activeRes.size() -\r
400                             1).toString());\r
401                 int end = res;\r
402 \r
403                 if (end < start)\r
404                 {\r
405                     int temp = end;\r
406                     end = start;\r
407                     start = temp;\r
408                 }\r
409 \r
410                 for (int n = start; n <= end; n++)\r
411                 {\r
412                     addEditableColumn(n);\r
413                 }\r
414             }\r
415         }\r
416         else\r
417         {\r
418             activeRes = new Vector();\r
419             activeRes.addElement(String.valueOf(res));\r
420         }\r
421 \r
422         repaint();\r
423     }\r
424 \r
425     /**\r
426      * DOCUMENT ME!\r
427      *\r
428      * @param evt DOCUMENT ME!\r
429      */\r
430     public void mouseReleased(MouseEvent evt)\r
431     {\r
432     }\r
433 \r
434     /**\r
435      * DOCUMENT ME!\r
436      *\r
437      * @param evt DOCUMENT ME!\r
438      */\r
439     public void mouseEntered(MouseEvent evt)\r
440     {\r
441     }\r
442 \r
443     /**\r
444      * DOCUMENT ME!\r
445      *\r
446      * @param evt DOCUMENT ME!\r
447      */\r
448     public void mouseExited(MouseEvent evt)\r
449     {\r
450     }\r
451 \r
452     /**\r
453      * DOCUMENT ME!\r
454      *\r
455      * @param evt DOCUMENT ME!\r
456      */\r
457     public void mouseDragged(MouseEvent evt)\r
458     {\r
459     }\r
460 \r
461     /**\r
462      * DOCUMENT ME!\r
463      *\r
464      * @param evt DOCUMENT ME!\r
465      */\r
466     public void mouseMoved(MouseEvent evt)\r
467     {\r
468         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
469 \r
470         if (aa == null)\r
471         {\r
472             return;\r
473         }\r
474 \r
475         int row = -1;\r
476         int height = 0;\r
477 \r
478         for (int i = 0; i < aa.length; i++)\r
479         {\r
480             if (aa[i].visible)\r
481             {\r
482                 height += aa[i].height;\r
483             }\r
484 \r
485             if (evt.getY() < height)\r
486             {\r
487                 row = i;\r
488 \r
489                 break;\r
490             }\r
491         }\r
492 \r
493         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
494 \r
495         if ((row > -1) && (res < aa[row].annotations.length) &&\r
496                 (aa[row].annotations[res] != null))\r
497         {\r
498             this.setToolTipText(aa[row].annotations[res].description);\r
499 \r
500             StringBuffer text = new StringBuffer("Sequence position " +\r
501                     (res + 1) + "  " + aa[row].annotations[res].description);\r
502             ap.alignFrame.statusBar.setText(text.toString());\r
503         }\r
504     }\r
505 \r
506     /**\r
507      * DOCUMENT ME!\r
508      *\r
509      * @param evt DOCUMENT ME!\r
510      */\r
511     public void mouseClicked(MouseEvent evt)\r
512     {\r
513     }\r
514 \r
515     /**\r
516      * DOCUMENT ME!\r
517      *\r
518      * @param g DOCUMENT ME!\r
519      */\r
520     public void paintComponent(Graphics g)\r
521     {\r
522       g.setColor(Color.white);\r
523       g.fillRect(0, 0, getWidth(), getHeight());\r
524 \r
525       if (fastPaint)\r
526       {\r
527         g.drawImage(image, 0, 0, this);\r
528         fastPaint = false;\r
529         return;\r
530       }\r
531 \r
532       imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
533 \r
534       if (image != null && imgWidth == image.getWidth())\r
535       {\r
536         //This will be called by a mouse over, tool tip etc\r
537         // no need to redraw whole image\r
538         g.drawImage(image, 0, 0, this);\r
539         fastPaint = false;\r
540         return;\r
541       }\r
542 \r
543       image = new BufferedImage(imgWidth, ap.annotationPanel.getHeight(),\r
544                                 BufferedImage.TYPE_INT_RGB);\r
545       gg = (Graphics2D) image.getGraphics();\r
546       gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
547                           RenderingHints.VALUE_ANTIALIAS_ON);\r
548 \r
549       gg.setFont(av.getFont());\r
550       fm = gg.getFontMetrics();\r
551 \r
552       drawComponent(gg, av.startRes, av.endRes + 1);\r
553       g.drawImage(image, 0, 0, this);\r
554     }\r
555 \r
556     /**\r
557      * DOCUMENT ME!\r
558      *\r
559      * @param horizontal DOCUMENT ME!\r
560      */\r
561     public void fastPaint(int horizontal)\r
562     {\r
563         if ((horizontal == 0) ||\r
564                 (av.alignment.getAlignmentAnnotation() == null) ||\r
565                 (av.alignment.getAlignmentAnnotation().length < 1))\r
566         {\r
567             repaint();\r
568 \r
569             return;\r
570         }\r
571 \r
572         gg.copyArea(0, 0, imgWidth, getHeight(), -horizontal * av.charWidth, 0);\r
573 \r
574         int sr = av.startRes;\r
575         int er = av.endRes + 1;\r
576         int transX = 0;\r
577 \r
578         if (horizontal > 0) // scrollbar pulled right, image to the left\r
579         {\r
580             transX = (er - sr - horizontal) * av.charWidth;\r
581             sr = er - horizontal;\r
582         }\r
583         else if (horizontal < 0)\r
584         {\r
585             er = sr - horizontal;\r
586         }\r
587 \r
588         gg.translate(transX, 0);\r
589 \r
590         drawComponent(gg, sr, er);\r
591 \r
592         gg.translate(-transX, 0);\r
593 \r
594         fastPaint = true;\r
595 \r
596         repaint();\r
597 \r
598     }\r
599 \r
600     /**\r
601      * DOCUMENT ME!\r
602      *\r
603      * @param g DOCUMENT ME!\r
604      * @param startRes DOCUMENT ME!\r
605      * @param endRes DOCUMENT ME!\r
606      */\r
607     public void drawComponent(Graphics2D g, int startRes, int endRes)\r
608     {\r
609         g.setColor(Color.white);\r
610         g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getHeight());\r
611 \r
612         if ((av.alignment.getAlignmentAnnotation() == null) ||\r
613                 (av.alignment.getAlignmentAnnotation().length < 1))\r
614         {\r
615             g.setColor(Color.white);\r
616             g.fillRect(0, 0, getWidth(), getHeight());\r
617             g.setColor(Color.black);\r
618             g.drawString("Alignment has no annotations", 20, 15);\r
619 \r
620             return;\r
621         }\r
622 \r
623         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
624 \r
625         int j;\r
626         int x = 0;\r
627         int y = 0;\r
628         char[] lastSS = new char[aa.length];\r
629         int[] lastSSX = new int[aa.length];\r
630         int iconOffset = av.charHeight / 2;\r
631         boolean validRes = false;\r
632 \r
633         //\u03B2 \u03B1\r
634         for (int i = 0; i < aa.length; i++)\r
635         {\r
636             AlignmentAnnotation row = aa[i];\r
637 \r
638             if (!row.visible)\r
639             {\r
640                 continue;\r
641             }\r
642 \r
643             if (row.isGraph)\r
644             {\r
645                 // this is so that we draw the characters below the graph\r
646                 y += row.height;\r
647 \r
648                 if (row.hasText)\r
649                 {\r
650                     y -= av.charHeight;\r
651                 }\r
652             }\r
653 \r
654             if (row.hasText)\r
655             {\r
656                 iconOffset = av.charHeight / 2;\r
657             }\r
658             else\r
659             {\r
660                 iconOffset = 0;\r
661             }\r
662 \r
663             for (j = startRes; j < endRes; j++)\r
664             {\r
665                 if ((row.annotations.length <= j) ||\r
666                         (row.annotations[j] == null))\r
667                 {\r
668                     validRes = false;\r
669                 }\r
670                 else\r
671                 {\r
672                     validRes = true;\r
673                 }\r
674 \r
675                 x = (j - startRes) * av.charWidth;\r
676 \r
677                 if (activeRow == i)\r
678                 {\r
679                     g.setColor(Color.red);\r
680 \r
681                     if (activeRes != null)\r
682                     {\r
683                         for (int n = 0; n < activeRes.size(); n++)\r
684                         {\r
685                             int v = Integer.parseInt(activeRes.get(n).toString());\r
686 \r
687                             if (v == j)\r
688                             {\r
689                                 g.fillRect((j - startRes) * av.charWidth, y,\r
690                                     av.charWidth, row.height);\r
691                             }\r
692                         }\r
693                     }\r
694                 }\r
695 \r
696                 if (validRes &&\r
697                         (row.annotations[j].displayCharacter.length() > 0))\r
698                 {\r
699 \r
700                     int charOffset = (av.charWidth -\r
701                         fm.charWidth(row.annotations[j].displayCharacter.charAt(\r
702                                 0))) / 2;\r
703                     g.setColor(row.annotations[j].colour);\r
704 \r
705                     if (j == 0 || row.isGraph)\r
706                     {\r
707                         g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
708                             y + iconOffset + 3);\r
709                     }\r
710                     else if (((row.annotations[j - 1] == null) ||\r
711                             (row.annotations[j].displayCharacter != row.annotations[j -\r
712                             1].displayCharacter)))\r
713                     {\r
714                         g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
715                             y + iconOffset + 3);\r
716                     }\r
717                 }\r
718 \r
719                 if (row.hasIcons)\r
720                 {\r
721                     if (!validRes ||\r
722                             (row.annotations[j].secondaryStructure != lastSS[i]))\r
723                     {\r
724                         switch (lastSS[i])\r
725                         {\r
726                         case 'H':\r
727                             g.setColor(HELIX_COLOUR);\r
728                             g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
729                                 x - lastSSX[i], 7, 8, 8);\r
730 \r
731                             break;\r
732 \r
733                         case 'E':\r
734                             g.setColor(SHEET_COLOUR);\r
735                             g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
736                                 x - lastSSX[i] - 4, 7);\r
737                             g.fillPolygon(new int[] { x - 4, x - 4, x },\r
738                                 new int[]\r
739                                 {\r
740                                     y + iconOffset, y + 14 + iconOffset,\r
741                                     y + 8 + iconOffset\r
742                                 }, 3);\r
743 \r
744                             break;\r
745 \r
746                         case 'C':\r
747                             break;\r
748 \r
749                         default:\r
750                             g.setColor(Color.gray);\r
751                             g.fillRect(lastSSX[i], y + 6 + iconOffset,\r
752                                 x - lastSSX[i], 2);\r
753 \r
754                             break;\r
755                         }\r
756 \r
757                         if (validRes)\r
758                         {\r
759                             lastSS[i] = row.annotations[j].secondaryStructure;\r
760                         }\r
761                         else\r
762                         {\r
763                             lastSS[i] = ' ';\r
764                         }\r
765 \r
766                         lastSSX[i] = x;\r
767                     }\r
768                 }\r
769 \r
770                 if (validRes && row.isGraph)\r
771                 {\r
772                     g.setColor(new Color(0, 0, 180));\r
773 \r
774                     int height = (int) ((row.annotations[j].value / row.graphMax) * GRAPH_HEIGHT);\r
775 \r
776                     if (row.windowLength > 1)\r
777                     {\r
778                         int total = 0;\r
779 \r
780                         for (int i2 = j - (row.windowLength / 2);\r
781                                 i2 < (j + (row.windowLength / 2)); i2++)\r
782                         {\r
783                             if ((i2 < 0) || (i2 >= av.alignment.getWidth()))\r
784                             {\r
785                                 continue;\r
786                             }\r
787 \r
788                             total += row.annotations[i2].value;\r
789                         }\r
790 \r
791                         total /= row.windowLength;\r
792                         height = (int) ((total / row.graphMax) * GRAPH_HEIGHT);\r
793                     }\r
794 \r
795                     g.setColor(row.annotations[j].colour);\r
796                     g.fillRect(x, y - height, av.charWidth, height);\r
797                 }\r
798             }\r
799 \r
800             x += av.charWidth;\r
801 \r
802             if (row.hasIcons)\r
803             {\r
804                 switch (lastSS[i])\r
805                 {\r
806                 case 'H':\r
807                     g.setColor(HELIX_COLOUR);\r
808                     g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
809                         x - lastSSX[i], 7, 8, 8);\r
810 \r
811                     break;\r
812 \r
813                 case 'E':\r
814                     g.setColor(SHEET_COLOUR);\r
815                     g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
816                         x - lastSSX[i] - 4, 7);\r
817                     g.fillPolygon(new int[] { x - 4, x - 4, x },\r
818                         new int[]\r
819                         {\r
820                             y + iconOffset, y + 14 + iconOffset,\r
821                             y + 7 + iconOffset\r
822                         }, 3);\r
823 \r
824                     break;\r
825 \r
826                 case 'C':\r
827                     break;\r
828 \r
829                 default:\r
830                     g.setColor(Color.gray);\r
831                     g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
832 \r
833                     break;\r
834                 }\r
835             }\r
836 \r
837             if (row.isGraph && row.hasText)\r
838             {\r
839                 y += av.charHeight;\r
840             }\r
841 \r
842             if (!row.isGraph)\r
843             {\r
844                 y += aa[i].height;\r
845             }\r
846         }\r
847     }\r
848 \r
849     // used by overview window\r
850     public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y)\r
851     {\r
852         g.setColor(Color.white);\r
853         g.fillRect(0, 0, width, y);\r
854         g.setColor(new Color(0, 0, 180));\r
855 \r
856         int x = 0;\r
857 \r
858         for (int j = 0; j < aa.annotations.length; j++)\r
859         {\r
860             g.setColor(new Color(0, 0, 180));\r
861 \r
862             int height = (int) ((aa.annotations[j].value / aa.graphMax) * GRAPH_HEIGHT);\r
863             g.fillRect(x, y - height, av.charWidth, height);\r
864             x += av.charWidth;\r
865         }\r
866     }\r
867 }\r