validCharWidth moved to viewport
[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 javax.swing.*;\r
28 \r
29 \r
30 /**\r
31  * DOCUMENT ME!\r
32  *\r
33  * @author $author$\r
34  * @version $Revision$\r
35  */\r
36 public class AnnotationPanel extends JPanel implements MouseListener,\r
37     MouseMotionListener, ActionListener, AdjustmentListener\r
38 {\r
39     final String HELIX = "Helix";\r
40     final String SHEET = "Sheet";\r
41     final String LABEL = "Label";\r
42     final String REMOVE = "Remove Annotation";\r
43     final String COLOUR = "Colour";\r
44     final Color HELIX_COLOUR = Color.red.darker();\r
45     final Color SHEET_COLOUR = Color.green.darker().darker();\r
46 \r
47     /** DOCUMENT ME!! */\r
48     AlignViewport av;\r
49     AlignmentPanel ap;\r
50     int activeRow = -1;\r
51     BufferedImage image;\r
52     Graphics2D gg;\r
53     FontMetrics fm;\r
54     int imgWidth = 0;\r
55     boolean fastPaint = false;\r
56 \r
57     //Used For mouse Dragging and resizing graphs\r
58     int graphStretch = -1;\r
59     int graphStretchY = -1;\r
60     int min; //used by mouseDragged to see if user\r
61     int max; //used by mouseDragged to see if user\r
62     boolean mouseDragging = false;\r
63 \r
64     /**\r
65      * Creates a new AnnotationPanel object.\r
66      *\r
67      * @param ap DOCUMENT ME!\r
68      */\r
69     public AnnotationPanel(AlignmentPanel ap)\r
70     {\r
71         ToolTipManager.sharedInstance().registerComponent(this);\r
72         ToolTipManager.sharedInstance().setInitialDelay(0);\r
73         ToolTipManager.sharedInstance().setDismissDelay(10000);\r
74         this.ap = ap;\r
75         av = ap.av;\r
76         this.setLayout(null);\r
77         addMouseListener(this);\r
78         addMouseMotionListener(this);\r
79         ap.annotationScroller.getVerticalScrollBar().addAdjustmentListener(this);\r
80     }\r
81 \r
82     public AnnotationPanel(AlignViewport av)\r
83     {\r
84       this.av = av;\r
85     }\r
86 \r
87 \r
88     /**\r
89      * DOCUMENT ME!\r
90      *\r
91      * @param evt DOCUMENT ME!\r
92      */\r
93     public void adjustmentValueChanged(AdjustmentEvent evt)\r
94     {\r
95         ap.alabels.setScrollOffset(-evt.getValue());\r
96     }\r
97 \r
98     /**\r
99      * DOCUMENT ME!\r
100      */\r
101     public int adjustPanelHeight()\r
102     {\r
103         // setHeight of panels\r
104         image = null;\r
105         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
106         int height = 0;\r
107 \r
108         if (aa != null)\r
109         {\r
110             for (int i = 0; i < aa.length; i++)\r
111             {\r
112                 if (!aa[i].visible)\r
113                 {\r
114                     continue;\r
115                 }\r
116 \r
117                 aa[i].height = 0;\r
118 \r
119                 if (aa[i].hasText)\r
120                 {\r
121                     aa[i].height += av.charHeight;\r
122                 }\r
123 \r
124                 if (aa[i].hasIcons)\r
125                 {\r
126                     aa[i].height += 16;\r
127                 }\r
128 \r
129                 if (aa[i].graph>0)\r
130                 {\r
131                     aa[i].height += aa[i].graphHeight;\r
132                 }\r
133 \r
134                 if (aa[i].height == 0)\r
135                 {\r
136                     aa[i].height = 20;\r
137                 }\r
138 \r
139                 height += aa[i].height;\r
140             }\r
141         }\r
142         else\r
143         {\r
144             height = 20;\r
145         }\r
146 \r
147         this.setPreferredSize(new Dimension(1, height));\r
148 \r
149         return height;\r
150     }\r
151 \r
152 \r
153 \r
154     /**\r
155      * DOCUMENT ME!\r
156      *\r
157      * @param evt DOCUMENT ME!\r
158      */\r
159     public void actionPerformed(ActionEvent evt)\r
160     {\r
161         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
162         Annotation[] anot = aa[activeRow].annotations;\r
163 \r
164         if (evt.getActionCommand().equals(REMOVE))\r
165         {\r
166             for (int i = 0; i < av.getColumnSelection().size(); i++)\r
167             {\r
168                 anot[av.getColumnSelection().columnAt(i)] = null;\r
169             }\r
170         }\r
171         else if (evt.getActionCommand().equals(LABEL))\r
172         {\r
173             String label = JOptionPane.showInputDialog(this, "Enter Label ",\r
174                     "Enter label", JOptionPane.QUESTION_MESSAGE);\r
175 \r
176             if (label == null)\r
177             {\r
178                 return;\r
179             }\r
180 \r
181             if ((label.length() > 0) && !aa[activeRow].hasText)\r
182             {\r
183                 aa[activeRow].hasText = true;\r
184             }\r
185 \r
186             for (int i = 0; i < av.getColumnSelection().size(); i++)\r
187             {\r
188                 int index = av.getColumnSelection().columnAt(i);\r
189 \r
190                 if (anot[index] == null)\r
191                 {\r
192                     anot[index] = new Annotation(label, "", ' ', 0);\r
193                 }\r
194 \r
195                 anot[index].displayCharacter = label;\r
196             }\r
197         }\r
198         else if (evt.getActionCommand().equals(COLOUR))\r
199         {\r
200             Color col = JColorChooser.showDialog(this,\r
201                     "Choose foreground colour", Color.black);\r
202 \r
203             for (int i = 0; i < av.getColumnSelection().size(); i++)\r
204             {\r
205                 int index = av.getColumnSelection().columnAt(i);\r
206 \r
207                 if (anot[index] == null)\r
208                 {\r
209                     anot[index] = new Annotation("", "", ' ', 0);\r
210                 }\r
211 \r
212                 anot[index].colour = col;\r
213             }\r
214         }\r
215         else // HELIX OR SHEET\r
216         {\r
217             char type = 0;\r
218             String symbol = "\u03B1";\r
219 \r
220             if (evt.getActionCommand().equals(HELIX))\r
221             {\r
222                 type = 'H';\r
223             }\r
224             else if (evt.getActionCommand().equals(SHEET))\r
225             {\r
226                 type = 'E';\r
227                 symbol = "\u03B2";\r
228             }\r
229 \r
230             if (!aa[activeRow].hasIcons)\r
231             {\r
232                 aa[activeRow].hasIcons = true;\r
233             }\r
234 \r
235             String label = JOptionPane.showInputDialog("Enter a label for the structure?",\r
236                     symbol);\r
237 \r
238             if (label == null)\r
239             {\r
240                 return;\r
241             }\r
242 \r
243             if ((label.length() > 0) && !aa[activeRow].hasText)\r
244             {\r
245                 aa[activeRow].hasText = true;\r
246             }\r
247 \r
248             for (int i = 0; i < av.getColumnSelection().size(); i++)\r
249             {\r
250                 int index = av.getColumnSelection().columnAt(i);\r
251 \r
252                 if (anot[index] == null)\r
253                 {\r
254                     anot[index] = new Annotation(label, "", type, 0);\r
255                 }\r
256 \r
257                 anot[index].secondaryStructure = type;\r
258                 anot[index].displayCharacter = label;\r
259             }\r
260         }\r
261 \r
262         adjustPanelHeight();\r
263         repaint();\r
264 \r
265         return;\r
266     }\r
267 \r
268     /**\r
269      * DOCUMENT ME!\r
270      *\r
271      * @param evt DOCUMENT ME!\r
272      */\r
273     public void mousePressed(MouseEvent evt)\r
274     {\r
275         int height = 0;\r
276         activeRow = -1;\r
277 \r
278         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
279         if(aa==null)\r
280           return;\r
281 \r
282         for (int i = 0; i < aa.length; i++)\r
283         {\r
284             if (aa[i].visible)\r
285             {\r
286               height += aa[i].height;\r
287             }\r
288 \r
289             if (evt.getY() < height)\r
290             {\r
291                 if (aa[i].editable)\r
292                 {\r
293                     activeRow = i;\r
294                 }\r
295                 else if(aa[i].graph>0)\r
296                 {\r
297                     //Stretch Graph\r
298                     graphStretch = i;\r
299                     graphStretchY = evt.getY();\r
300                 }\r
301 \r
302                 break;\r
303             }\r
304         }\r
305 \r
306         if (SwingUtilities.isRightMouseButton(evt))\r
307         {\r
308             if (av.getColumnSelection() == null)\r
309             {\r
310                 return;\r
311             }\r
312 \r
313             JPopupMenu pop = new JPopupMenu("Structure type");\r
314             JMenuItem item = new JMenuItem(HELIX);\r
315             item.addActionListener(this);\r
316             pop.add(item);\r
317             item = new JMenuItem(SHEET);\r
318             item.addActionListener(this);\r
319             pop.add(item);\r
320             item = new JMenuItem(LABEL);\r
321             item.addActionListener(this);\r
322             pop.add(item);\r
323             item = new JMenuItem(COLOUR);\r
324             item.addActionListener(this);\r
325             pop.add(item);\r
326             item = new JMenuItem(REMOVE);\r
327             item.addActionListener(this);\r
328             pop.add(item);\r
329             pop.show(this, evt.getX(), evt.getY());\r
330 \r
331             return;\r
332         }\r
333 \r
334         if (aa == null)\r
335         {\r
336             return;\r
337         }\r
338 \r
339         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
340 \r
341         min = res;\r
342         max = res;\r
343 \r
344         if (av.getColumnSelection().contains(res))\r
345           av.getColumnSelection().removeElement(res);\r
346         else\r
347         {\r
348             av.getColumnSelection().addElement(res);\r
349             SequenceGroup sg = new SequenceGroup();\r
350 \r
351             for (int i = 0; i < av.alignment.getSequences().size(); i++)\r
352             {\r
353                 sg.addSequence(av.alignment.getSequenceAt(i), false);\r
354             }\r
355 \r
356             sg.setStartRes(res);\r
357             sg.setEndRes(res);\r
358             av.setSelectionGroup(sg);\r
359         }\r
360 \r
361         ap.repaint();\r
362 \r
363     }\r
364 \r
365     /**\r
366      * DOCUMENT ME!\r
367      *\r
368      * @param evt DOCUMENT ME!\r
369      */\r
370     public void mouseReleased(MouseEvent evt)\r
371     {\r
372       graphStretch = -1;\r
373       graphStretchY = -1;\r
374       mouseDragging = false;\r
375     }\r
376 \r
377     /**\r
378      * DOCUMENT ME!\r
379      *\r
380      * @param evt DOCUMENT ME!\r
381      */\r
382     public void mouseEntered(MouseEvent evt)\r
383     {\r
384       if(mouseDragging)\r
385         ap.seqPanel.scrollCanvas(null);\r
386     }\r
387 \r
388     /**\r
389      * DOCUMENT ME!\r
390      *\r
391      * @param evt DOCUMENT ME!\r
392      */\r
393     public void mouseExited(MouseEvent evt)\r
394     {\r
395       if(mouseDragging)\r
396         ap.seqPanel.scrollCanvas(evt);\r
397     }\r
398 \r
399 \r
400     /**\r
401      * DOCUMENT ME!\r
402      *\r
403      * @param evt DOCUMENT ME!\r
404      */\r
405     public void mouseDragged(MouseEvent evt)\r
406     {\r
407       if(graphStretch>-1)\r
408       {\r
409         av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight += graphStretchY - evt.getY();\r
410         if(av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight <10)\r
411           av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight = 10;\r
412         graphStretchY = evt.getY();\r
413         adjustPanelHeight();\r
414         ap.repaint();\r
415       }\r
416       else\r
417       {\r
418         mouseDragging = true;\r
419 \r
420         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
421 \r
422         SequenceGroup sg = av.getSelectionGroup();\r
423 \r
424         if (res < min)\r
425         {\r
426             min = res;\r
427         }\r
428 \r
429         if (res > max)\r
430         {\r
431             max = res;\r
432         }\r
433 \r
434         if (sg != null)\r
435         {\r
436             if (!av.getColumnSelection().contains(res))\r
437             {\r
438                 av.getColumnSelection().addElement(res);\r
439             }\r
440 \r
441             if (res > sg.getStartRes())\r
442             {\r
443                 sg.setEndRes(res);\r
444             }\r
445             else if (res < sg.getStartRes())\r
446             {\r
447                 sg.setStartRes(res);\r
448             }\r
449 \r
450             for (int i = min; i <= max; i++)\r
451             {\r
452                 if ((i < sg.getStartRes()) || (i > sg.getEndRes()))\r
453                 {\r
454                     av.getColumnSelection().removeElement(i);\r
455                 }\r
456                 else\r
457                 {\r
458                     av.getColumnSelection().addElement(i);\r
459                 }\r
460             }\r
461 \r
462             ap.repaint();\r
463         }\r
464 \r
465       }\r
466     }\r
467 \r
468     /**\r
469      * DOCUMENT ME!\r
470      *\r
471      * @param evt DOCUMENT ME!\r
472      */\r
473     public void mouseMoved(MouseEvent evt)\r
474     {\r
475         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
476 \r
477         if (aa == null)\r
478         {\r
479             return;\r
480         }\r
481 \r
482         int row = -1;\r
483         int height = 0;\r
484 \r
485         for (int i = 0; i < aa.length; i++)\r
486         {\r
487             if (aa[i].visible)\r
488             {\r
489                 height += aa[i].height;\r
490             }\r
491 \r
492             if (evt.getY() < height)\r
493             {\r
494                 row = i;\r
495 \r
496                 break;\r
497             }\r
498         }\r
499 \r
500         int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();\r
501 \r
502         if(av.hasHiddenColumns)\r
503           res = av.getColumnSelection().adjustForHiddenColumns(res);\r
504 \r
505         if (row > -1 && res<aa[row].annotations.length)\r
506         {\r
507             if(aa[row].graphGroup>-1)\r
508             {\r
509               StringBuffer tip = new StringBuffer("<html>");\r
510               for (int gg = 0; gg < aa.length; gg++)\r
511               {\r
512                 if (aa[gg].graphGroup == aa[row].graphGroup && aa[gg].annotations[res]!=null)\r
513                   tip.append(aa[gg].label+" "+aa[gg].annotations[res].description+"<br>" );\r
514               }\r
515               if(tip.length()!=6)\r
516               {\r
517                 tip.setLength(tip.length() - 4);\r
518                 this.setToolTipText(tip.toString() + "</html>");\r
519               }\r
520             }\r
521             else if(aa[row].annotations[res] != null)\r
522               this.setToolTipText(aa[row].annotations[res].description);\r
523 \r
524             if(aa[row].annotations[res]!=null)\r
525             {\r
526               StringBuffer text = new StringBuffer("Sequence position " +\r
527                                                    (res + 1) + "  " +\r
528                                                    aa[row].annotations[res].description);\r
529 \r
530               ap.alignFrame.statusBar.setText(text.toString());\r
531             }\r
532         }\r
533     }\r
534 \r
535     /**\r
536      * DOCUMENT ME!\r
537      *\r
538      * @param evt DOCUMENT ME!\r
539      */\r
540     public void mouseClicked(MouseEvent evt)\r
541     {\r
542     }\r
543 \r
544     /**\r
545      * DOCUMENT ME!\r
546      *\r
547      * @param g DOCUMENT ME!\r
548      */\r
549     public void paintComponent(Graphics g)\r
550     {\r
551       g.setColor(Color.white);\r
552       g.fillRect(0, 0, getWidth(), getHeight());\r
553 \r
554       if(image!=null)\r
555       {if (fastPaint\r
556             || (getVisibleRect().width != g.getClipBounds().width)\r
557             || (getVisibleRect().height != g.getClipBounds().height))\r
558         {\r
559           g.drawImage(image, 0, 0, this);\r
560           fastPaint = false;\r
561           return;\r
562         }\r
563       }\r
564       imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
565 \r
566       if (image == null || imgWidth != image.getWidth()\r
567           || image.getHeight(this) != getHeight())\r
568       {\r
569         image = new BufferedImage(imgWidth, ap.annotationPanel.getHeight(),\r
570                                   BufferedImage.TYPE_INT_RGB);\r
571         gg = (Graphics2D) image.getGraphics();\r
572 \r
573         if(av.antiAlias)\r
574         gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
575                             RenderingHints.VALUE_ANTIALIAS_ON);\r
576 \r
577         gg.setFont(av.getFont());\r
578         fm = gg.getFontMetrics();\r
579       }\r
580 \r
581 \r
582       drawComponent(gg, av.startRes, av.endRes + 1);\r
583       g.drawImage(image, 0, 0, this);\r
584     }\r
585 \r
586     /**\r
587      * DOCUMENT ME!\r
588      *\r
589      * @param horizontal DOCUMENT ME!\r
590      */\r
591     public void fastPaint(int horizontal)\r
592     {\r
593         if ((horizontal == 0) || gg==null ||\r
594                 (av.alignment.getAlignmentAnnotation() == null) ||\r
595                 (av.alignment.getAlignmentAnnotation().length < 1))\r
596         {\r
597             repaint();\r
598             return;\r
599         }\r
600 \r
601         gg.copyArea(0, 0, imgWidth, getHeight(), -horizontal * av.charWidth, 0);\r
602 \r
603         int sr = av.startRes;\r
604         int er = av.endRes + 1;\r
605         int transX = 0;\r
606 \r
607         if (horizontal > 0) // scrollbar pulled right, image to the left\r
608         {\r
609             transX = (er - sr - horizontal) * av.charWidth;\r
610             sr = er - horizontal;\r
611         }\r
612         else if (horizontal < 0)\r
613         {\r
614             er = sr - horizontal;\r
615         }\r
616 \r
617         gg.translate(transX, 0);\r
618 \r
619         drawComponent(gg, sr, er);\r
620 \r
621         gg.translate(-transX, 0);\r
622 \r
623         fastPaint = true;\r
624 \r
625         repaint();\r
626 \r
627     }\r
628 \r
629     /**\r
630      * DOCUMENT ME!\r
631      *\r
632      * @param g DOCUMENT ME!\r
633      * @param startRes DOCUMENT ME!\r
634      * @param endRes DOCUMENT ME!\r
635      */\r
636     public void drawComponent(Graphics g, int startRes, int endRes)\r
637     {\r
638 \r
639 \r
640       g.setFont(av.getFont());\r
641 \r
642       if (fm == null)\r
643         fm = g.getFontMetrics();\r
644 \r
645 \r
646         g.setColor(Color.white);\r
647         g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getHeight());\r
648 \r
649         if ( (av.alignment.getAlignmentAnnotation() == null) ||\r
650                 (av.alignment.getAlignmentAnnotation().length < 1))\r
651         {\r
652             g.setColor(Color.white);\r
653             g.fillRect(0, 0, getWidth(), getHeight());\r
654             g.setColor(Color.black);\r
655             if(av.validCharWidth)\r
656               g.drawString("Alignment has no annotations", 20, 15);\r
657 \r
658             return;\r
659         }\r
660 \r
661         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
662 \r
663         int x = 0;\r
664         int y = 0;\r
665         char lastSS;\r
666         int lastSSX;\r
667         int iconOffset = av.charHeight / 2;\r
668         boolean validRes = false;\r
669 \r
670         boolean [] graphGroupDrawn = new boolean[aa.length];\r
671 \r
672 \r
673         //\u03B2 \u03B1\r
674         for (int i = 0; i < aa.length; i++)\r
675         {\r
676             AlignmentAnnotation row = aa[i];\r
677 \r
678             if (!row.visible)\r
679             {\r
680                 continue;\r
681             }\r
682 \r
683             lastSS = ' ';\r
684             lastSSX = 0;\r
685 \r
686 \r
687             if (row.graph>0)\r
688             {\r
689                 if(row.graphGroup>-1 && graphGroupDrawn[ row.graphGroup ] )\r
690                   continue;\r
691 \r
692                 // this is so that we draw the characters below the graph\r
693                 y += row.height;\r
694 \r
695                 if (row.hasText)\r
696                 {\r
697                     y -= av.charHeight;\r
698                 }\r
699             }\r
700 \r
701             if (row.hasText)\r
702             {\r
703                 iconOffset = av.charHeight / 2;\r
704             }\r
705             else\r
706             {\r
707                 iconOffset = 0;\r
708             }\r
709 \r
710             int column = startRes;\r
711 \r
712             while (column < endRes)\r
713             {\r
714               if (av.hasHiddenColumns)\r
715               {\r
716                 column = av.getColumnSelection().adjustForHiddenColumns(column);\r
717                 if (column > row.annotations.length-1)\r
718                 {\r
719                   break;\r
720                 }\r
721               }\r
722 \r
723                 if ((row.annotations.length <= column) ||\r
724                         (row.annotations[column] == null))\r
725                 {\r
726                     validRes = false;\r
727                 }\r
728                 else\r
729                 {\r
730                     validRes = true;\r
731                 }\r
732 \r
733                 x = (column - startRes) * av.charWidth;\r
734 \r
735                 if (activeRow == i)\r
736                 {\r
737                     g.setColor(Color.red);\r
738 \r
739                     if (av.getColumnSelection() != null)\r
740                     {\r
741                         for (int n = 0; n < av.getColumnSelection().size(); n++)\r
742                         {\r
743                             int v = av.getColumnSelection().columnAt(n);\r
744 \r
745                             if (v == column)\r
746                             {\r
747                                 g.fillRect((column - startRes) * av.charWidth, y,\r
748                                     av.charWidth, row.height);\r
749                             }\r
750                         }\r
751                     }\r
752                 }\r
753 \r
754                 if (av.validCharWidth && validRes &&\r
755                         (row.annotations[column].displayCharacter.length() > 0))\r
756                 {\r
757 \r
758                     int charOffset = (av.charWidth -\r
759                         fm.charWidth(row.annotations[column].displayCharacter.charAt(\r
760                                 0))) / 2;\r
761                     g.setColor(row.annotations[column].colour);\r
762 \r
763                     if (column == 0 || row.graph>0)\r
764                     {\r
765                         g.drawString(row.annotations[column].displayCharacter, x+charOffset,\r
766                             y + iconOffset + 3);\r
767                     }\r
768                     else if (\r
769                         row.annotations[column - 1] == null\r
770                         ||(!row.annotations[column].displayCharacter.equals(\r
771                             row.annotations[column - 1].displayCharacter)\r
772                         ||\r
773                   (row.annotations[column].displayCharacter.length() <2 &&\r
774                    row.annotations[column].secondaryStructure==' ')))\r
775                     {\r
776                         g.drawString(row.annotations[column].displayCharacter, x+charOffset,\r
777                             y + iconOffset + 3);\r
778                     }\r
779                 }\r
780 \r
781                 if (row.hasIcons)\r
782                 {\r
783                     if (!validRes ||\r
784                             (row.annotations[column].secondaryStructure != lastSS))\r
785                     {\r
786                         switch (lastSS)\r
787                         {\r
788                         case 'H':\r
789                             g.setColor(HELIX_COLOUR);\r
790                             int sCol = (lastSSX / av.charWidth) + startRes;\r
791                             int x1 = lastSSX;\r
792                             int x2 = x;\r
793 \r
794                            if(row.annotations[sCol-1]==null ||\r
795                               row.annotations[sCol-1].secondaryStructure!='H')\r
796                            {\r
797                              g.fillArc(lastSSX, y+4+iconOffset, av.charWidth, 8, 90,180) ;\r
798                              x1 += av.charWidth/2;\r
799                            }\r
800 \r
801                             if(row.annotations[column]==null ||\r
802                                row.annotations[column].secondaryStructure!='H')\r
803                             {\r
804                               g.fillArc(x-av.charWidth, y+4+iconOffset, av.charWidth, 8, 270,180);\r
805                               x2 -= av.charWidth/2;\r
806                             }\r
807 \r
808                             g.fillRect(x1, y+4+iconOffset, x2-x1, 8);\r
809                             break;\r
810 \r
811                         case 'E':\r
812                             g.setColor(SHEET_COLOUR);\r
813                             g.fillRect(lastSSX, y + 4 + iconOffset,\r
814                                 x - lastSSX - 4, 7);\r
815                             g.fillPolygon(new int[] { x - 4, x - 4, x },\r
816                                 new int[]\r
817                                 {\r
818                                     y + iconOffset, y + 14 + iconOffset,\r
819                                     y + 8 + iconOffset\r
820                                 }, 3);\r
821 \r
822                             break;\r
823 \r
824 \r
825                         default:\r
826                             g.setColor(Color.gray);\r
827                             g.fillRect(lastSSX, y + 6 + iconOffset,\r
828                                 x - lastSSX, 2);\r
829 \r
830                             break;\r
831                         }\r
832 \r
833                         if (validRes)\r
834                         {\r
835                             lastSS = row.annotations[column].secondaryStructure;\r
836                         }\r
837                         else\r
838                         {\r
839                             lastSS = ' ';\r
840                         }\r
841 \r
842                         lastSSX = x;\r
843                     }\r
844                 }\r
845 \r
846                 column++;\r
847             }\r
848 \r
849             x += av.charWidth;\r
850 \r
851             if (row.hasIcons)\r
852             {\r
853                 switch (lastSS)\r
854                 {\r
855                 case 'H':\r
856                   g.setColor(HELIX_COLOUR);\r
857 \r
858                   int sCol = (lastSSX / av.charWidth) + startRes;\r
859                   int x1 = lastSSX;\r
860                   int x2 = x;\r
861 \r
862                  if(row.annotations[sCol-1]==null ||\r
863                     row.annotations[sCol-1].secondaryStructure!='H')\r
864                  {\r
865                    g.fillArc(lastSSX, y+4+iconOffset, av.charWidth, 8, 90,180) ;\r
866                    x1 += av.charWidth/2;\r
867                  }\r
868 \r
869                   if(row.annotations[column]==null ||\r
870                      row.annotations[column].secondaryStructure!='H')\r
871                   {\r
872                     g.fillArc(x-av.charWidth, y+4+iconOffset, av.charWidth, 8, 270,180);\r
873                     x2 -= av.charWidth/2;\r
874                   }\r
875 \r
876                   g.fillRect(x1, y+4+iconOffset, x2-x1, 8);\r
877 \r
878                     break;\r
879 \r
880                 case 'E':\r
881                     g.setColor(SHEET_COLOUR);\r
882 \r
883                     if (row.annotations[endRes] !=null\r
884                         && row.annotations[endRes].secondaryStructure != 'E')\r
885                     {\r
886                       g.fillRect(lastSSX, y + 4 + iconOffset,\r
887                                  x - lastSSX - 4, 7);\r
888                       g.fillPolygon(new int[]\r
889                                     {x - 4, x - 4, x},\r
890                                     new int[]\r
891                                     {\r
892                                     y + iconOffset, y + 14 + iconOffset,\r
893                                     y + 7 + iconOffset\r
894                       }, 3);\r
895                     }\r
896                     else\r
897                       g.fillRect(lastSSX, y + 4 + iconOffset,\r
898                                  x - lastSSX, 7);\r
899 \r
900                     break;\r
901 \r
902 \r
903                 default:\r
904                     g.setColor(Color.ORANGE);\r
905                     if(!av.wrapAlignment || endRes==av.endRes)\r
906                       g.fillRect(lastSSX, y + 6 + iconOffset, x - lastSSX, 2);\r
907 \r
908                     break;\r
909                 }\r
910             }\r
911 \r
912             if (row.graph>0)\r
913             {\r
914                 if(row.graph == AlignmentAnnotation.LINE_GRAPH )\r
915                 {\r
916                   if(row.graphGroup>-1 && !graphGroupDrawn[row.graphGroup])\r
917                    {\r
918                      float groupmax=-999999, groupmin=9999999;\r
919                      for(int gg=0; gg<aa.length; gg++)\r
920                      {\r
921                        if(aa[gg].graphGroup!=row.graphGroup)\r
922                          continue;\r
923 \r
924                        if(aa[gg]!=row)\r
925                          aa[gg].visible = false;\r
926 \r
927                        if(aa[gg].graphMax>groupmax)\r
928                          groupmax = aa[gg].graphMax;\r
929                        if(aa[gg].graphMin<groupmin)\r
930                          groupmin = aa[gg].graphMin;\r
931                      }\r
932 \r
933                      for (int gg = 0; gg < aa.length; gg++)\r
934                      {\r
935                        if (aa[gg].graphGroup == row.graphGroup)\r
936                        {\r
937                          drawLineGraph(g, aa[gg], startRes, endRes, y,\r
938                                        groupmin, groupmax,\r
939                                        row.graphHeight);\r
940                        }\r
941                      }\r
942 \r
943                      graphGroupDrawn[ row.graphGroup ] = true;\r
944                    }\r
945                    else\r
946                      drawLineGraph(g, row, startRes, endRes,\r
947                                    y, row.graphMin, row.graphMax, row.graphHeight  );\r
948                 }\r
949                 else if(row.graph == AlignmentAnnotation.BAR_GRAPH )\r
950                    drawBarGraph(g, row, startRes, endRes,\r
951                                 row.graphMin, row.graphMax, y);\r
952             }\r
953 \r
954             if (row.graph>0 && row.hasText)\r
955             {\r
956                 y += av.charHeight;\r
957             }\r
958 \r
959             if (row.graph==0)\r
960             {\r
961                 y += aa[i].height;\r
962             }\r
963         }\r
964     }\r
965 \r
966     public void drawLineGraph(Graphics g, AlignmentAnnotation aa,\r
967                               int sRes, int eRes,\r
968                               int y,\r
969                               float min, float max,\r
970                               int graphHeight)\r
971     {\r
972       if(sRes>aa.annotations.length)\r
973         return;\r
974 \r
975       eRes = Math.min(eRes, aa.annotations.length);\r
976 \r
977       int x = 0;\r
978 \r
979       //Adjustment for fastpaint to left\r
980       if(eRes<av.endRes)\r
981         eRes++;\r
982 \r
983       if(sRes==0)\r
984       {\r
985         sRes++;\r
986         x+=av.charWidth;\r
987       }\r
988 \r
989       int y1=y, y2=y;\r
990       float range = max - min;\r
991 \r
992       ////Draw origin\r
993       if(min<0)\r
994         y2 = (int)(y - (0-min / range)*graphHeight);\r
995 \r
996       g.setColor(Color.gray);\r
997       g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
998 \r
999       eRes = Math.min(eRes, aa.annotations.length);\r
1000 \r
1001       int column = sRes;\r
1002       int aaMax = aa.annotations.length-1;\r
1003 \r
1004       while( column < eRes )\r
1005       {\r
1006         if(av.hasHiddenColumns)\r
1007         {\r
1008           column = av.getColumnSelection().adjustForHiddenColumns(column);\r
1009           if(column > aaMax)\r
1010           {\r
1011             break;\r
1012           }\r
1013         }\r
1014 \r
1015         if(aa.annotations[column]==null || aa.annotations[column-1]==null)\r
1016         {\r
1017           x+=av.charWidth;\r
1018           column ++;\r
1019           continue;\r
1020         }\r
1021 \r
1022           g.setColor(aa.annotations[column].colour);\r
1023           y1 = y - (int) (((aa.annotations[column-1].value-min) / range) * graphHeight);\r
1024           y2 = y - (int) (((aa.annotations[column].value-min) / range) * graphHeight);\r
1025           g.drawLine(x-av.charWidth/2, y1, x+av.charWidth/2, y2);\r
1026           x += av.charWidth;\r
1027 \r
1028           column++;\r
1029 \r
1030        }\r
1031        if(aa.threshold!=null)\r
1032        {\r
1033            g.setColor(aa.threshold.colour);\r
1034            Graphics2D g2 = (Graphics2D)g;\r
1035            g2.setStroke(new BasicStroke(1,\r
1036                                          BasicStroke.CAP_SQUARE,\r
1037                                          BasicStroke.JOIN_ROUND, 3f,\r
1038                                          new float[] { 5f, 3f }, 0f));\r
1039 \r
1040            y2 = (int)(y - ((aa.threshold.value-min) / range)*graphHeight);\r
1041            g.drawLine(0,y2,(eRes-sRes)*av.charWidth,y2);\r
1042            g2.setStroke(new BasicStroke());\r
1043       }\r
1044     }\r
1045 \r
1046     public void drawBarGraph(Graphics g, AlignmentAnnotation aa,\r
1047                              int sRes, int eRes,\r
1048                              float min, float max,\r
1049                              int y)\r
1050     {\r
1051       if(sRes>aa.annotations.length)\r
1052         return;\r
1053 \r
1054       eRes = Math.min(eRes, aa.annotations.length);\r
1055 \r
1056       int x=0, y1, y2;\r
1057 \r
1058       float range = max - min;\r
1059 \r
1060       y1 = y2 = y;\r
1061 \r
1062       if(min<0)\r
1063         y2 = (int)(y - (0-min / (range))*aa.graphHeight);\r
1064 \r
1065       g.setColor(Color.gray);\r
1066 \r
1067       g.drawLine(x,y2,(eRes-sRes)*av.charWidth,y2);\r
1068 \r
1069 \r
1070       int column = sRes;\r
1071       int aaMax = aa.annotations.length-1;\r
1072 \r
1073       while( column < eRes )\r
1074       {\r
1075         if(av.hasHiddenColumns)\r
1076         {\r
1077           column = av.getColumnSelection().adjustForHiddenColumns(column);\r
1078           if(column > aaMax)\r
1079           {\r
1080             break;\r
1081           }\r
1082         }\r
1083 \r
1084         if (aa.annotations[column] == null)\r
1085         {\r
1086           x += av.charWidth;\r
1087           column ++;\r
1088           continue;\r
1089         }\r
1090 \r
1091           g.setColor(aa.annotations[column].colour);\r
1092           y1 = y - (int) (((aa.annotations[column].value-min) / (range)) * aa.graphHeight);\r
1093 \r
1094           if(y1-y2>0)\r
1095             g.fillRect(x, y2, av.charWidth, y1-y2 );\r
1096           else\r
1097             g.fillRect(x, y1, av.charWidth, y2-y1 );\r
1098 \r
1099           x += av.charWidth;\r
1100           column ++;\r
1101 \r
1102       }\r
1103       if(aa.threshold!=null)\r
1104       {\r
1105           g.setColor(aa.threshold.colour);\r
1106           Graphics2D g2 = (Graphics2D)g;\r
1107           g2.setStroke(new BasicStroke(1,\r
1108                                         BasicStroke.CAP_SQUARE,\r
1109                                         BasicStroke.JOIN_ROUND, 3f,\r
1110                                         new float[] { 5f, 3f }, 0f));\r
1111 \r
1112           y2 = (int)(y - ((aa.threshold.value-min) / range)*aa.graphHeight);\r
1113           g.drawLine(0,y2,(eRes-sRes)*av.charWidth,y2);\r
1114           g2.setStroke(new BasicStroke());\r
1115       }\r
1116     }\r
1117 \r
1118     // used by overview window\r
1119     public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y, int sRes, int eRes)\r
1120     {\r
1121       g.setColor(Color.white);\r
1122       g.fillRect(0, 0, width, y);\r
1123       g.setColor(new Color(0, 0, 180));\r
1124 \r
1125       int x = 0, height;\r
1126 \r
1127       for (int j = sRes; j < eRes; j++)\r
1128       {\r
1129           g.setColor(aa.annotations[j].colour);\r
1130 \r
1131           height = (int) ((aa.annotations[j].value / aa.graphMax) * y);\r
1132           if(height>y)\r
1133             height = y;\r
1134 \r
1135           g.fillRect(x, y - height, av.charWidth, height);\r
1136           x += av.charWidth;\r
1137       }\r
1138     }\r
1139 \r
1140 }\r