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.AlignmentI;
25 import jalview.datamodel.Annotation;
26 import jalview.datamodel.ColumnSelection;
27 import jalview.datamodel.HiddenColumns;
28 import jalview.datamodel.SequenceI;
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.util.Platform;
35 import jalview.viewmodel.ViewportListenerI;
36 import jalview.viewmodel.ViewportRanges;
38 import java.awt.AlphaComposite;
39 import java.awt.Color;
40 import java.awt.Dimension;
41 import java.awt.FontMetrics;
42 import java.awt.Graphics;
43 import java.awt.Graphics2D;
44 import java.awt.Image;
45 import java.awt.Rectangle;
46 import java.awt.RenderingHints;
47 import java.awt.event.ActionEvent;
48 import java.awt.event.ActionListener;
49 import java.awt.event.AdjustmentEvent;
50 import java.awt.event.AdjustmentListener;
51 import java.awt.event.MouseEvent;
52 import java.awt.event.MouseListener;
53 import java.awt.event.MouseMotionListener;
54 import java.awt.event.MouseWheelEvent;
55 import java.awt.event.MouseWheelListener;
56 import java.awt.image.BufferedImage;
57 import java.beans.PropertyChangeEvent;
58 import java.util.ArrayList;
59 import java.util.Collections;
60 import java.util.List;
62 import javax.swing.JColorChooser;
63 import javax.swing.JMenuItem;
64 import javax.swing.JPanel;
65 import javax.swing.JPopupMenu;
66 import javax.swing.Scrollable;
67 import javax.swing.ToolTipManager;
70 * AnnotationPanel displays visible portion of annotation rows below unwrapped
76 public class AnnotationPanel extends JPanel implements AwtRenderPanelI,
77 MouseListener, MouseWheelListener, MouseMotionListener,
78 ActionListener, AdjustmentListener, Scrollable, ViewportListenerI
82 Select, Resize, Undefined
85 String HELIX = MessageManager.getString("label.helix");
87 String SHEET = MessageManager.getString("label.sheet");
90 * For RNA secondary structure "stems" aka helices
92 String STEM = MessageManager.getString("label.rna_helix");
94 String LABEL = MessageManager.getString("label.label");
96 String REMOVE = MessageManager.getString("label.remove_annotation");
98 String COLOUR = MessageManager.getString("action.colour");
100 public final Color HELIX_COLOUR = Color.red.darker();
102 public final Color SHEET_COLOUR = Color.green.darker().darker();
104 public final Color STEM_COLOUR = Color.blue.darker();
107 public AlignViewport av;
111 public int activeRow = -1;
113 public BufferedImage image;
115 public volatile BufferedImage fadedImage;
119 public FontMetrics fm;
121 public int imgWidth = 0;
123 boolean fastPaint = false;
125 // Used For mouse Dragging and resizing graphs
126 int graphStretch = -1;
128 int mouseDragLastX = -1;
130 int mouseDragLastY = -1;
132 DragMode dragMode = DragMode.Undefined;
134 boolean mouseDragging = false;
136 // for editing cursor
141 public final AnnotationRenderer renderer;
143 private MouseWheelListener[] _mwl;
146 * Creates a new AnnotationPanel object.
151 public AnnotationPanel(AlignmentPanel ap)
153 ToolTipManager.sharedInstance().registerComponent(this);
154 ToolTipManager.sharedInstance().setInitialDelay(0);
155 ToolTipManager.sharedInstance().setDismissDelay(10000);
158 this.setLayout(null);
159 addMouseListener(this);
160 addMouseMotionListener(this);
161 ap.annotationScroller.getVerticalScrollBar()
162 .addAdjustmentListener(this);
163 // save any wheel listeners on the scroller, so we can propagate scroll
165 _mwl = ap.annotationScroller.getMouseWheelListeners();
166 // and then set our own listener to consume all mousewheel events
167 ap.annotationScroller.addMouseWheelListener(this);
168 renderer = new AnnotationRenderer();
170 av.getRanges().addPropertyChangeListener(this);
173 public AnnotationPanel(AlignViewport av)
176 renderer = new AnnotationRenderer();
180 public void mouseWheelMoved(MouseWheelEvent e)
185 double wheelRotation = e.getPreciseWheelRotation();
186 if (wheelRotation > 0)
188 av.getRanges().scrollRight(true);
190 else if (wheelRotation < 0)
192 av.getRanges().scrollRight(false);
197 // TODO: find the correct way to let the event bubble up to
198 // ap.annotationScroller
199 for (MouseWheelListener mwl : _mwl)
203 mwl.mouseWheelMoved(e);
214 public Dimension getPreferredScrollableViewportSize()
216 Dimension ps = getPreferredSize();
217 return new Dimension(ps.width, adjustForAlignFrame(false, ps.height));
221 public int getScrollableBlockIncrement(Rectangle visibleRect,
222 int orientation, int direction)
228 public boolean getScrollableTracksViewportHeight()
234 public boolean getScrollableTracksViewportWidth()
240 public int getScrollableUnitIncrement(Rectangle visibleRect,
241 int orientation, int direction)
250 * java.awt.event.AdjustmentListener#adjustmentValueChanged(java.awt.event
254 public void adjustmentValueChanged(AdjustmentEvent evt)
256 // update annotation label display
257 ap.getAlabels().setScrollOffset(-evt.getValue());
261 * Calculates the height of the annotation displayed in the annotation panel.
262 * Callers should normally call the ap.adjustAnnotationHeight method to ensure
263 * all annotation associated components are updated correctly.
266 public int adjustPanelHeight()
268 int height = av.calcPanelHeight();
269 this.setPreferredSize(new Dimension(1, height));
272 // revalidate only when the alignment panel is fully constructed
286 public void actionPerformed(ActionEvent evt)
288 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
293 Annotation[] anot = aa[activeRow].annotations;
295 if (anot.length < av.getColumnSelection().getMax())
297 Annotation[] temp = new Annotation[av.getColumnSelection().getMax()
299 System.arraycopy(anot, 0, temp, 0, anot.length);
301 aa[activeRow].annotations = anot;
304 String action = evt.getActionCommand();
305 if (action.equals(REMOVE))
307 for (int index : av.getColumnSelection().getSelected())
309 if (av.getAlignment().getHiddenColumns().isVisible(index))
315 else if (action.equals(LABEL))
317 String exMesg = collectAnnotVals(anot, LABEL);
318 String label = JvOptionPane.showInputDialog(this,
319 MessageManager.getString("label.enter_label"), exMesg);
326 if ((label.length() > 0) && !aa[activeRow].hasText)
328 aa[activeRow].hasText = true;
331 for (int index : av.getColumnSelection().getSelected())
333 if (!av.getAlignment().getHiddenColumns().isVisible(index))
338 if (anot[index] == null)
340 anot[index] = new Annotation(label, "", ' ', 0);
344 anot[index].displayCharacter = label;
348 else if (action.equals(COLOUR))
350 Color col = JColorChooser.showDialog(this,
351 MessageManager.getString("label.select_foreground_colour"),
354 for (int index : av.getColumnSelection().getSelected())
356 if (!av.getAlignment().getHiddenColumns().isVisible(index))
361 if (anot[index] == null)
363 anot[index] = new Annotation("", "", ' ', 0);
366 anot[index].colour = col;
370 // HELIX, SHEET or STEM
373 String symbol = "\u03B1"; // alpha
375 if (action.equals(HELIX))
379 else if (action.equals(SHEET))
382 symbol = "\u03B2"; // beta
385 // Added by LML to color stems
386 else if (action.equals(STEM))
389 int column = av.getColumnSelection().getSelectedRanges().get(0)[0];
390 symbol = aa[activeRow].getDefaultRnaHelixSymbol(column);
393 if (!aa[activeRow].hasIcons)
395 aa[activeRow].hasIcons = true;
398 String label = JvOptionPane.showInputDialog(MessageManager
399 .getString("label.enter_label_for_the_structure"), symbol);
406 if ((label.length() > 0) && !aa[activeRow].hasText)
408 aa[activeRow].hasText = true;
409 if (action.equals(STEM))
411 aa[activeRow].showAllColLabels = true;
414 for (int index : av.getColumnSelection().getSelected())
416 if (!av.getAlignment().getHiddenColumns().isVisible(index))
421 if (anot[index] == null)
423 anot[index] = new Annotation(label, "", type, 0);
426 anot[index].secondaryStructure = type != 'S' ? type
427 : label.length() == 0 ? ' ' : label.charAt(0);
428 anot[index].displayCharacter = label;
433 av.getAlignment().validateAnnotation(aa[activeRow]);
434 ap.alignmentChanged();
435 ap.alignFrame.setMenusForViewport();
443 * Returns any existing annotation concatenated as a string. For each
444 * annotation, takes the description, if any, else the secondary structure
445 * character (if type is HELIX, SHEET or STEM), else the display character (if
452 private String collectAnnotVals(Annotation[] anots, String type)
454 // TODO is this method wanted? why? 'last' is not used
456 StringBuilder collatedInput = new StringBuilder(64);
458 ColumnSelection viscols = av.getColumnSelection();
459 HiddenColumns hidden = av.getAlignment().getHiddenColumns();
462 * the selection list (read-only view) is in selection order, not
463 * column order; make a copy so we can sort it
465 List<Integer> selected = new ArrayList<>(viscols.getSelected());
466 Collections.sort(selected);
467 for (int index : selected)
469 // always check for current display state - just in case
470 if (!hidden.isVisible(index))
474 String tlabel = null;
475 if (anots[index] != null)
476 { // LML added stem code
477 if (type.equals(HELIX) || type.equals(SHEET) || type.equals(STEM)
478 || type.equals(LABEL))
480 tlabel = anots[index].description;
481 if (tlabel == null || tlabel.length() < 1)
483 if (type.equals(HELIX) || type.equals(SHEET)
484 || type.equals(STEM))
486 tlabel = "" + anots[index].secondaryStructure;
490 tlabel = "" + anots[index].displayCharacter;
494 if (tlabel != null && !tlabel.equals(last))
496 if (last.length() > 0)
498 collatedInput.append(" ");
500 collatedInput.append(tlabel);
504 return collatedInput.toString();
508 * Action on right mouse pressed on Mac is to show a pop-up menu for the
509 * annotation. Action on left mouse pressed is to find which annotation is
510 * pressed and mark the start of a column selection or graph resize operation.
515 public void mousePressed(MouseEvent evt)
518 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
523 mouseDragLastX = evt.getX();
524 mouseDragLastY = evt.getY();
527 * add visible annotation heights until we reach the y
528 * position, to find which annotation it is in
533 final int y = evt.getY();
534 for (int i = 0; i < aa.length; i++)
538 height += aa[i].height;
547 else if (aa[i].graph > 0)
550 * we have clicked on a resizable graph annotation
559 * isPopupTrigger fires in mousePressed on Mac,
560 * not until mouseRelease on Windows
562 if (evt.isPopupTrigger() && activeRow != -1)
564 showPopupMenu(y, evt.getX());
568 ap.getScalePanel().mousePressed(evt);
572 * Construct and display a context menu at the right-click position
577 void showPopupMenu(final int y, int x)
579 if (av.getColumnSelection() == null
580 || av.getColumnSelection().isEmpty())
585 JPopupMenu pop = new JPopupMenu(
586 MessageManager.getString("label.structure_type"));
589 * Just display the needed structure options
591 if (av.getAlignment().isNucleotide())
593 item = new JMenuItem(STEM);
594 item.addActionListener(this);
599 item = new JMenuItem(HELIX);
600 item.addActionListener(this);
602 item = new JMenuItem(SHEET);
603 item.addActionListener(this);
606 item = new JMenuItem(LABEL);
607 item.addActionListener(this);
609 item = new JMenuItem(COLOUR);
610 item.addActionListener(this);
612 item = new JMenuItem(REMOVE);
613 item.addActionListener(this);
615 pop.show(this, x, y);
619 * Action on mouse up is to clear mouse drag data and call mouseReleased on
620 * ScalePanel, to deal with defining the selection group (if any) defined by
626 public void mouseReleased(MouseEvent evt)
631 mouseDragging = false;
632 dragMode = DragMode.Undefined;
633 ap.getScalePanel().mouseReleased(evt);
636 * isPopupTrigger is set in mouseReleased on Windows
637 * (in mousePressed on Mac)
639 if (evt.isPopupTrigger() && activeRow != -1)
641 showPopupMenu(evt.getY(), evt.getX());
653 public void mouseEntered(MouseEvent evt)
655 ap.getScalePanel().mouseEntered(evt);
665 public void mouseExited(MouseEvent evt)
667 ap.getScalePanel().mouseExited(evt);
677 public void mouseDragged(MouseEvent evt)
680 * todo: if dragMode is Undefined:
681 * - set to Select if dx > dy
682 * - set to Resize if dy > dx
683 * - do nothing if dx == dy
685 final int x = evt.getX();
686 final int y = evt.getY();
687 if (dragMode == DragMode.Undefined)
689 int dx = Math.abs(x - mouseDragLastX);
690 int dy = Math.abs(y - mouseDragLastY);
691 if (graphStretch == -1 || dx > dy)
694 * mostly horizontal drag, or not a graph annotation
696 dragMode = DragMode.Select;
701 * mostly vertical drag
703 dragMode = DragMode.Resize;
707 if (dragMode == DragMode.Undefined)
710 * drag is diagonal - defer deciding whether to
711 * treat as up/down or left/right
718 if (dragMode == DragMode.Resize)
721 * resize graph annotation if mouse was dragged up or down
723 int deltaY = mouseDragLastY - evt.getY();
726 AlignmentAnnotation graphAnnotation = av.getAlignment()
727 .getAlignmentAnnotation()[graphStretch];
728 int newHeight = Math.max(0, graphAnnotation.graphHeight + deltaY);
729 graphAnnotation.graphHeight = newHeight;
731 ap.paintAlignment(false, false);
737 * for mouse drag left or right, delegate to
738 * ScalePanel to adjust the column selection
740 ap.getScalePanel().mouseDragged(evt);
750 * Constructs the tooltip, and constructs and displays a status message, for
751 * the current mouse position
756 public void mouseMoved(MouseEvent evt)
758 int yPos = evt.getY();
759 AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
761 int row = getRowIndex(yPos, aa);
765 this.setToolTipText(null);
768 int column = av.getAbsoluteColumn(evt.getX());
770 AlignmentAnnotation ann = aa[row];
771 if (row > -1 && ann.annotations != null
772 && column < ann.annotations.length)
774 setToolTipText(buildToolTip(ann, column, aa));
775 String msg = getStatusMessage(av.getAlignment(), column, ann);
776 ap.alignFrame.setStatus(msg);
780 this.setToolTipText(null);
781 ap.alignFrame.setStatus(" ");
786 * Answers the index in the annotations array of the visible annotation at the
787 * given y position. This is done by adding the heights of visible annotations
788 * until the y position has been exceeded. Answers -1 if no annotations are
789 * visible, or the y position is below all annotations.
795 static int getRowIndex(int yPos, AlignmentAnnotation[] aa)
804 for (int i = 0; i < aa.length; i++)
808 height += aa[i].height;
821 * Answers a tooltip for the annotation at the current mouse position
827 static String buildToolTip(AlignmentAnnotation ann, int column,
828 AlignmentAnnotation[] anns)
830 String tooltip = null;
831 if (ann.graphGroup > -1)
833 StringBuilder tip = new StringBuilder(32);
834 tip.append("<html>");
835 for (int i = 0; i < anns.length; i++)
837 if (anns[i].graphGroup == ann.graphGroup
838 && anns[i].annotations[column] != null)
840 tip.append(anns[i].label);
841 String description = anns[i].annotations[column].description;
842 if (description != null && description.length() > 0)
844 tip.append(" ").append(description);
849 if (tip.length() != 6)
851 tip.setLength(tip.length() - 4);
852 tooltip = tip.toString() + "</html>";
855 else if (column < ann.annotations.length
856 && ann.annotations[column] != null)
858 String description = ann.annotations[column].description;
859 if (description != null && description.length() > 0)
861 tooltip = JvSwingUtils.wrapTooltip(true, description);
865 tooltip = null; // no tooltip if null or empty description
870 // clear the tooltip.
877 * Constructs and returns the status bar message
883 static String getStatusMessage(AlignmentI al, int column,
884 AlignmentAnnotation ann)
887 * show alignment column and annotation description if any
889 StringBuilder text = new StringBuilder(32);
890 text.append(MessageManager.getString("label.column")).append(" ")
893 if (column < ann.annotations.length && ann.annotations[column] != null)
895 String description = ann.annotations[column].description;
896 if (description != null && description.trim().length() > 0)
898 text.append(" ").append(description);
903 * if the annotation is sequence-specific, show the sequence number
904 * in the alignment, and (if not a gap) the residue and position
906 SequenceI seqref = ann.sequenceRef;
909 int seqIndex = al.findIndex(seqref);
912 text.append(", ").append(MessageManager.getString("label.sequence"))
913 .append(" ").append(seqIndex + 1);
914 char residue = seqref.getCharAt(column);
915 if (!Comparison.isGap(residue))
919 if (al.isNucleotide())
921 name = ResidueProperties.nucleotideName
922 .get(String.valueOf(residue));
923 text.append(" Nucleotide: ")
924 .append(name != null ? name : residue);
928 name = 'X' == residue ? "X"
929 : ('*' == residue ? "STOP"
930 : ResidueProperties.aa2Triplet
931 .get(String.valueOf(residue)));
932 text.append(" Residue: ").append(name != null ? name : residue);
934 int residuePos = seqref.findPosition(column);
935 text.append(" (").append(residuePos).append(")");
940 return text.toString();
950 public void mouseClicked(MouseEvent evt)
952 // if (activeRow != -1)
954 // AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
955 // AlignmentAnnotation anot = aa[activeRow];
959 // TODO mouseClicked-content and drawCursor are quite experimental!
960 public void drawCursor(Graphics graphics, SequenceI seq, int res, int x1,
963 int pady = av.getCharHeight() / 5;
965 graphics.setColor(Color.black);
966 graphics.fillRect(x1, y1, av.getCharWidth(), av.getCharHeight());
968 if (av.validCharWidth)
970 graphics.setColor(Color.white);
972 char s = seq.getCharAt(res);
974 charOffset = (av.getCharWidth() - fm.charWidth(s)) / 2;
975 graphics.drawString(String.valueOf(s), charOffset + x1,
976 (y1 + av.getCharHeight()) - pady);
981 private volatile boolean imageFresh = false;
990 public void paintComponent(Graphics g)
992 super.paintComponent(g);
994 g.setColor(Color.white);
995 g.fillRect(0, 0, getWidth(), getHeight());
999 if (fastPaint || (getVisibleRect().width != g.getClipBounds().width)
1000 || (getVisibleRect().height != g.getClipBounds().height))
1002 g.drawImage(image, 0, 0, this);
1007 imgWidth = (av.getRanges().getEndRes() - av.getRanges().getStartRes()
1008 + 1) * av.getCharWidth();
1013 if (image == null || imgWidth != image.getWidth(this)
1014 || image.getHeight(this) != getHeight())
1018 image = new BufferedImage(imgWidth,
1019 ap.getAnnotationPanel().getHeight(),
1020 BufferedImage.TYPE_INT_RGB);
1021 } catch (OutOfMemoryError oom)
1026 } catch (Exception x)
1031 "Couldn't allocate memory to redraw screen. Please restart Jalview",
1035 gg = (Graphics2D) image.getGraphics();
1039 gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
1040 RenderingHints.VALUE_ANTIALIAS_ON);
1043 gg.setFont(av.getFont());
1044 fm = gg.getFontMetrics();
1045 gg.setColor(Color.white);
1046 gg.fillRect(0, 0, imgWidth, image.getHeight());
1050 drawComponent(gg, av.getRanges().getStartRes(),
1051 av.getRanges().getEndRes() + 1);
1053 g.drawImage(image, 0, 0, this);
1057 * set true to enable redraw timing debug output on stderr
1059 private final boolean debugRedraw = false;
1062 * non-Thread safe repaint
1065 * repaint with horizontal shift in alignment
1067 public void fastPaint(int horizontal)
1069 if ((horizontal == 0) || gg == null
1070 || av.getAlignment().getAlignmentAnnotation() == null
1071 || av.getAlignment().getAlignmentAnnotation().length < 1
1072 || av.isCalcInProgress())
1078 int sr = av.getRanges().getStartRes();
1079 int er = av.getRanges().getEndRes() + 1;
1082 gg.copyArea(0, 0, imgWidth, getHeight(),
1083 -horizontal * av.getCharWidth(), 0);
1085 if (horizontal > 0) // scrollbar pulled right, image to the left
1087 transX = (er - sr - horizontal) * av.getCharWidth();
1088 sr = er - horizontal;
1090 else if (horizontal < 0)
1092 er = sr - horizontal;
1095 gg.translate(transX, 0);
1097 drawComponent(gg, sr, er);
1099 gg.translate(-transX, 0);
1103 // Call repaint on alignment panel so that repaints from other alignment
1104 // panel components can be aggregated. Otherwise performance of the overview
1105 // window and others may be adversely affected.
1106 av.getAlignPanel().repaint();
1109 private volatile boolean lastImageGood = false;
1121 public void drawComponent(Graphics g, int startRes, int endRes)
1123 BufferedImage oldFaded = fadedImage;
1124 if (av.isCalcInProgress())
1128 lastImageGood = false;
1131 // We'll keep a record of the old image,
1132 // and draw a faded image until the calculation
1135 && (fadedImage == null || fadedImage.getWidth() != imgWidth
1136 || fadedImage.getHeight() != image.getHeight()))
1138 // System.err.println("redraw faded image ("+(fadedImage==null ?
1139 // "null image" : "") + " lastGood="+lastImageGood+")");
1140 fadedImage = new BufferedImage(imgWidth, image.getHeight(),
1141 BufferedImage.TYPE_INT_RGB);
1143 Graphics2D fadedG = (Graphics2D) fadedImage.getGraphics();
1145 fadedG.setColor(Color.white);
1146 fadedG.fillRect(0, 0, imgWidth, image.getHeight());
1148 fadedG.setComposite(
1149 AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .3f));
1150 fadedG.drawImage(image, 0, 0, this);
1153 // make sure we don't overwrite the last good faded image until all
1154 // calculations have finished
1155 lastImageGood = false;
1160 if (fadedImage != null)
1162 oldFaded = fadedImage;
1167 g.setColor(Color.white);
1168 g.fillRect(0, 0, (endRes - startRes) * av.getCharWidth(), getHeight());
1170 g.setFont(av.getFont());
1173 fm = g.getFontMetrics();
1176 if ((av.getAlignment().getAlignmentAnnotation() == null)
1177 || (av.getAlignment().getAlignmentAnnotation().length < 1))
1179 g.setColor(Color.white);
1180 g.fillRect(0, 0, getWidth(), getHeight());
1181 g.setColor(Color.black);
1182 if (av.validCharWidth)
1184 g.drawString(MessageManager
1185 .getString("label.alignment_has_no_annotations"), 20, 15);
1190 lastImageGood = renderer.drawComponent(this, av, g, activeRow, startRes,
1192 if (!lastImageGood && fadedImage == null)
1194 fadedImage = oldFaded;
1199 public FontMetrics getFontMetrics()
1205 public Image getFadedImage()
1211 public int getFadedImageWidth()
1216 private int[] bounds = new int[2];
1219 public int[] getVisibleVRange()
1221 if (ap != null && ap.getAlabels() != null)
1223 int sOffset = -ap.getAlabels().getScrollOffset();
1224 int visHeight = sOffset + ap.annotationSpaceFillerHolder.getHeight();
1225 bounds[0] = sOffset;
1226 bounds[1] = visHeight;
1236 * Try to ensure any references held are nulled
1238 public void dispose()
1248 * I created the renderer so I will dispose of it
1250 if (renderer != null)
1257 public void propertyChange(PropertyChangeEvent evt)
1259 // Respond to viewport range changes (e.g. alignment panel was scrolled)
1260 // Both scrolling and resizing change viewport ranges: scrolling changes
1261 // both start and end points, but resize only changes end values.
1262 // Here we only want to fastpaint on a scroll, with resize using a normal
1263 // paint, so scroll events are identified as changes to the horizontal or
1264 // vertical start value.
1265 if (evt.getPropertyName().equals(ViewportRanges.STARTRES))
1267 fastPaint((int) evt.getNewValue() - (int) evt.getOldValue());
1269 else if (evt.getPropertyName().equals(ViewportRanges.STARTRESANDSEQ))
1271 fastPaint(((int[]) evt.getNewValue())[0]
1272 - ((int[]) evt.getOldValue())[0]);
1274 else if (evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT))
1281 * computes the visible height of the annotation panel
1283 * @param adjustPanelHeight
1284 * - when false, just adjust existing height according to other
1286 * @param annotationHeight
1287 * @return height to use for the ScrollerPreferredVisibleSize
1289 public int adjustForAlignFrame(boolean adjustPanelHeight,
1290 int annotationHeight)
1293 * Estimate available height in the AlignFrame for alignment +
1294 * annotations. Deduct an estimate for title bar, menu bar, scale panel,
1295 * hscroll, status bar, insets.
1297 int stuff = (ap.getViewName() != null ? 30 : 0)
1298 + (Platform.isAMac() ? 120 : 140);
1299 int availableHeight = ap.alignFrame.getHeight() - stuff;
1300 int rowHeight = av.getCharHeight();
1302 if (adjustPanelHeight)
1304 int alignmentHeight = rowHeight * av.getAlignment().getHeight();
1307 * If not enough vertical space, maximize annotation height while keeping
1308 * at least two rows of alignment visible
1310 if (annotationHeight + alignmentHeight > availableHeight)
1312 annotationHeight = Math.min(annotationHeight,
1313 availableHeight - 2 * rowHeight);
1318 // maintain same window layout whilst updating sliders
1319 annotationHeight = Math.min(ap.annotationScroller.getSize().height,
1320 availableHeight - 2 * rowHeight);
1322 return annotationHeight;