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