2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
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
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.datamodel.AlignmentAnnotation;
24 import jalview.datamodel.Annotation;
25 import jalview.datamodel.ColumnSelection;
26 import jalview.datamodel.HiddenColumns;
27 import jalview.datamodel.SequenceI;
28 import jalview.gui.JalviewColourChooser.ColourChooserListener;
29 import jalview.renderer.AnnotationRenderer;
30 import jalview.renderer.AwtRenderPanelI;
31 import jalview.schemes.ResidueProperties;
32 import jalview.util.Comparison;
33 import jalview.util.MessageManager;
34 import jalview.viewmodel.ViewportListenerI;
35 import jalview.viewmodel.ViewportRanges;
37 import java.awt.AlphaComposite;
38 import java.awt.Color;
39 import java.awt.Dimension;
40 import java.awt.FontMetrics;
41 import java.awt.Graphics;
42 import java.awt.Graphics2D;
43 import java.awt.Image;
44 import java.awt.Rectangle;
45 import java.awt.RenderingHints;
46 import java.awt.event.ActionEvent;
47 import java.awt.event.ActionListener;
48 import java.awt.event.AdjustmentEvent;
49 import java.awt.event.AdjustmentListener;
50 import java.awt.event.MouseEvent;
51 import java.awt.event.MouseListener;
52 import java.awt.event.MouseMotionListener;
53 import java.awt.event.MouseWheelEvent;
54 import java.awt.event.MouseWheelListener;
55 import java.awt.image.BufferedImage;
56 import java.beans.PropertyChangeEvent;
57 import java.util.ArrayList;
58 import java.util.Collections;
59 import java.util.List;
61 import javax.swing.JMenuItem;
62 import javax.swing.JPanel;
63 import javax.swing.JPopupMenu;
64 import javax.swing.Scrollable;
65 import javax.swing.ToolTipManager;
68 * AnnotationPanel displays visible portion of annotation rows below unwrapped
74 public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
75 MouseListener, MouseWheelListener, MouseMotionListener,
76 ActionListener, AdjustmentListener, Scrollable, ViewportListenerI
80 Select, Resize, Undefined
83 String HELIX = MessageManager.getString("label.helix");
85 String SHEET = MessageManager.getString("label.sheet");
88 * For RNA secondary structure "stems" aka helices
90 String STEM = MessageManager.getString("label.rna_helix");
92 String LABEL = MessageManager.getString("label.label");
94 String REMOVE = MessageManager.getString("label.remove_annotation");
96 String COLOUR = MessageManager.getString("action.colour");
98 public final Color HELIX_COLOUR = Color.red.darker();
100 public final Color SHEET_COLOUR = Color.green.darker().darker();
102 public final Color STEM_COLOUR = Color.blue.darker();
105 public AlignViewport av;
109 public int activeRow = -1;
111 public BufferedImage image;
113 public volatile BufferedImage fadedImage;
117 public FontMetrics fm;
119 public int imgWidth = 0;
121 boolean fastPaint = false;
123 // Used For mouse Dragging and resizing graphs
124 int graphStretch = -1;
126 int mouseDragLastX = -1;
128 int mouseDragLastY = -1;
130 DragMode dragMode = DragMode.Undefined;
132 boolean mouseDragging = false;
134 // for editing cursor
139 public final AnnotationRenderer renderer;
141 private MouseWheelListener[] _mwl;
144 * Creates a new AnnotationPanel object.
149 public AnnotationPanel(AlignmentPanel ap)
151 ToolTipManager.sharedInstance().registerComponent(this);
152 ToolTipManager.sharedInstance().setInitialDelay(0);
153 ToolTipManager.sharedInstance().setDismissDelay(10000);
156 this.setLayout(null);
157 addMouseListener(this);
158 addMouseMotionListener(this);
159 ap.annotationScroller.getVerticalScrollBar()
160 .addAdjustmentListener(this);
161 // save any wheel listeners on the scroller, so we can propagate scroll
163 _mwl = ap.annotationScroller.getMouseWheelListeners();
164 // and then set our own listener to consume all mousewheel events
165 ap.annotationScroller.addMouseWheelListener(this);
166 renderer = new AnnotationRenderer();
168 av.getRanges().addPropertyChangeListener(this);
171 public AnnotationPanel(AlignViewport av)
174 renderer = new AnnotationRenderer();
178 public void mouseWheelMoved(MouseWheelEvent e)
183 double wheelRotation = e.getPreciseWheelRotation();
184 if (wheelRotation > 0)
186 av.getRanges().scrollRight(true);
188 else if (wheelRotation < 0)
190 av.getRanges().scrollRight(false);
195 // TODO: find the correct way to let the event bubble up to
196 // ap.annotationScroller
197 for (MouseWheelListener mwl : _mwl)
201 mwl.mouseWheelMoved(e);
212 public Dimension getPreferredScrollableViewportSize()
214 return getPreferredSize();
218 public int getScrollableBlockIncrement(Rectangle visibleRect,
219 int orientation, int direction)
225 public boolean getScrollableTracksViewportHeight()
231 public boolean getScrollableTracksViewportWidth()
237 public int getScrollableUnitIncrement(Rectangle visibleRect,
238 int orientation, int direction)
247 * java.awt.event.AdjustmentListener#adjustmentValueChanged(java.awt.event
251 public void adjustmentValueChanged(AdjustmentEvent evt)
253 // update annotation label display
254 ap.getAlabels().setScrollOffset(-evt.getValue());
258 * Calculates the height of the annotation displayed in the annotation panel.
259 * Callers should normally call the ap.adjustAnnotationHeight method to ensure
260 * all annotation associated components are updated correctly.
263 public int adjustPanelHeight()
265 int height = av.calcPanelHeight();
266 this.setPreferredSize(new Dimension(1, height));
269 // revalidate only when the alignment panel is fully constructed
283 public void actionPerformed(ActionEvent evt)
285 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
290 Annotation[] anot = aa[activeRow].annotations;
292 if (anot.length < av.getColumnSelection().getMax())
294 Annotation[] temp = new Annotation[av.getColumnSelection().getMax()
296 System.arraycopy(anot, 0, temp, 0, anot.length);
298 aa[activeRow].annotations = anot;
301 String action = evt.getActionCommand();
302 if (action.equals(REMOVE))
304 for (int index : av.getColumnSelection().getSelected())
306 if (av.getAlignment().getHiddenColumns().isVisible(index))
312 else if (action.equals(LABEL))
314 String exMesg = collectAnnotVals(anot, LABEL);
315 String label = JvOptionPane.showInputDialog(this,
316 MessageManager.getString("label.enter_label"), exMesg);
323 if ((label.length() > 0) && !aa[activeRow].hasText)
325 aa[activeRow].hasText = true;
328 for (int index : av.getColumnSelection().getSelected())
330 if (!av.getAlignment().getHiddenColumns().isVisible(index))
335 if (anot[index] == null)
337 anot[index] = new Annotation(label, "", ' ', 0);
341 anot[index].displayCharacter = label;
345 else if (action.equals(COLOUR))
347 final Annotation[] fAnot = anot;
348 String title = MessageManager
349 .getString("label.select_foreground_colour");
350 ColourChooserListener listener = new ColourChooserListener()
353 public void colourSelected(Color c)
355 HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns();
356 for (int index : av.getColumnSelection().getSelected())
358 if (hiddenColumns.isVisible(index))
360 if (fAnot[index] == null)
362 fAnot[index] = new Annotation("", "", ' ', 0);
364 fAnot[index].colour = c;
368 JalviewColourChooser.showColourChooser(this,
369 title, Color.black, listener);
372 // HELIX, SHEET or STEM
375 String symbol = "\u03B1"; // alpha
377 if (action.equals(HELIX))
381 else if (action.equals(SHEET))
384 symbol = "\u03B2"; // beta
387 // Added by LML to color stems
388 else if (action.equals(STEM))
391 int column = av.getColumnSelection().getSelectedRanges().get(0)[0];
392 symbol = aa[activeRow].getDefaultRnaHelixSymbol(column);
395 if (!aa[activeRow].hasIcons)
397 aa[activeRow].hasIcons = true;
400 String label = JvOptionPane.showInputDialog(MessageManager
401 .getString("label.enter_label_for_the_structure"), symbol);
408 if ((label.length() > 0) && !aa[activeRow].hasText)
410 aa[activeRow].hasText = true;
411 if (action.equals(STEM))
413 aa[activeRow].showAllColLabels = true;
416 for (int index : av.getColumnSelection().getSelected())
418 if (!av.getAlignment().getHiddenColumns().isVisible(index))
423 if (anot[index] == null)
425 anot[index] = new Annotation(label, "", type, 0);
428 anot[index].secondaryStructure = type != 'S' ? type
429 : label.length() == 0 ? ' ' : label.charAt(0);
430 anot[index].displayCharacter = label;
435 av.getAlignment().validateAnnotation(aa[activeRow]);
436 ap.alignmentChanged();
437 ap.alignFrame.setMenusForViewport();
445 * Returns any existing annotation concatenated as a string. For each
446 * annotation, takes the description, if any, else the secondary structure
447 * character (if type is HELIX, SHEET or STEM), else the display character (if
454 private String collectAnnotVals(Annotation[] anots, String type)
456 // TODO is this method wanted? why? 'last' is not used
458 StringBuilder collatedInput = new StringBuilder(64);
460 ColumnSelection viscols = av.getColumnSelection();
461 HiddenColumns hidden = av.getAlignment().getHiddenColumns();
464 * the selection list (read-only view) is in selection order, not
465 * column order; make a copy so we can sort it
467 List<Integer> selected = new ArrayList<>(viscols.getSelected());
468 Collections.sort(selected);
469 for (int index : selected)
471 // always check for current display state - just in case
472 if (!hidden.isVisible(index))
476 String tlabel = null;
477 if (anots[index] != null)
478 { // LML added stem code
479 if (type.equals(HELIX) || type.equals(SHEET) || type.equals(STEM)
480 || type.equals(LABEL))
482 tlabel = anots[index].description;
483 if (tlabel == null || tlabel.length() < 1)
485 if (type.equals(HELIX) || type.equals(SHEET)
486 || type.equals(STEM))
488 tlabel = "" + anots[index].secondaryStructure;
492 tlabel = "" + anots[index].displayCharacter;
496 if (tlabel != null && !tlabel.equals(last))
498 if (last.length() > 0)
500 collatedInput.append(" ");
502 collatedInput.append(tlabel);
506 return collatedInput.toString();
510 * Action on right mouse pressed on Mac is to show a pop-up menu for the
511 * annotation. Action on left mouse pressed is to find which annotation is
512 * pressed and mark the start of a column selection or graph resize operation.
517 public void mousePressed(MouseEvent evt)
520 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
525 mouseDragLastX = evt.getX();
526 mouseDragLastY = evt.getY();
529 * add visible annotation heights until we reach the y
530 * position, to find which annotation it is in
535 final int y = evt.getY();
536 for (int i = 0; i < aa.length; i++)
540 height += aa[i].height;
549 else if (aa[i].graph > 0)
552 * we have clicked on a resizable graph annotation
561 * isPopupTrigger fires in mousePressed on Mac,
562 * not until mouseRelease on Windows
564 if (evt.isPopupTrigger() && activeRow != -1)
566 showPopupMenu(y, evt.getX());
570 ap.getScalePanel().mousePressed(evt);
574 * Construct and display a context menu at the right-click position
579 void showPopupMenu(final int y, int x)
581 if (av.getColumnSelection() == null
582 || av.getColumnSelection().isEmpty())
587 JPopupMenu pop = new JPopupMenu(
588 MessageManager.getString("label.structure_type"));
591 * Just display the needed structure options
593 if (av.getAlignment().isNucleotide())
595 item = new JMenuItem(STEM);
596 item.addActionListener(this);
601 item = new JMenuItem(HELIX);
602 item.addActionListener(this);
604 item = new JMenuItem(SHEET);
605 item.addActionListener(this);
608 item = new JMenuItem(LABEL);
609 item.addActionListener(this);
611 item = new JMenuItem(COLOUR);
612 item.addActionListener(this);
614 item = new JMenuItem(REMOVE);
615 item.addActionListener(this);
617 pop.show(this, x, y);
621 * Action on mouse up is to clear mouse drag data and call mouseReleased on
622 * ScalePanel, to deal with defining the selection group (if any) defined by
628 public void mouseReleased(MouseEvent evt)
633 mouseDragging = false;
634 dragMode = DragMode.Undefined;
635 ap.getScalePanel().mouseReleased(evt);
638 * isPopupTrigger is set in mouseReleased on Windows
639 * (in mousePressed on Mac)
641 if (evt.isPopupTrigger() && activeRow != -1)
643 showPopupMenu(evt.getY(), evt.getX());
655 public void mouseEntered(MouseEvent evt)
657 ap.getScalePanel().mouseEntered(evt);
661 * On leaving the panel, calls ScalePanel.mouseExited to deal with scrolling
662 * with column selection on a mouse drag
667 public void mouseExited(MouseEvent evt)
669 ap.getScalePanel().mouseExited(evt);
679 public void mouseDragged(MouseEvent evt)
682 * todo: if dragMode is Undefined:
683 * - set to Select if dx > dy
684 * - set to Resize if dy > dx
685 * - do nothing if dx == dy
687 final int x = evt.getX();
688 final int y = evt.getY();
689 if (dragMode == DragMode.Undefined)
691 int dx = Math.abs(x - mouseDragLastX);
692 int dy = Math.abs(y - mouseDragLastY);
693 if (graphStretch == -1 || dx > dy)
696 * mostly horizontal drag, or not a graph annotation
698 dragMode = DragMode.Select;
703 * mostly vertical drag
705 dragMode = DragMode.Resize;
709 if (dragMode == DragMode.Undefined)
712 * drag is diagonal - defer deciding whether to
713 * treat as up/down or left/right
720 if (dragMode == DragMode.Resize)
723 * resize graph annotation if mouse was dragged up or down
725 int deltaY = mouseDragLastY - evt.getY();
728 AlignmentAnnotation graphAnnotation = av.getAlignment()
729 .getAlignmentAnnotation()[graphStretch];
730 int newHeight = Math.max(0, graphAnnotation.graphHeight + deltaY);
731 graphAnnotation.graphHeight = newHeight;
733 ap.paintAlignment(false, false);
739 * for mouse drag left or right, delegate to
740 * ScalePanel to adjust the column selection
742 ap.getScalePanel().mouseDragged(evt);
752 * Constructs the tooltip, and constructs and displays a status message, for
753 * the current mouse position
758 public void mouseMoved(MouseEvent evt)
760 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
764 this.setToolTipText(null);
771 for (int i = 0; i < aa.length; i++)
775 height += aa[i].height;
778 if (evt.getY() < height)
787 this.setToolTipText(null);
791 int column = (evt.getX() / av.getCharWidth())
792 + av.getRanges().getStartRes();
794 if (av.hasHiddenColumns())
796 column = av.getAlignment().getHiddenColumns()
797 .visibleToAbsoluteColumn(column);
800 AlignmentAnnotation ann = aa[row];
801 if (row > -1 && ann.annotations != null
802 && column < ann.annotations.length)
804 buildToolTip(ann, column, aa);
805 setStatusMessage(column, ann);
809 this.setToolTipText(null);
810 ap.alignFrame.statusBar.setText(" ");
815 * Builds a tooltip for the annotation at the current mouse position.
821 void buildToolTip(AlignmentAnnotation ann, int column,
822 AlignmentAnnotation[] anns)
824 if (ann.graphGroup > -1)
826 StringBuilder tip = new StringBuilder(32);
827 tip.append("<html>");
828 for (int i = 0; i < anns.length; i++)
830 if (anns[i].graphGroup == ann.graphGroup
831 && anns[i].annotations[column] != null)
833 tip.append(anns[i].label);
834 String description = anns[i].annotations[column].description;
835 if (description != null && description.length() > 0)
837 tip.append(" ").append(description);
842 if (tip.length() != 6)
844 tip.setLength(tip.length() - 4);
845 this.setToolTipText(tip.toString() + "</html>");
848 else if (ann.annotations[column] != null)
850 String description = ann.annotations[column].description;
851 if (description != null && description.length() > 0)
853 this.setToolTipText(JvSwingUtils.wrapTooltip(true, description));
857 this.setToolTipText(null); // no tooltip if null or empty description
862 // clear the tooltip.
863 this.setToolTipText(null);
868 * Constructs and displays the status bar message
873 void setStatusMessage(int column, AlignmentAnnotation ann)
876 * show alignment column and annotation description if any
878 StringBuilder text = new StringBuilder(32);
879 text.append(MessageManager.getString("label.column")).append(" ")
882 if (ann.annotations[column] != null)
884 String description = ann.annotations[column].description;
885 if (description != null && description.trim().length() > 0)
887 text.append(" ").append(description);
892 * if the annotation is sequence-specific, show the sequence number
893 * in the alignment, and (if not a gap) the residue and position
895 SequenceI seqref = ann.sequenceRef;
898 int seqIndex = av.getAlignment().findIndex(seqref);
901 text.append(", ").append(MessageManager.getString("label.sequence"))
902 .append(" ").append(seqIndex + 1);
903 char residue = seqref.getCharAt(column);
904 if (!Comparison.isGap(residue))
908 if (av.getAlignment().isNucleotide())
910 name = ResidueProperties.nucleotideName
911 .get(String.valueOf(residue));
912 text.append(" Nucleotide: ")
913 .append(name != null ? name : residue);
917 name = 'X' == residue ? "X"
918 : ('*' == residue ? "STOP"
919 : ResidueProperties.aa2Triplet
920 .get(String.valueOf(residue)));
921 text.append(" Residue: ").append(name != null ? name : residue);
923 int residuePos = seqref.findPosition(column);
924 text.append(" (").append(residuePos).append(")");
929 ap.alignFrame.statusBar.setText(text.toString());
939 public void mouseClicked(MouseEvent evt)
941 // if (activeRow != -1)
943 // AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
944 // AlignmentAnnotation anot = aa[activeRow];
948 // TODO mouseClicked-content and drawCursor are quite experimental!
949 public void drawCursor(Graphics graphics, SequenceI seq, int res, int x1,
952 int pady = av.getCharHeight() / 5;
954 graphics.setColor(Color.black);
955 graphics.fillRect(x1, y1, av.getCharWidth(), av.getCharHeight());
957 if (av.validCharWidth)
959 graphics.setColor(Color.white);
961 char s = seq.getCharAt(res);
963 charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
964 graphics.drawString(String.valueOf(s), charOffset + x1,
965 (y1 + av.getCharHeight()) - pady);
970 private volatile boolean imageFresh = false;
979 public void paintComponent(Graphics g)
981 super.paintComponent(g);
983 g.setColor(Color.white);
984 g.fillRect(0, 0, getWidth(), getHeight());
988 if (fastPaint || (getVisibleRect().width != g.getClipBounds().width)
989 || (getVisibleRect().height != g.getClipBounds().height))
991 g.drawImage(image, 0, 0, this);
996 imgWidth = (av.getRanges().getEndRes() - av.getRanges().getStartRes()
997 + 1) * av.getCharWidth();
1002 if (image == null || imgWidth != image.getWidth(this)
1003 || image.getHeight(this) != getHeight())
1007 image = new BufferedImage(imgWidth,
1008 ap.getAnnotationPanel().getHeight(),
1009 BufferedImage.TYPE_INT_RGB);
1010 } catch (OutOfMemoryError oom)
1015 } catch (Exception x)
1020 "Couldn't allocate memory to redraw screen. Please restart Jalview",
1024 gg = (Graphics2D) image.getGraphics();
1028 gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
1029 RenderingHints.VALUE_ANTIALIAS_ON);
1032 gg.setFont(av.getFont());
1033 fm = gg.getFontMetrics();
1034 gg.setColor(Color.white);
1035 gg.fillRect(0, 0, imgWidth, image.getHeight());
1039 drawComponent(gg, av.getRanges().getStartRes(),
1040 av.getRanges().getEndRes() + 1);
1042 g.drawImage(image, 0, 0, this);
1046 * set true to enable redraw timing debug output on stderr
1048 private final boolean debugRedraw = false;
1051 * non-Thread safe repaint
1054 * repaint with horizontal shift in alignment
1056 public void fastPaint(int horizontal)
1058 if ((horizontal == 0) || gg == null
1059 || av.getAlignment().getAlignmentAnnotation() == null
1060 || av.getAlignment().getAlignmentAnnotation().length < 1
1061 || av.isCalcInProgress())
1067 int sr = av.getRanges().getStartRes();
1068 int er = av.getRanges().getEndRes() + 1;
1071 gg.copyArea(0, 0, imgWidth, getHeight(),
1072 -horizontal * av.getCharWidth(), 0);
1074 if (horizontal > 0) // scrollbar pulled right, image to the left
1076 transX = (er - sr - horizontal) * av.getCharWidth();
1077 sr = er - horizontal;
1079 else if (horizontal < 0)
1081 er = sr - horizontal;
1084 gg.translate(transX, 0);
1086 drawComponent(gg, sr, er);
1088 gg.translate(-transX, 0);
1092 // Call repaint on alignment panel so that repaints from other alignment
1093 // panel components can be aggregated. Otherwise performance of the overview
1094 // window and others may be adversely affected.
1095 av.getAlignPanel().repaint();
1098 private volatile boolean lastImageGood = false;
1110 public void drawComponent(Graphics g, int startRes, int endRes)
1112 BufferedImage oldFaded = fadedImage;
1113 if (av.isCalcInProgress())
1117 lastImageGood = false;
1120 // We'll keep a record of the old image,
1121 // and draw a faded image until the calculation
1124 && (fadedImage == null || fadedImage.getWidth() != imgWidth
1125 || fadedImage.getHeight() != image.getHeight()))
1127 // System.err.println("redraw faded image ("+(fadedImage==null ?
1128 // "null image" : "") + " lastGood="+lastImageGood+")");
1129 fadedImage = new BufferedImage(imgWidth, image.getHeight(),
1130 BufferedImage.TYPE_INT_RGB);
1132 Graphics2D fadedG = (Graphics2D) fadedImage.getGraphics();
1134 fadedG.setColor(Color.white);
1135 fadedG.fillRect(0, 0, imgWidth, image.getHeight());
1137 fadedG.setComposite(
1138 AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .3f));
1139 fadedG.drawImage(image, 0, 0, this);
1142 // make sure we don't overwrite the last good faded image until all
1143 // calculations have finished
1144 lastImageGood = false;
1149 if (fadedImage != null)
1151 oldFaded = fadedImage;
1156 g.setColor(Color.white);
1157 g.fillRect(0, 0, (endRes - startRes) * av.getCharWidth(), getHeight());
1159 g.setFont(av.getFont());
1162 fm = g.getFontMetrics();
1165 if ((av.getAlignment().getAlignmentAnnotation() == null)
1166 || (av.getAlignment().getAlignmentAnnotation().length < 1))
1168 g.setColor(Color.white);
1169 g.fillRect(0, 0, getWidth(), getHeight());
1170 g.setColor(Color.black);
1171 if (av.validCharWidth)
1173 g.drawString(MessageManager
1174 .getString("label.alignment_has_no_annotations"), 20, 15);
1179 lastImageGood = renderer.drawComponent(this, av, g, activeRow, startRes,
1181 if (!lastImageGood && fadedImage == null)
1183 fadedImage = oldFaded;
1188 public FontMetrics getFontMetrics()
1194 public Image getFadedImage()
1200 public int getFadedImageWidth()
1205 private int[] bounds = new int[2];
1208 public int[] getVisibleVRange()
1210 if (ap != null && ap.getAlabels() != null)
1212 int sOffset = -ap.getAlabels().getScrollOffset();
1213 int visHeight = sOffset + ap.annotationSpaceFillerHolder.getHeight();
1214 bounds[0] = sOffset;
1215 bounds[1] = visHeight;
1225 * Try to ensure any references held are nulled
1227 public void dispose()
1237 * I created the renderer so I will dispose of it
1239 if (renderer != null)
1246 public void propertyChange(PropertyChangeEvent evt)
1248 // Respond to viewport range changes (e.g. alignment panel was scrolled)
1249 // Both scrolling and resizing change viewport ranges: scrolling changes
1250 // both start and end points, but resize only changes end values.
1251 // Here we only want to fastpaint on a scroll, with resize using a normal
1252 // paint, so scroll events are identified as changes to the horizontal or
1253 // vertical start value.
1254 if (evt.getPropertyName().equals(ViewportRanges.STARTRES))
1256 fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
1258 else if (evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ))
1260 fastPaint(((int[]) evt.getNewValue())[0]
1261 - ((int[]) evt.getOldValue())[0]);
1263 else if (evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT))