2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3 * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
18 package jalview.appletgui;
23 import java.awt.event.*;
24 import java.awt.font.LineMetrics;
25 import java.awt.geom.AffineTransform;
27 import jalview.analysis.AAFrequency;
28 import jalview.datamodel.*;
29 import jalview.schemes.ColourSchemeI;
31 public class AnnotationPanel extends Panel implements AdjustmentListener,
32 ActionListener, MouseListener, MouseMotionListener
42 static String HELIX = "Helix";
44 static String SHEET = "Sheet";
46 static String LABEL = "Label";
48 static String REMOVE = "Remove Annotation";
50 static String COLOUR = "Colour";
52 static Color HELIX_COLOUR = Color.red.darker();
54 static Color SHEET_COLOUR = Color.green.darker().darker();
64 boolean fastPaint = false;
66 // Used For mouse Dragging and resizing graphs
67 int graphStretch = -1;
69 int graphStretchY = -1;
71 boolean mouseDragging = false;
73 public static int GRAPH_HEIGHT = 40;
77 public AnnotationPanel(AlignmentPanel ap)
79 MAC = new jalview.util.Platform().isAMac();
83 int height = adjustPanelHeight();
84 ap.apvscroll.setValues(0, getHeight(), 0, height);
86 addMouseMotionListener(this);
88 addMouseListener(this);
90 // ap.annotationScroller.getVAdjustable().addAdjustmentListener( this );
93 public AnnotationPanel(AlignViewport av)
98 public void adjustmentValueChanged(AdjustmentEvent evt)
108 public void actionPerformed(ActionEvent evt)
110 AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
115 Annotation[] anot = aa[activeRow].annotations;
117 if (anot.length < av.getColumnSelection().getMax())
119 Annotation[] temp = new Annotation[av.getColumnSelection().getMax() + 2];
120 System.arraycopy(anot, 0, temp, 0, anot.length);
122 aa[activeRow].annotations = anot;
126 if (av.colSel != null && av.colSel.size() > 0
127 && anot[av.colSel.getMin()] != null)
128 label = anot[av.getColumnSelection().getMin()].displayCharacter;
130 if (evt.getActionCommand().equals(REMOVE))
132 for (int i = 0; i < av.getColumnSelection().size(); i++)
134 anot[av.getColumnSelection().columnAt(i)] = null;
137 else if (evt.getActionCommand().equals(LABEL))
139 label = enterLabel(label, "Enter Label");
146 if ((label.length() > 0) && !aa[activeRow].hasText)
148 aa[activeRow].hasText = true;
151 for (int i = 0; i < av.getColumnSelection().size(); i++)
153 int index = av.getColumnSelection().columnAt(i);
155 if (!av.colSel.isVisible(index))
158 if (anot[index] == null)
160 anot[index] = new Annotation(label, "", ' ', 0);
163 anot[index].displayCharacter = label;
166 else if (evt.getActionCommand().equals(COLOUR))
168 UserDefinedColours udc = new UserDefinedColours(this, Color.black,
171 Color col = udc.getColor();
173 for (int i = 0; i < av.getColumnSelection().size(); i++)
175 int index = av.getColumnSelection().columnAt(i);
177 if (!av.colSel.isVisible(index))
180 if (anot[index] == null)
182 anot[index] = new Annotation("", "", ' ', 0);
185 anot[index].colour = col;
192 String symbol = "\u03B1";
194 if (evt.getActionCommand().equals(HELIX))
198 else if (evt.getActionCommand().equals(SHEET))
204 if (!aa[activeRow].hasIcons)
206 aa[activeRow].hasIcons = true;
209 label = enterLabel(symbol, "Enter Label");
216 if ((label.length() > 0) && !aa[activeRow].hasText)
218 aa[activeRow].hasText = true;
221 for (int i = 0; i < av.getColumnSelection().size(); i++)
223 int index = av.getColumnSelection().columnAt(i);
225 if (!av.colSel.isVisible(index))
228 if (anot[index] == null)
230 anot[index] = new Annotation(label, "", type, 0);
233 anot[index].secondaryStructure = type;
234 anot[index].displayCharacter = label;
244 String enterLabel(String text, String label)
246 EditNameDialog dialog = new EditNameDialog(text, null, label, null,
247 ap.alignFrame, "Enter Label", 400, 200, true);
250 return dialog.getName();
255 public void mousePressed(MouseEvent evt)
257 AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
263 int height = -scrollOffset;
266 for (int i = 0; i < aa.length; i++)
270 height += aa[i].height;
273 if (evt.getY() < height)
279 else if (aa[i].graph > 0)
283 graphStretchY = evt.getY();
290 if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK
293 if (av.getColumnSelection() == null)
298 PopupMenu pop = new PopupMenu("Structure type");
299 MenuItem item = new MenuItem(HELIX);
300 item.addActionListener(this);
302 item = new MenuItem(SHEET);
303 item.addActionListener(this);
305 item = new MenuItem(LABEL);
306 item.addActionListener(this);
308 item = new MenuItem(COLOUR);
309 item.addActionListener(this);
311 item = new MenuItem(REMOVE);
312 item.addActionListener(this);
314 ap.alignFrame.add(pop);
315 pop.show(this, evt.getX(), evt.getY());
325 ap.scalePanel.mousePressed(evt);
328 public void mouseReleased(MouseEvent evt)
332 mouseDragging = false;
336 needValidating = false;
338 ap.scalePanel.mouseReleased(evt);
341 public void mouseClicked(MouseEvent evt)
345 boolean needValidating = false;
347 public void mouseDragged(MouseEvent evt)
349 if (graphStretch > -1)
351 av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight += graphStretchY
353 if (av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight < 0)
355 av.alignment.getAlignmentAnnotation()[graphStretch].graphHeight = 0;
357 graphStretchY = evt.getY();
359 needValidating = true;
360 ap.paintAlignment(true);
364 ap.scalePanel.mouseDragged(evt);
368 public void mouseMoved(MouseEvent evt)
370 AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
377 int height = -scrollOffset;
378 for (int i = 0; i < aa.length; i++)
383 height += aa[i].height;
386 if (evt.getY() < height)
393 int res = evt.getX() / av.getCharWidth() + av.getStartRes();
395 if (av.hasHiddenColumns)
397 res = av.getColumnSelection().adjustForHiddenColumns(res);
400 if (row > -1 && res < aa[row].annotations.length
401 && aa[row].annotations[res] != null)
403 StringBuffer text = new StringBuffer("Sequence position " + (res + 1));
404 if (aa[row].annotations[res].description != null)
406 text.append(" " + aa[row].annotations[res].description);
408 ap.alignFrame.statusBar.setText(text.toString());
412 public void mouseEntered(MouseEvent evt)
414 ap.scalePanel.mouseEntered(evt);
417 public void mouseExited(MouseEvent evt)
419 ap.scalePanel.mouseExited(evt);
422 public int adjustPanelHeight()
424 return adjustPanelHeight(true);
427 public int adjustPanelHeight(boolean repaint)
430 // setHeight of panels
431 AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
436 for (int i = 0; i < aa.length; i++)
447 aa[i].height += av.charHeight;
457 aa[i].height += aa[i].graphHeight;
460 if (aa[i].height == 0)
465 height += aa[i].height;
472 this.setSize(new Dimension(getSize().width, height));
482 public void addEditableColumn(int i)
486 AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
492 for (int j = 0; j < aa.length; j++)
502 if (activeRes == null)
504 activeRes = new Vector();
505 activeRes.addElement(String.valueOf(i));
509 activeRes.addElement(String.valueOf(i));
512 public void update(Graphics g)
517 public void paint(Graphics g)
520 imgWidth = getSize().width;
521 // (av.endRes - av.startRes + 1) * av.charWidth;
523 if (image == null || imgWidth != image.getWidth(this))
525 image = createImage(imgWidth, ap.annotationPanel.getSize().height);
526 gg = image.getGraphics();
527 gg.setFont(av.getFont());
528 fm = gg.getFontMetrics();
534 g.drawImage(image, 0, 0, this);
539 gg.setColor(Color.white);
540 gg.fillRect(0, 0, getSize().width, getSize().height);
541 drawComponent(gg, av.startRes, av.endRes + 1);
543 g.drawImage(image, 0, 0, this);
546 public void fastPaint(int horizontal)
548 if (horizontal == 0 || av.alignment.getAlignmentAnnotation() == null
549 || av.alignment.getAlignmentAnnotation().length < 1)
555 gg.copyArea(0, 0, imgWidth, getSize().height, -horizontal
557 int sr = av.startRes, er = av.endRes + 1, transX = 0;
559 if (horizontal > 0) // scrollbar pulled right, image to the left
561 transX = (er - sr - horizontal) * av.charWidth;
562 sr = er - horizontal;
564 else if (horizontal < 0)
566 er = sr - horizontal;
569 gg.translate(transX, 0);
571 drawComponent(gg, sr, er);
573 gg.translate(-transX, 0);
589 public void drawComponent(Graphics g, int startRes, int endRes)
591 Font ofont = av.getFont();
594 g.setColor(Color.white);
595 g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getSize().height);
599 fm = g.getFontMetrics();
602 if ((av.alignment.getAlignmentAnnotation() == null)
603 || (av.alignment.getAlignmentAnnotation().length < 1))
605 g.setColor(Color.white);
606 g.fillRect(0, 0, getSize().width, getSize().height);
607 g.setColor(Color.black);
608 if (av.validCharWidth)
610 g.drawString("Alignment has no annotations", 20, 15);
616 AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();
617 g.translate(0, -scrollOffset);
623 int iconOffset = av.charHeight / 2;
624 boolean validRes = false;
625 boolean validEnd = false;
626 boolean labelAllCols = false;
627 boolean centreColLabels, centreColLabelsDef = av
628 .getCentreColumnLabels();
629 boolean scaleColLabel = false;
630 boolean[] graphGroupDrawn = new boolean[aa.length];
631 int charOffset = 0; // offset for a label
632 float fmWidth, fmScaling = 1f; // scaling for a label to fit it into a
635 for (int i = 0; i < aa.length; i++)
637 AlignmentAnnotation row = aa[i];
643 centreColLabels = row.centreColLabels || centreColLabelsDef;
644 labelAllCols = row.showAllColLabels;
645 scaleColLabel = row.scaleColLabel;
651 if (row.graphGroup > -1 && graphGroupDrawn[row.graphGroup])
656 // this is so that we draw the characters below the graph
661 iconOffset = av.charHeight - fm.getDescent();
665 // TODO: else is the logic used in application, applet had no 'else'
666 else if (row.hasText)
668 iconOffset = av.charHeight - fm.getDescent();
677 while (x < endRes - startRes)
679 if (av.hasHiddenColumns)
681 column = av.getColumnSelection().adjustForHiddenColumns(
683 if (column > row.annotations.length - 1)
690 column = startRes + x;
693 if ((row.annotations.length <= column)
694 || (row.annotations[column] == null))
705 g.setColor(Color.red);
707 if (av.getColumnSelection() != null)
709 for (int n = 0; n < av.getColumnSelection().size(); n++)
711 int v = av.getColumnSelection().columnAt(n);
715 g.fillRect(x * av.charWidth, y, av.charWidth, av.charHeight);
721 if (av.validCharWidth
723 && (row.annotations[column].displayCharacter != null && row.annotations[column].displayCharacter
727 if (centreColLabels || scaleColLabel)
729 fmWidth = (float) fm.charsWidth(
730 row.annotations[column].displayCharacter.toCharArray(),
731 0, row.annotations[column].displayCharacter.length());
735 // justify the label and scale to fit in column
736 if (fmWidth > av.charWidth)
738 // scale only if the current font isn't already small enough
739 fmScaling = av.charWidth;
740 fmScaling /= fmWidth;
741 // not 1.1 // g.setFont(new
742 // Font(ofont,AffineTransform.getScaleInstance(fmScaling,
744 // and update the label's width to reflect the scaling.
745 fmWidth = av.charWidth;
752 .charWidth(row.annotations[column].displayCharacter
755 charOffset = (int) ((av.charWidth - fmWidth) / 2f);
757 if (row.annotations[column].colour == null)
758 g.setColor(Color.black);
760 g.setColor(row.annotations[column].colour);
762 if (column == 0 || row.graph > 0)
764 g.drawString(row.annotations[column].displayCharacter,
765 (x * av.charWidth) + charOffset, y + iconOffset + 3); // +
768 else if (row.annotations[column - 1] == null
770 || !row.annotations[column].displayCharacter
771 .equals(row.annotations[column - 1].displayCharacter) || (row.annotations[column].displayCharacter
772 .length() < 2 && row.annotations[column].secondaryStructure == ' ')))
774 g.drawString(row.annotations[column].displayCharacter,
775 (x * av.charWidth) + charOffset, y + iconOffset + 3); // +3?
783 || (row.annotations[column].secondaryStructure != lastSS))
788 g.setColor(HELIX_COLOUR);
791 // Off by 1 offset when drawing rects and ovals
792 // to offscreen image on the MAC
793 g.fillRoundRect(lastSSX, y + 4 + iconOffset,
794 (x * av.charWidth) - lastSSX, 7, 8, 8);
798 int sCol = (lastSSX / av.charWidth) + startRes;
800 int x2 = (x * av.charWidth);
803 || row.annotations[sCol - 1] == null
804 || row.annotations[sCol - 1].secondaryStructure != 'H')
806 g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90,
808 x1 += av.charWidth / 2;
811 if (!validRes || row.annotations[column] == null
812 || row.annotations[column].secondaryStructure != 'H')
814 g.fillArc((x * av.charWidth) - av.charWidth, y + 4
815 + iconOffset, av.charWidth, 8, 270, 180);
816 x2 -= av.charWidth / 2;
819 g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
823 g.setColor(SHEET_COLOUR);
824 g.fillRect(lastSSX, y + 4 + iconOffset, (x * av.charWidth)
826 g.fillPolygon(new int[]
827 { (x * av.charWidth) - 4, (x * av.charWidth) - 4,
828 (x * av.charWidth) }, new int[]
829 { y + iconOffset, y + 14 + iconOffset, y + 8 + iconOffset },
835 g.setColor(Color.gray);
836 g.fillRect(lastSSX, y + 6 + iconOffset, (x * av.charWidth)
844 lastSS = row.annotations[column].secondaryStructure;
851 lastSSX = (x * av.charWidth);
859 if (column >= row.annotations.length)
861 column = row.annotations.length - 1;
876 g.setColor(HELIX_COLOUR);
879 // Off by 1 offset when drawing rects and ovals
880 // to offscreen image on the MAC
881 g.fillRoundRect(lastSSX, y + 4 + iconOffset, (x * av.charWidth)
886 int sCol = (lastSSX / av.charWidth) + startRes;
888 int x2 = (x * av.charWidth);
890 if (sCol == 0 || row.annotations[sCol - 1] == null
891 || row.annotations[sCol - 1].secondaryStructure != 'H')
893 g.fillArc(lastSSX, y + 4 + iconOffset, av.charWidth, 8, 90, 180);
894 x1 += av.charWidth / 2;
897 if (row.annotations[column] == null
898 || row.annotations[column].secondaryStructure != 'H')
900 g.fillArc((x * av.charWidth) - av.charWidth,
901 y + 4 + iconOffset, av.charWidth, 8, 270, 180);
902 x2 -= av.charWidth / 2;
905 g.fillRect(x1, y + 4 + iconOffset, x2 - x1, 8);
910 g.setColor(SHEET_COLOUR);
912 if (!validEnd || row.annotations[endRes] == null
913 || row.annotations[endRes].secondaryStructure != 'E')
915 g.fillRect(lastSSX, y + 4 + iconOffset, (x * av.charWidth)
917 g.fillPolygon(new int[]
918 { (x * av.charWidth) - 4, (x * av.charWidth) - 4,
919 (x * av.charWidth) }, new int[]
920 { y + iconOffset, y + 14 + iconOffset, y + 7 + iconOffset }, 3);
924 g.fillRect(lastSSX, y + 4 + iconOffset, x * av.charWidth
930 g.setColor(Color.gray);
931 if (!av.wrapAlignment || endRes == av.endRes)
933 g.fillRect(lastSSX, y + 6 + iconOffset, (x * av.charWidth)
941 if (row.graph > 0 && row.graphHeight > 0)
943 if (row.graph == AlignmentAnnotation.LINE_GRAPH)
945 if (row.graphGroup > -1 && !graphGroupDrawn[row.graphGroup])
947 float groupmax = -999999, groupmin = 9999999;
948 for (int gg = 0; gg < aa.length; gg++)
950 if (aa[gg].graphGroup != row.graphGroup)
957 aa[gg].visible = false;
960 if (aa[gg].graphMax > groupmax)
962 groupmax = aa[gg].graphMax;
964 if (aa[gg].graphMin < groupmin)
966 groupmin = aa[gg].graphMin;
970 for (int gg = 0; gg < aa.length; gg++)
972 if (aa[gg].graphGroup == row.graphGroup)
974 drawLineGraph(g, aa[gg], startRes, endRes, y, groupmin,
975 groupmax, row.graphHeight);
979 graphGroupDrawn[row.graphGroup] = true;
983 drawLineGraph(g, row, startRes, endRes, y, row.graphMin,
984 row.graphMax, row.graphHeight);
987 else if (row.graph == AlignmentAnnotation.BAR_GRAPH)
989 drawBarGraph(g, row, startRes, endRes, row.graphMin,
994 if (row.graph > 0 && row.hasText)
1004 g.translate(0, +scrollOffset);
1007 public void drawLineGraph(Graphics g, AlignmentAnnotation aa, int sRes,
1008 int eRes, int y, float min, float max, int graphHeight)
1010 if (sRes > aa.annotations.length)
1017 // Adjustment for fastpaint to left
1018 if (eRes < av.endRes)
1023 eRes = Math.min(eRes, aa.annotations.length);
1026 float range = max - min;
1031 y2 = y - (int) ((0 - min / range) * graphHeight);
1034 g.setColor(Color.gray);
1035 g.drawLine(x - av.charWidth, y2, (eRes - sRes) * av.charWidth, y2);
1037 eRes = Math.min(eRes, aa.annotations.length);
1040 int aaMax = aa.annotations.length - 1;
1042 while (x < eRes - sRes)
1045 if (av.hasHiddenColumns)
1047 column = av.getColumnSelection().adjustForHiddenColumns(column);
1055 if (aa.annotations[column] == null) // || coaa.annotations[column - 1] ==
1062 if (aa.annotations[column].colour == null)
1063 g.setColor(Color.black);
1065 g.setColor(aa.annotations[column].colour);
1066 if (column == 0 || aa.annotations[column - 1] == null)
1069 - (int) (((aa.annotations[column].value - min) / range) * graphHeight);
1074 - (int) (((aa.annotations[column - 1].value - min) / range) * graphHeight);
1077 - (int) (((aa.annotations[column].value - min) / range) * graphHeight);
1079 g.drawLine(x * av.charWidth - av.charWidth / 2, y1, x * av.charWidth
1080 + av.charWidth / 2, y2);
1084 if (aa.threshold != null)
1086 g.setColor(aa.threshold.colour);
1088 y2 = (int) (y - ((aa.threshold.value - min) / range) * graphHeight);
1089 g.drawLine(0, y2, (eRes - sRes) * av.charWidth, y2);
1093 public void drawBarGraph(Graphics g, AlignmentAnnotation aa, int sRes,
1094 int eRes, float min, float max, int y)
1096 ColourSchemeI profcolour = av.getGlobalColourScheme();
1097 if (profcolour == null)
1099 profcolour = new jalview.schemes.ZappoColourScheme();
1101 if (sRes > aa.annotations.length)
1105 Font ofont = g.getFont();
1106 eRes = Math.min(eRes, aa.annotations.length);
1108 int x = 0, y1 = y, y2 = y;
1110 float range = max - min;
1114 y2 = y - (int) ((0 - min / (range)) * aa.graphHeight);
1117 g.setColor(Color.gray);
1119 g.drawLine(x, y2, (eRes - sRes) * av.charWidth, y2);
1122 int aaMax = aa.annotations.length - 1;
1123 boolean renderHistogram = true, renderProfile = false;
1124 if (aa.autoCalculated && aa.label.startsWith("Consensus"))
1125 { // TODO: generalise this to have render styles for consensus/profile data
1126 if (aa.groupRef != null)
1128 renderHistogram = aa.groupRef.isShowConsensusHistogram();
1129 renderProfile = aa.groupRef.isShowSequenceLogo();
1133 renderHistogram = av.isShowConsensusHistogram();
1134 renderProfile = av.isShowSequenceLogo();
1138 while (x < eRes - sRes)
1141 if (av.hasHiddenColumns)
1143 column = av.getColumnSelection().adjustForHiddenColumns(column);
1151 if (aa.annotations[column] == null)
1157 if (aa.annotations[column].colour == null)
1158 g.setColor(Color.black);
1160 g.setColor(aa.annotations[column].colour);
1163 - (int) (((aa.annotations[column].value - min) / (range)) * aa.graphHeight);
1165 if (renderHistogram)
1169 g.fillRect(x * av.charWidth, y2, av.charWidth, y1 - y2);
1173 g.fillRect(x * av.charWidth, y1, av.charWidth, y2 - y1);
1176 // draw profile if available
1177 if (aa.annotations[column].value != 0 && renderProfile)
1179 int profl[] = getProfileFor(aa, column);
1180 int ht = y1, htn = y2 - y1;// aa.graphHeight;
1183 char[] dc = new char[1];
1185 for (int c = 1; profl != null && c < profl[0];)
1187 dc[0] = (char) profl[c++];
1188 wdth = av.charWidth;
1189 wdth /= (float) fm.charsWidth(dc, 0, 1);
1195 { // not java 1.1 compatible: Bug # 0060064
1196 g.setFont(ofont.deriveFont(AffineTransform.getScaleInstance(
1197 wdth, (ht2 = (htn * ((double) profl[c++]) / 100.0))
1199 lm = g.getFontMetrics().getLineMetrics(dc, 0, 1, g);
1200 g.setColor(profcolour.findColour(dc[0]));
1201 g.drawChars(dc, 0, 1, x * av.charWidth,
1202 (int) (ht + lm.getHeight()));
1211 if (aa.threshold != null)
1213 g.setColor(aa.threshold.colour);
1214 y2 = (int) (y - ((aa.threshold.value - min) / range) * aa.graphHeight);
1215 g.drawLine(0, y2, (eRes - sRes) * av.charWidth, y2);
1219 private int[] getProfileFor(AlignmentAnnotation aa, int column)
1221 // if (aa.autoCalculated && aa.label.startsWith("Consensus")) {
1222 if (aa.groupRef != null && aa.groupRef.consensusData != null)
1224 // && aa.groupRef.isShowSequenceLogo()) {
1225 return AAFrequency.extractProfile(aa.groupRef.consensusData[column],
1226 aa.groupRef.getIgnoreGapsConsensus());
1228 // TODO extend annotation row to enable dynamic and static profile data to
1230 if (aa.groupRef == null && aa.sequenceRef == null)
1231 // && av.isShowSequenceLogo())
1233 return AAFrequency.extractProfile(av.hconsensus[column],
1234 av.getIgnoreGapsConsensus());
1240 // used by overview window
1241 public void drawGraph(Graphics g, AlignmentAnnotation aa, int width,
1242 int y, int sRes, int eRes)
1244 eRes = Math.min(eRes, aa.annotations.length);
1245 g.setColor(Color.white);
1246 g.fillRect(0, 0, width, y);
1247 g.setColor(new Color(0, 0, 180));
1251 for (int j = sRes; j < eRes; j++)
1253 if (aa.annotations[j].colour == null)
1254 g.setColor(Color.black);
1256 g.setColor(aa.annotations[j].colour);
1258 height = (int) ((aa.annotations[j].value / aa.graphMax) * GRAPH_HEIGHT);
1263 g.fillRect(x, y - height, av.charWidth, height);
1268 int scrollOffset = 0;
1270 public void setScrollOffset(int value)
1272 scrollOffset = value;