Scrolls if dragged off the screen
[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       g.setFont(av.getFont());\r
639 \r
640       if (fm == null)\r
641         fm = g.getFontMetrics();\r
642 \r
643 \r
644         g.setColor(Color.white);\r
645         g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getHeight());\r
646 \r
647         if ((av.alignment.getAlignmentAnnotation() == null) ||\r
648                 (av.alignment.getAlignmentAnnotation().length < 1))\r
649         {\r
650             g.setColor(Color.white);\r
651             g.fillRect(0, 0, getWidth(), getHeight());\r
652             g.setColor(Color.black);\r
653             g.drawString("Alignment has no annotations", 20, 15);\r
654 \r
655             return;\r
656         }\r
657 \r
658         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
659 \r
660         int x = 0;\r
661         int y = 0;\r
662         char lastSS;\r
663         int lastSSX;\r
664         int iconOffset = av.charHeight / 2;\r
665         boolean validRes = false;\r
666 \r
667         boolean [] graphGroupDrawn = new boolean[aa.length];\r
668 \r
669 \r
670         //\u03B2 \u03B1\r
671         for (int i = 0; i < aa.length; i++)\r
672         {\r
673             AlignmentAnnotation row = aa[i];\r
674 \r
675             if (!row.visible)\r
676             {\r
677                 continue;\r
678             }\r
679 \r
680             lastSS = ' ';\r
681             lastSSX = 0;\r
682 \r
683 \r
684             if (row.graph>0)\r
685             {\r
686                 if(row.graphGroup>-1 && graphGroupDrawn[ row.graphGroup ] )\r
687                   continue;\r
688 \r
689                 // this is so that we draw the characters below the graph\r
690                 y += row.height;\r
691 \r
692                 if (row.hasText)\r
693                 {\r
694                     y -= av.charHeight;\r
695                 }\r
696             }\r
697 \r
698             if (row.hasText)\r
699             {\r
700                 iconOffset = av.charHeight / 2;\r
701             }\r
702             else\r
703             {\r
704                 iconOffset = 0;\r
705             }\r
706 \r
707             int column = startRes;\r
708             int yPos = startRes;\r
709 \r
710             while (yPos < endRes)\r
711             {\r
712               if (av.hasHiddenColumns)\r
713               {\r
714                 column = av.getColumnSelection().adjustForHiddenColumns(yPos);\r
715                 if (column > row.annotations.length-1)\r
716                 {\r
717                   break;\r
718                 }\r
719               }\r
720               else\r
721                 column = yPos;\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 = (yPos - 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 (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 (((row.annotations[column - 1] == null)\r
769                               ||\r
770                             (!row.annotations[column].displayCharacter.equals(\r
771                              row.annotations[column - 1].displayCharacter))))\r
772                     {\r
773                         g.drawString(row.annotations[column].displayCharacter, x+charOffset,\r
774                             y + iconOffset + 3);\r
775                     }\r
776                 }\r
777 \r
778                 if (row.hasIcons)\r
779                 {\r
780                     if (!validRes ||\r
781                             (row.annotations[column].secondaryStructure != lastSS))\r
782                     {\r
783                         switch (lastSS)\r
784                         {\r
785                         case 'H':\r
786                             g.setColor(HELIX_COLOUR);\r
787                             g.fillRoundRect(lastSSX, y + 4 + iconOffset,\r
788                                 x - lastSSX, 7, 8, 8);\r
789 \r
790                             break;\r
791 \r
792                         case 'E':\r
793                             g.setColor(SHEET_COLOUR);\r
794                             g.fillRect(lastSSX, y + 4 + iconOffset,\r
795                                 x - lastSSX - 4, 7);\r
796                             g.fillPolygon(new int[] { x - 4, x - 4, x },\r
797                                 new int[]\r
798                                 {\r
799                                     y + iconOffset, y + 14 + iconOffset,\r
800                                     y + 8 + iconOffset\r
801                                 }, 3);\r
802 \r
803                             break;\r
804 \r
805 \r
806                         default:\r
807                             g.setColor(Color.gray);\r
808                             g.fillRect(lastSSX, y + 6 + iconOffset,\r
809                                 x - lastSSX, 2);\r
810 \r
811                             break;\r
812                         }\r
813 \r
814                         if (validRes)\r
815                         {\r
816                             lastSS = row.annotations[column].secondaryStructure;\r
817                         }\r
818                         else\r
819                         {\r
820                             lastSS = ' ';\r
821                         }\r
822 \r
823                         lastSSX = x;\r
824                     }\r
825                 }\r
826 \r
827                 yPos++;\r
828             }\r
829 \r
830             x += av.charWidth;\r
831 \r
832             if (row.hasIcons)\r
833             {\r
834                 switch (lastSS)\r
835                 {\r
836                 case 'H':\r
837                     g.setColor(HELIX_COLOUR);\r
838                     g.fillRoundRect(lastSSX, y + 4 + iconOffset,\r
839                         x - lastSSX, 7, 8, 8);\r
840 \r
841                     break;\r
842 \r
843                 case 'E':\r
844                     g.setColor(SHEET_COLOUR);\r
845 \r
846                     if (row.annotations[endRes] !=null\r
847                         && row.annotations[endRes].secondaryStructure != 'E')\r
848                     {\r
849                       g.fillRect(lastSSX, y + 4 + iconOffset,\r
850                                  x - lastSSX - 4, 7);\r
851                       g.fillPolygon(new int[]\r
852                                     {x - 4, x - 4, x},\r
853                                     new int[]\r
854                                     {\r
855                                     y + iconOffset, y + 14 + iconOffset,\r
856                                     y + 7 + iconOffset\r
857                       }, 3);\r
858                     }\r
859                     else\r
860                       g.fillRect(lastSSX, y + 4 + iconOffset,\r
861                                  x - lastSSX, 7);\r
862 \r
863                     break;\r
864 \r
865 \r
866                 default:\r
867                     g.setColor(Color.gray);\r
868                     g.fillRect(lastSSX, y + 6 + iconOffset, x - lastSSX, 2);\r
869 \r
870                     break;\r
871                 }\r
872             }\r
873 \r
874             if (row.graph>0)\r
875             {\r
876                 if(row.graph == AlignmentAnnotation.LINE_GRAPH )\r
877                 {\r
878                   if(row.graphGroup>-1 && !graphGroupDrawn[row.graphGroup])\r
879                    {\r
880                      float groupmax=-999999, groupmin=9999999;\r
881                      for(int gg=0; gg<aa.length; gg++)\r
882                      {\r
883                        if(aa[gg].graphGroup!=row.graphGroup)\r
884                          continue;\r
885 \r
886                        if(aa[gg]!=row)\r
887                          aa[gg].visible = false;\r
888 \r
889                        if(aa[gg].graphMax>groupmax)\r
890                          groupmax = aa[gg].graphMax;\r
891                        if(aa[gg].graphMin<groupmin)\r
892                          groupmin = aa[gg].graphMin;\r
893                      }\r
894 \r
895                      for (int gg = 0; gg < aa.length; gg++)\r
896                      {\r
897                        if (aa[gg].graphGroup == row.graphGroup)\r
898                        {\r
899                          drawLineGraph(g, aa[gg], startRes, endRes, y,\r
900                                        groupmin, groupmax,\r
901                                        row.graphHeight);\r
902                        }\r
903                      }\r
904 \r
905                      graphGroupDrawn[ row.graphGroup ] = true;\r
906                    }\r
907                    else\r
908                      drawLineGraph(g, row, startRes, endRes,\r
909                                    y, row.graphMin, row.graphMax, row.graphHeight  );\r
910                 }\r
911                 else if(row.graph == AlignmentAnnotation.BAR_GRAPH )\r
912                    drawBarGraph(g, row, startRes, endRes,\r
913                                 row.graphMin, row.graphMax, y);\r
914             }\r
915 \r
916             if (row.graph>0 && row.hasText)\r
917             {\r
918                 y += av.charHeight;\r
919             }\r
920 \r
921             if (row.graph==0)\r
922             {\r
923                 y += aa[i].height;\r
924             }\r
925         }\r
926     }\r
927 \r
928     public void drawLineGraph(Graphics g, AlignmentAnnotation aa,\r
929                               int sRes, int eRes,\r
930                               int y,\r
931                               float min, float max,\r
932                               int graphHeight)\r
933     {\r
934       if(sRes>aa.annotations.length)\r
935         return;\r
936 \r
937       eRes = Math.min(eRes, aa.annotations.length);\r
938 \r
939       int x = 0;\r
940 \r
941       //Adjustment for fastpaint to left\r
942       if(eRes<av.endRes)\r
943         eRes++;\r
944 \r
945       if(sRes==0)\r
946       {\r
947         sRes++;\r
948         x+=av.charWidth;\r
949       }\r
950 \r
951       int y1=y, y2=y;\r
952       float range = max - min;\r
953 \r
954       ////Draw origin\r
955       if(min<0)\r
956         y2 = (int)(y - (0-min / range)*graphHeight);\r
957 \r
958       g.setColor(Color.gray);\r
959       g.drawLine(x-av.charWidth,y2,(eRes-sRes+1)*av.charWidth,y2);\r
960 \r
961 \r
962       if(aa.threshold!=null)\r
963       {\r
964           g.setColor(aa.threshold.colour);\r
965           Graphics2D g2 = (Graphics2D)g;\r
966           g2.setStroke(new BasicStroke(1,\r
967                                         BasicStroke.CAP_SQUARE,\r
968                                         BasicStroke.JOIN_ROUND, 3f,\r
969                                         new float[] { 5f, 3f }, 0f));\r
970 \r
971           y2 = (int)(y - ((aa.threshold.value-min) / range)*graphHeight);\r
972           g.drawLine(x-av.charWidth,y2,(eRes-sRes)*av.charWidth,y2);\r
973           g2.setStroke(new BasicStroke());\r
974       }\r
975 \r
976       eRes = Math.min(eRes, aa.annotations.length);\r
977 \r
978       int column = sRes;\r
979       int yPos = sRes;\r
980       int aaMax = aa.annotations.length-1;\r
981 \r
982       while( yPos < eRes )\r
983       {\r
984         if(av.hasHiddenColumns)\r
985         {\r
986           column = av.getColumnSelection().adjustForHiddenColumns(yPos);\r
987           if(column > aaMax)\r
988           {\r
989             break;\r
990           }\r
991         }\r
992         else\r
993           column = yPos;\r
994 \r
995         yPos ++;\r
996 \r
997         if(aa.annotations[column]==null || aa.annotations[column-1]==null)\r
998         {\r
999           x+=av.charWidth;\r
1000           continue;\r
1001         }\r
1002 \r
1003           g.setColor(aa.annotations[column].colour);\r
1004           y1 = y - (int) (((aa.annotations[column-1].value-min) / range) * graphHeight);\r
1005           y2 = y - (int) (((aa.annotations[column].value-min) / range) * graphHeight);\r
1006           g.drawLine(x-av.charWidth/2, y1, x+av.charWidth/2, y2);\r
1007           x += av.charWidth;\r
1008        }\r
1009     }\r
1010 \r
1011     public void drawBarGraph(Graphics g, AlignmentAnnotation aa,\r
1012                              int sRes, int eRes,\r
1013                              float min, float max,\r
1014                              int y)\r
1015     {\r
1016       if(sRes>aa.annotations.length)\r
1017         return;\r
1018 \r
1019       eRes = Math.min(eRes, aa.annotations.length);\r
1020 \r
1021       int x=0, y1, y2;\r
1022 \r
1023       float range = max - min;\r
1024 \r
1025       if(aa.threshold!=null)\r
1026       {\r
1027           g.setColor(aa.threshold.colour);\r
1028           Graphics2D g2 = (Graphics2D)g;\r
1029           g2.setStroke(new BasicStroke(1,\r
1030                                         BasicStroke.CAP_SQUARE,\r
1031                                         BasicStroke.JOIN_ROUND, 3f,\r
1032                                         new float[] { 5f, 3f }, 0f));\r
1033 \r
1034           y2 = (int)(y - ((aa.threshold.value-min) / range)*aa.graphHeight);\r
1035           g.drawLine(x-av.charWidth,y2,(eRes-sRes)*av.charWidth,y2);\r
1036           g2.setStroke(new BasicStroke());\r
1037       }\r
1038 \r
1039       y1 = y2 = y;\r
1040 \r
1041       if(min<0)\r
1042         y2 = (int)(y - (0-min / (range))*aa.graphHeight);\r
1043 \r
1044       g.setColor(Color.gray);\r
1045 \r
1046       g.drawLine(x,y2,(eRes-sRes)*av.charWidth,y2);\r
1047 \r
1048 \r
1049       int column = sRes;\r
1050       int yPos = sRes;\r
1051       int aaMax = aa.annotations.length-1;\r
1052 \r
1053       while( yPos < eRes )\r
1054       {\r
1055         if(av.hasHiddenColumns)\r
1056         {\r
1057           column = av.getColumnSelection().adjustForHiddenColumns(yPos);\r
1058           if(column > aaMax)\r
1059           {\r
1060             break;\r
1061           }\r
1062         }\r
1063         else\r
1064           column = yPos;\r
1065 \r
1066         yPos ++;\r
1067 \r
1068         if (aa.annotations[column] == null)\r
1069         {\r
1070           x += av.charWidth;\r
1071           continue;\r
1072         }\r
1073 \r
1074 \r
1075           g.setColor(aa.annotations[column].colour);\r
1076           y1 = y - (int) (((aa.annotations[column].value-min) / (range)) * aa.graphHeight);\r
1077 \r
1078           if(y1-y2>0)\r
1079             g.fillRect(x, y2, av.charWidth, y1-y2 );\r
1080           else\r
1081             g.fillRect(x, y1, av.charWidth, y2-y1 );\r
1082 \r
1083           x += av.charWidth;\r
1084       }\r
1085 \r
1086     }\r
1087 \r
1088     // used by overview window\r
1089     public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y, int sRes, int eRes)\r
1090     {\r
1091       g.setColor(Color.white);\r
1092       g.fillRect(0, 0, width, y);\r
1093       g.setColor(new Color(0, 0, 180));\r
1094 \r
1095       int x = 0, height;\r
1096 \r
1097       for (int j = sRes; j < eRes; j++)\r
1098       {\r
1099           g.setColor(aa.annotations[j].colour);\r
1100 \r
1101           height = (int) ((aa.annotations[j].value / aa.graphMax) * y);\r
1102           if(height>y)\r
1103             height = y;\r
1104 \r
1105           g.fillRect(x, y - height, av.charWidth, height);\r
1106           x += av.charWidth;\r
1107       }\r
1108     }\r
1109 \r
1110 }\r