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