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