ensure lines are drawn from first alignment column.
[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     if (System.getProperty("os.name").startsWith("Mac"))
60     {
61       MAC = true;
62     }
63
64     this.ap = ap;
65     av = ap.av;
66     setLayout(null);
67     adjustPanelHeight();
68
69     addMouseMotionListener(this);
70
71     addMouseListener(this);
72
73
74     // ap.annotationScroller.getVAdjustable().addAdjustmentListener( this );
75   }
76
77   public AnnotationPanel(AlignViewport av)
78   {
79     this.av = av;
80   }
81
82   public void adjustmentValueChanged(AdjustmentEvent evt)
83   {
84     ap.alabels.setScrollOffset( -evt.getValue());
85   }
86
87   /**
88    * DOCUMENT ME!
89    *
90    * @param evt DOCUMENT ME!
91    */
92   public void actionPerformed(ActionEvent evt)
93   {
94     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
95     Annotation[] anot = aa[activeRow].annotations;
96
97     if (anot.length < av.getColumnSelection().getMax())
98     {
99       Annotation[] temp = new Annotation[av.getColumnSelection().getMax() + 2];
100       System.arraycopy(anot, 0, temp, 0, anot.length);
101       anot = temp;
102       aa[activeRow].annotations = anot;
103     }
104
105     String label = "";
106     if (av.colSel != null && av.colSel.size() > 0
107         && anot[av.colSel.getMin()] != null)
108       label = anot[av.getColumnSelection().getMin()].displayCharacter;
109
110
111     if (evt.getActionCommand().equals(REMOVE))
112     {
113       for (int i = 0; i < av.getColumnSelection().size(); i++)
114       {
115         anot[av.getColumnSelection().columnAt(i)] = null;
116       }
117     }
118     else if (evt.getActionCommand().equals(LABEL))
119     {
120       label = enterLabel(label, "Enter Label");
121
122       if (label == null)
123       {
124         return;
125       }
126
127       if ( (label.length() > 0) && !aa[activeRow].hasText)
128       {
129         aa[activeRow].hasText = true;
130       }
131
132       for (int i = 0; i < av.getColumnSelection().size(); i++)
133       {
134         int index = av.getColumnSelection().columnAt(i);
135
136         if(!av.colSel.isVisible(index))
137           continue;
138
139         if (anot[index] == null)
140         {
141           anot[index] = new Annotation(label, "", ' ', 0);
142         }
143
144         anot[index].displayCharacter = label;
145       }
146     }
147     else if (evt.getActionCommand().equals(COLOUR))
148     {
149       UserDefinedColours udc = new UserDefinedColours(
150           this,
151          Color.black, ap.alignFrame);
152
153       Color col = udc.getColor();
154
155       for (int i = 0; i < av.getColumnSelection().size(); i++)
156       {
157         int index = av.getColumnSelection().columnAt(i);
158
159         if(!av.colSel.isVisible(index))
160           continue;
161
162         if (anot[index] == null)
163         {
164           anot[index] = new Annotation("", "", ' ', 0);
165         }
166
167         anot[index].colour = col;
168       }
169     }
170     else // HELIX OR SHEET
171     {
172       char type = 0;
173       String symbol = "\u03B1";
174
175       if (evt.getActionCommand().equals(HELIX))
176       {
177         type = 'H';
178       }
179       else if (evt.getActionCommand().equals(SHEET))
180       {
181         type = 'E';
182         symbol = "\u03B2";
183       }
184
185       if (!aa[activeRow].hasIcons)
186       {
187         aa[activeRow].hasIcons = true;
188       }
189
190       label = enterLabel(symbol, "Enter Label");
191
192       if (label == null)
193       {
194         return;
195       }
196
197       if ( (label.length() > 0) && !aa[activeRow].hasText)
198       {
199         aa[activeRow].hasText = true;
200       }
201
202       for (int i = 0; i < av.getColumnSelection().size(); i++)
203       {
204         int index = av.getColumnSelection().columnAt(i);
205
206         if(!av.colSel.isVisible(index))
207           continue;
208
209         if (anot[index] == null)
210         {
211           anot[index] = new Annotation(label, "", type, 0);
212         }
213
214         anot[index].secondaryStructure = type;
215         anot[index].displayCharacter = label;
216       }
217     }
218
219     adjustPanelHeight();
220     repaint();
221
222     return;
223   }
224
225   String enterLabel(String text, String label)
226   {
227     EditNameDialog dialog = new EditNameDialog(text,null,label,null,
228         ap.alignFrame,"Enter Label", 400,200, true);
229
230     if(dialog.accept)
231       return dialog.getName();
232     else
233       return null;
234   }
235
236   public void mousePressed(MouseEvent evt)
237   {
238       AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
239       if (aa == null)
240       {
241         return;
242       }
243
244       int height = 0;
245       activeRow = -1;
246
247
248       for (int i = 0; i < aa.length; i++)
249       {
250         if (aa[i].visible)
251         {
252           height += aa[i].height;
253         }
254
255         if (evt.getY() < height)
256         {
257           if (aa[i].editable)
258           {
259             activeRow = i;
260           }
261
262           break;
263         }
264       }
265
266       if ( (evt.getModifiers() & InputEvent.BUTTON3_MASK) ==
267         InputEvent.BUTTON3_MASK  && activeRow != -1)
268       {
269         if (av.getColumnSelection() == null)
270         {
271           return;
272         }
273
274         PopupMenu pop = new PopupMenu("Structure type");
275         MenuItem item = new MenuItem(HELIX);
276         item.addActionListener(this);
277         pop.add(item);
278         item = new MenuItem(SHEET);
279         item.addActionListener(this);
280         pop.add(item);
281         item = new MenuItem(LABEL);
282         item.addActionListener(this);
283         pop.add(item);
284         item = new MenuItem(COLOUR);
285         item.addActionListener(this);
286         pop.add(item);
287         item = new MenuItem(REMOVE);
288         item.addActionListener(this);
289         pop.add(item);
290         ap.alignFrame.add(pop);
291         pop.show(this, evt.getX(), evt.getY());
292
293         return;
294       }
295
296       if (aa == null)
297       {
298         return;
299       }
300
301       ap.scalePanel.mousePressed(evt);
302   }
303
304   public void mouseReleased(MouseEvent evt)
305   {
306     ap.scalePanel.mouseReleased(evt);
307   }
308
309   public void mouseClicked(MouseEvent evt)
310   {}
311
312   public void mouseDragged(MouseEvent evt)
313   {
314     ap.scalePanel.mouseDragged(evt);
315   }
316
317   public void mouseMoved(MouseEvent evt)
318   {
319     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
320     if (aa == null)
321     {
322       return;
323     }
324
325     int row = -1;
326     int height = 0;
327     for (int i = 0; i < aa.length; i++)
328     {
329
330       if (aa[i].visible)
331       {
332         height += aa[i].height;
333       }
334
335       if (evt.getY() < height)
336       {
337         row = i;
338         break;
339       }
340     }
341
342     int res = evt.getX() / av.getCharWidth() + av.getStartRes();
343
344     if (av.hasHiddenColumns)
345     {
346       res = av.getColumnSelection().adjustForHiddenColumns(res);
347     }
348
349     if (row > -1 && res < aa[row].annotations.length && aa[row].annotations[res] != null)
350     {
351       StringBuffer text = new StringBuffer("Sequence position " + (res + 1));
352       if (aa[row].annotations[res].description != null)
353       {
354         text.append("  " + aa[row].annotations[res].description);
355       }
356       ap.alignFrame.statusBar.setText(text.toString());
357     }
358   }
359   public void mouseEntered(MouseEvent evt)
360   {
361     ap.scalePanel.mouseEntered(evt);
362   }
363   public void mouseExited(MouseEvent evt)
364   {
365     ap.scalePanel.mouseExited(evt);
366   }
367
368
369   public int adjustPanelHeight()
370   {
371     // setHeight of panels
372     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
373     int height = 0;
374
375     if (aa != null)
376     {
377       for (int i = 0; i < aa.length; i++)
378       {
379         if (!aa[i].visible)
380         {
381           continue;
382         }
383
384         aa[i].height = 0;
385
386         if (aa[i].hasText)
387         {
388           aa[i].height += av.charHeight;
389         }
390
391         if (aa[i].hasIcons)
392         {
393           aa[i].height += 16;
394         }
395
396         if (aa[i].graph > 0)
397         {
398           aa[i].height += aa[i].graphHeight;
399         }
400
401         if (aa[i].height == 0)
402         {
403           aa[i].height = 20;
404         }
405
406         height += aa[i].height;
407       }
408     }
409     else
410     {
411       height = 20;
412     }
413
414     this.setSize(getSize().width, height);
415
416     repaint();
417
418     return height;
419
420   }
421
422   public void addEditableColumn(int i)
423   {
424     if (activeRow == -1)
425     {
426       AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
427       if (aa == null)
428       {
429         return;
430       }
431
432       for (int j = 0; j < aa.length; j++)
433       {
434         if (aa[j].editable)
435         {
436           activeRow = j;
437           break;
438         }
439       }
440     }
441
442     if (activeRes == null)
443     {
444       activeRes = new Vector();
445       activeRes.addElement(String.valueOf(i));
446       return;
447     }
448
449     activeRes.addElement(String.valueOf(i));
450   }
451
452
453   public void update(Graphics g)
454   {
455     paint(g);
456   }
457
458   public void paint(Graphics g)
459   {
460
461     imgWidth = getSize().width;
462     //(av.endRes - av.startRes + 1) * av.charWidth;
463
464     if (image == null || imgWidth != image.getWidth(this))
465     {
466       image = createImage(imgWidth, ap.annotationPanel.getSize().height);
467       gg = image.getGraphics();
468       gg.setFont(av.getFont());
469       fm = gg.getFontMetrics();
470       fastPaint = false;
471     }
472
473     if (fastPaint)
474     {
475       g.drawImage(image, 0, 0, this);
476       fastPaint = false;
477       return;
478     }
479
480     gg.setColor(Color.white);
481     gg.fillRect(0, 0, getSize().width, getSize().height);
482     drawComponent(gg, av.startRes, av.endRes + 1);
483
484     g.drawImage(image, 0, 0, this);
485   }
486
487   public void fastPaint(int horizontal)
488   {
489     if (horizontal == 0
490         || av.alignment.getAlignmentAnnotation() == null
491         || av.alignment.getAlignmentAnnotation().length < 1
492         )
493     {
494       repaint();
495       return;
496     }
497
498     gg.copyArea(0, 0, imgWidth, getSize().height, -horizontal * av.charWidth, 0);
499     int sr = av.startRes, er = av.endRes + 1, transX = 0;
500
501     if (horizontal > 0) // scrollbar pulled right, image to the left
502     {
503       transX = (er - sr - horizontal) * av.charWidth;
504       sr = er - horizontal;
505     }
506     else if (horizontal < 0)
507     {
508       er = sr - horizontal;
509     }
510
511     gg.translate(transX, 0);
512
513     drawComponent(gg, sr, er);
514
515     gg.translate( -transX, 0);
516
517     fastPaint = true;
518     repaint();
519   }
520
521   /**
522    * DOCUMENT ME!
523    *
524    * @param g DOCUMENT ME!
525    * @param startRes DOCUMENT ME!
526    * @param endRes DOCUMENT ME!
527    */
528   public void drawComponent(Graphics g, int startRes, int endRes)
529   {
530     g.setFont(av.getFont());
531
532     g.setColor(Color.white);
533     g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getSize().height);
534
535     if (fm == null)
536     {
537       fm = g.getFontMetrics();
538     }
539
540     if ( (av.alignment.getAlignmentAnnotation() == null) ||
541         (av.alignment.getAlignmentAnnotation().length < 1))
542     {
543       g.setColor(Color.white);
544       g.fillRect(0, 0, getSize().width, getSize().height);
545       g.setColor(Color.black);
546       if (av.validCharWidth)
547       {
548         g.drawString("Alignment has no annotations", 20, 15);
549       }
550
551       return;
552     }
553
554     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
555
556     int x = 0;
557     int y = 0;
558     int column = 0;
559     char lastSS;
560     int lastSSX;
561     int iconOffset = av.charHeight / 2;
562     boolean validRes = false;
563
564     boolean[] graphGroupDrawn = new boolean[aa.length];
565
566     //\u03B2 \u03B1
567     for (int i = 0; i < aa.length; i++)
568     {
569       AlignmentAnnotation row = aa[i];
570
571       if (!row.visible)
572       {
573         continue;
574       }
575
576       lastSS = ' ';
577       lastSSX = 0;
578
579       if (row.graph > 0)
580       {
581         if (row.graphGroup > -1 && graphGroupDrawn[row.graphGroup])
582         {
583           continue;
584         }
585
586         // this is so that we draw the characters below the graph
587         y += row.height;
588
589         if (row.hasText)
590         {
591           y -= av.charHeight;
592         }
593       }
594
595       if (row.hasText)
596       {
597         iconOffset = av.charHeight / 2;
598       }
599       else
600       {
601         iconOffset = 0;
602       }
603
604       x = 0;
605       while (x < endRes - startRes)
606       {
607         if (av.hasHiddenColumns)
608         {
609           column = av.getColumnSelection().adjustForHiddenColumns(startRes + x);
610           if (column > row.annotations.length - 1)
611           {
612             break;
613           }
614         }
615         else
616         {
617           column = startRes + x;
618         }
619
620         if ( (row.annotations.length <= column) ||
621             (row.annotations[column] == null))
622         {
623           validRes = false;
624         }
625         else
626         {
627           validRes = true;
628         }
629
630         if (activeRow == i)
631         {
632           g.setColor(Color.red);
633
634           if (av.getColumnSelection() != null)
635           {
636             for (int n = 0; n < av.getColumnSelection().size(); n++)
637             {
638               int v = av.getColumnSelection().columnAt(n);
639
640               if (v == column)
641               {
642                 g.fillRect(x * av.charWidth, y,
643                            av.charWidth, av.charHeight);
644               }
645             }
646           }
647         }
648
649
650
651         if (av.validCharWidth && validRes &&
652             (row.annotations[column].displayCharacter.length() > 0))
653         {
654           int charOffset = (av.charWidth -
655                             fm.charWidth(row.annotations[column].
656                                          displayCharacter.charAt(
657                                              0))) / 2;
658
659           if (row.annotations[column].colour == null)
660             g.setColor(Color.black);
661           else
662             g.setColor(row.annotations[column].colour);
663
664           if (column == 0 || row.graph > 0)
665           {
666             g.drawString(row.annotations[column].displayCharacter,
667                          (x * av.charWidth) + charOffset,
668                          y + iconOffset + 3);
669           }
670           else if (
671               row.annotations[column - 1] == null
672               || (!row.annotations[column].displayCharacter.equals(
673                   row.annotations[column - 1].displayCharacter)
674                   ||
675                   (row.annotations[column].displayCharacter.length() < 2 &&
676                    row.annotations[column].secondaryStructure == ' ')))
677           {
678             g.drawString(row.annotations[column].displayCharacter,
679                          (x * av.charWidth) + charOffset,
680                          y + iconOffset + 3);
681           }
682         }
683
684         if (row.hasIcons)
685         {
686           if (!validRes ||
687               (row.annotations[column].secondaryStructure != lastSS))
688           {
689             switch (lastSS)
690             {
691               case 'H':
692                 g.setColor(HELIX_COLOUR);
693                 if (MAC)
694                 {
695                   //Off by 1 offset when drawing rects and ovals
696                   //to offscreen image on the MAC
697                   g.fillRoundRect(lastSSX, y + 4 + iconOffset,
698                                   (x * av.charWidth) - lastSSX, 7, 8, 8);
699                   break;
700                 }
701
702                 int sCol = (lastSSX / av.charWidth) + startRes;
703                 int x1 = lastSSX;
704                 int x2 = (x * av.charWidth);
705
706                 if (sCol == 0 ||
707                     row.annotations[sCol - 1] == null ||
708                     row.annotations[sCol - 1].secondaryStructure != 'H')
709                 {
710                   g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90,
711                             180);
712                   x1 += av.charWidth / 2;
713                 }
714
715                 if (row.annotations[column] == null ||
716                     row.annotations[column].secondaryStructure != 'H')
717                 {
718                   g.fillArc( (x * av.charWidth) - av.charWidth,
719                             y + 4 + iconOffset, av.charWidth, 8, 270, 180);
720                   x2 -= av.charWidth / 2;
721                 }
722
723                 g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
724                 break;
725
726               case 'E':
727                 g.setColor(SHEET_COLOUR);
728                 g.fillRect(lastSSX, y + 4 + iconOffset,
729                            (x * av.charWidth) - lastSSX - 4, 7);
730                 g.fillPolygon(new int[]
731                               { (x * av.charWidth) - 4,
732                               (x * av.charWidth) - 4,
733                               (x * av.charWidth)},
734                               new int[]
735                               {
736                               y + iconOffset, y + 14 + iconOffset,
737                               y + 8 + iconOffset
738                 }, 3);
739
740                 break;
741
742               default:
743                 g.setColor(Color.gray);
744                 g.fillRect(lastSSX, y + 6 + iconOffset,
745                            (x * av.charWidth) - lastSSX, 2);
746
747                 break;
748             }
749
750             if (validRes)
751             {
752               lastSS = row.annotations[column].secondaryStructure;
753             }
754             else
755             {
756               lastSS = ' ';
757             }
758
759             lastSSX = (x * av.charWidth);
760           }
761         }
762
763         column++;
764         x++;
765       }
766
767       if (column >= row.annotations.length)
768       {
769         column = row.annotations.length - 1;
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 (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 }