added help and documentation for annotation editing.
[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 \r
530             return;\r
531         }\r
532 \r
533         imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
534 \r
535         image = new BufferedImage(imgWidth, ap.annotationPanel.getHeight(),\r
536                 BufferedImage.TYPE_INT_RGB);\r
537         gg = (Graphics2D) image.getGraphics();\r
538         gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
539             RenderingHints.VALUE_ANTIALIAS_ON);\r
540 \r
541         gg.setFont(av.getFont());\r
542 \r
543         drawComponent(gg, av.startRes, av.endRes + 1);\r
544         g.drawImage(image, 0, 0, this);\r
545     }\r
546 \r
547     /**\r
548      * DOCUMENT ME!\r
549      *\r
550      * @param horizontal DOCUMENT ME!\r
551      */\r
552     public void fastPaint(int horizontal)\r
553     {\r
554         if ((horizontal == 0) ||\r
555                 (av.alignment.getAlignmentAnnotation() == null) ||\r
556                 (av.alignment.getAlignmentAnnotation().length < 1))\r
557         {\r
558             repaint();\r
559 \r
560             return;\r
561         }\r
562 \r
563         gg.copyArea(0, 0, imgWidth, getHeight(), -horizontal * av.charWidth, 0);\r
564 \r
565         int sr = av.startRes;\r
566         int er = av.endRes + 1;\r
567         int transX = 0;\r
568 \r
569         if (horizontal > 0) // scrollbar pulled right, image to the left\r
570         {\r
571             transX = (er - sr - horizontal) * av.charWidth;\r
572             sr = er - horizontal;\r
573         }\r
574         else if (horizontal < 0)\r
575         {\r
576             er = sr - horizontal;\r
577         }\r
578 \r
579         gg.translate(transX, 0);\r
580 \r
581         drawComponent(gg, sr, er);\r
582 \r
583         gg.translate(-transX, 0);\r
584 \r
585         fastPaint = true;\r
586         repaint();\r
587     }\r
588 \r
589     /**\r
590      * DOCUMENT ME!\r
591      *\r
592      * @param g DOCUMENT ME!\r
593      * @param startRes DOCUMENT ME!\r
594      * @param endRes DOCUMENT ME!\r
595      */\r
596     public void drawComponent(Graphics2D g, int startRes, int endRes)\r
597     {\r
598       if(fm==null)\r
599         fm = g.getFontMetrics();\r
600 \r
601         g.setColor(Color.white);\r
602         g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getHeight());\r
603 \r
604         if ((av.alignment.getAlignmentAnnotation() == null) ||\r
605                 (av.alignment.getAlignmentAnnotation().length < 1))\r
606         {\r
607             g.setColor(Color.white);\r
608             g.fillRect(0, 0, getWidth(), getHeight());\r
609             g.setColor(Color.black);\r
610             g.drawString("Alignment has no annotations", 20, 15);\r
611 \r
612             return;\r
613         }\r
614 \r
615         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
616 \r
617         int j;\r
618         int x = 0;\r
619         int y = 0;\r
620         char[] lastSS = new char[aa.length];\r
621         int[] lastSSX = new int[aa.length];\r
622         int iconOffset = av.charHeight / 2;\r
623         boolean validRes = false;\r
624 \r
625         //\u03B2 \u03B1\r
626         for (int i = 0; i < aa.length; i++)\r
627         {\r
628             AlignmentAnnotation row = aa[i];\r
629 \r
630             if (!row.visible)\r
631             {\r
632                 continue;\r
633             }\r
634 \r
635             if (row.isGraph)\r
636             {\r
637                 // this is so that we draw the characters below the graph\r
638                 y += row.height;\r
639 \r
640                 if (row.hasText)\r
641                 {\r
642                     y -= av.charHeight;\r
643                 }\r
644             }\r
645 \r
646             if (row.hasText)\r
647             {\r
648                 iconOffset = av.charHeight / 2;\r
649             }\r
650             else\r
651             {\r
652                 iconOffset = 0;\r
653             }\r
654 \r
655             for (j = startRes; j < endRes; j++)\r
656             {\r
657                 if ((row.annotations.length <= j) ||\r
658                         (row.annotations[j] == null))\r
659                 {\r
660                     validRes = false;\r
661                 }\r
662                 else\r
663                 {\r
664                     validRes = true;\r
665                 }\r
666 \r
667                 x = (j - startRes) * av.charWidth;\r
668 \r
669                 if (activeRow == i)\r
670                 {\r
671                     g.setColor(Color.red);\r
672 \r
673                     if (activeRes != null)\r
674                     {\r
675                         for (int n = 0; n < activeRes.size(); n++)\r
676                         {\r
677                             int v = Integer.parseInt(activeRes.get(n).toString());\r
678 \r
679                             if (v == j)\r
680                             {\r
681                                 g.fillRect((j - startRes) * av.charWidth, y,\r
682                                     av.charWidth, row.height);\r
683                             }\r
684                         }\r
685                     }\r
686                 }\r
687 \r
688                 if (validRes &&\r
689                         (row.annotations[j].displayCharacter.length() > 0))\r
690                 {\r
691                     int charOffset = (av.charWidth -\r
692                         fm.charWidth(row.annotations[j].displayCharacter.charAt(\r
693                                 0))) / 2;\r
694                     g.setColor(row.annotations[j].colour);\r
695 \r
696                     if (j == 0)\r
697                     {\r
698                         g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
699                             y + iconOffset + 2);\r
700                     }\r
701                     else if (((row.annotations[j - 1] == null) ||\r
702                             (row.annotations[j].displayCharacter != row.annotations[j -\r
703                             1].displayCharacter)))\r
704                     {\r
705                         g.drawString(row.annotations[j].displayCharacter, x+charOffset,\r
706                             y + iconOffset + 2);\r
707                     }\r
708                 }\r
709 \r
710                 if (row.hasIcons)\r
711                 {\r
712                     if (!validRes ||\r
713                             (row.annotations[j].secondaryStructure != lastSS[i]))\r
714                     {\r
715                         switch (lastSS[i])\r
716                         {\r
717                         case 'H':\r
718                             g.setColor(HELIX_COLOUR);\r
719                             g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
720                                 x - lastSSX[i], 7, 8, 8);\r
721 \r
722                             break;\r
723 \r
724                         case 'E':\r
725                             g.setColor(SHEET_COLOUR);\r
726                             g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
727                                 x - lastSSX[i] - 4, 7);\r
728                             g.fillPolygon(new int[] { x - 4, x - 4, x },\r
729                                 new int[]\r
730                                 {\r
731                                     y + iconOffset, y + 14 + iconOffset,\r
732                                     y + 8 + iconOffset\r
733                                 }, 3);\r
734 \r
735                             break;\r
736 \r
737                         case 'C':\r
738                             break;\r
739 \r
740                         default:\r
741                             g.setColor(Color.gray);\r
742                             g.fillRect(lastSSX[i], y + 6 + iconOffset,\r
743                                 x - lastSSX[i], 2);\r
744 \r
745                             break;\r
746                         }\r
747 \r
748                         if (validRes)\r
749                         {\r
750                             lastSS[i] = row.annotations[j].secondaryStructure;\r
751                         }\r
752                         else\r
753                         {\r
754                             lastSS[i] = ' ';\r
755                         }\r
756 \r
757                         lastSSX[i] = x;\r
758                     }\r
759                 }\r
760 \r
761                 if (validRes && row.isGraph)\r
762                 {\r
763                     g.setColor(new Color(0, 0, 180));\r
764 \r
765                     int height = (int) ((row.annotations[j].value / row.graphMax) * GRAPH_HEIGHT);\r
766 \r
767                     if (row.windowLength > 1)\r
768                     {\r
769                         int total = 0;\r
770 \r
771                         for (int i2 = j - (row.windowLength / 2);\r
772                                 i2 < (j + (row.windowLength / 2)); i2++)\r
773                         {\r
774                             if ((i2 < 0) || (i2 >= av.alignment.getWidth()))\r
775                             {\r
776                                 continue;\r
777                             }\r
778 \r
779                             total += row.annotations[i2].value;\r
780                         }\r
781 \r
782                         total /= row.windowLength;\r
783                         height = (int) ((total / row.graphMax) * GRAPH_HEIGHT);\r
784                     }\r
785 \r
786                     g.setColor(row.annotations[j].colour);\r
787                     g.fillRect(x, y - height, av.charWidth, height);\r
788                 }\r
789             }\r
790 \r
791             x += av.charWidth;\r
792 \r
793             if (row.hasIcons)\r
794             {\r
795                 switch (lastSS[i])\r
796                 {\r
797                 case 'H':\r
798                     g.setColor(HELIX_COLOUR);\r
799                     g.fillRoundRect(lastSSX[i], y + 4 + iconOffset,\r
800                         x - lastSSX[i], 7, 8, 8);\r
801 \r
802                     break;\r
803 \r
804                 case 'E':\r
805                     g.setColor(SHEET_COLOUR);\r
806                     g.fillRect(lastSSX[i], y + 4 + iconOffset,\r
807                         x - lastSSX[i] - 4, 7);\r
808                     g.fillPolygon(new int[] { x - 4, x - 4, x },\r
809                         new int[]\r
810                         {\r
811                             y + iconOffset, y + 14 + iconOffset,\r
812                             y + 7 + iconOffset\r
813                         }, 3);\r
814 \r
815                     break;\r
816 \r
817                 case 'C':\r
818                     break;\r
819 \r
820                 default:\r
821                     g.setColor(Color.gray);\r
822                     g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
823 \r
824                     break;\r
825                 }\r
826             }\r
827 \r
828             if (row.isGraph && row.hasText)\r
829             {\r
830                 y += av.charHeight;\r
831             }\r
832 \r
833             if (!row.isGraph)\r
834             {\r
835                 y += aa[i].height;\r
836             }\r
837         }\r
838     }\r
839 \r
840     // used by overview window\r
841     public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y)\r
842     {\r
843         g.setColor(Color.white);\r
844         g.fillRect(0, 0, width, y);\r
845         g.setColor(new Color(0, 0, 180));\r
846 \r
847         int x = 0;\r
848 \r
849         for (int j = 0; j < aa.annotations.length; j++)\r
850         {\r
851             g.setColor(new Color(0, 0, 180));\r
852 \r
853             int height = (int) ((aa.annotations[j].value / aa.graphMax) * GRAPH_HEIGHT);\r
854             g.fillRect(x, y - height, av.charWidth, height);\r
855             x += av.charWidth;\r
856         }\r
857     }\r
858 }\r