X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSeqCanvas.java;h=d110e659c29f6eb7a97729de1217d20c0d13ecc2;hb=afe4b88500a5d61bc8d312909cfdde2b7cdd53df;hp=36ec08f1b0dfb2f5e876a203d5fb32d2cdaf60b2;hpb=b1beceda238e50719ad3ea28c02ae4ffab265b59;p=jalview.git diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 36ec08f..d110e65 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -20,31 +20,33 @@ */ package jalview.gui; -import jalview.datamodel.AlignmentI; -import jalview.datamodel.HiddenColumns; -import jalview.datamodel.SearchResultsI; -import jalview.datamodel.SequenceGroup; -import jalview.datamodel.SequenceI; -import jalview.renderer.ScaleRenderer; -import jalview.renderer.ScaleRenderer.ScaleMark; -import jalview.util.Comparison; -import jalview.viewmodel.ViewportListenerI; -import jalview.viewmodel.ViewportRanges; - -import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Rectangle; import java.awt.RenderingHints; -import java.awt.Shape; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; +import java.util.Iterator; import java.util.List; -import javax.swing.JComponent; +import javax.swing.JPanel; + +import jalview.api.SequenceRenderer; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.SearchResultsI; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.datamodel.VisibleContigsIterator; +import jalview.renderer.ScaleRenderer; +import jalview.renderer.ScaleRenderer.ScaleMark; +import jalview.util.Comparison; +import jalview.viewmodel.ViewportListenerI; +import jalview.viewmodel.ViewportRanges; /** * The Swing component on which the alignment sequences, and annotations (if @@ -52,8 +54,15 @@ import javax.swing.JComponent; * Wrapped mode, but not the scale above in Unwrapped mode. * */ -public class SeqCanvas extends JComponent implements ViewportListenerI +@SuppressWarnings("serial") +public class SeqCanvas extends JPanel implements ViewportListenerI { + /** + * vertical gap in pixels between sequences and annotations when in wrapped + * mode + */ + static final int SEQS_ANNOTATION_GAP = 3; + private static final String ZEROS = "0000000000"; final FeatureRenderer fr; @@ -68,7 +77,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI private final SequenceRenderer seqRdr; - private boolean fastPaint = false; + boolean fastPaint = false; private boolean fastpainting = false; @@ -81,13 +90,14 @@ public class SeqCanvas extends JComponent implements ViewportListenerI private int labelWidthWest; // label left width in pixels if shown - private int wrappedSpaceAboveAlignment; // gap between widths + int wrappedSpaceAboveAlignment; // gap between widths - private int wrappedRepeatHeightPx; // height in pixels of wrapped width + int wrappedRepeatHeightPx; // height in pixels of wrapped width private int wrappedVisibleWidths; // number of wrapped widths displayed - private Graphics2D gg; + // Don't do this! Graphics handles are supposed to be transient + // private Graphics2D gg; /** * Creates a new SeqCanvas object. @@ -98,7 +108,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { this.av = ap.av; fr = new FeatureRenderer(ap); - seqRdr = new SequenceRenderer(av); + seqRdr = new jalview.gui.SequenceRenderer(av); setLayout(new BorderLayout()); PaintRefresher.Register(this, av.getSequenceSetId()); setBackground(Color.white); @@ -198,8 +208,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns(); - startX = hiddenColumns.adjustForHiddenColumns(startx); - endX = hiddenColumns.adjustForHiddenColumns(endx); + startX = hiddenColumns.visibleToAbsoluteColumn(startx); + endX = hiddenColumns.visibleToAbsoluteColumn(endx); } FontMetrics fm = getFontMetrics(av.getFont()); @@ -254,6 +264,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI g.drawString(valueAsString, xOffset, y); } } + } /** @@ -267,6 +278,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI *
- * Currently fastPaint is not implemented for wrapped alignments. If a wrapped - * alignment had to be scrolled to show the highlighted region, then it should - * be fully redrawn, otherwise a fast paint can be performed. This argument - * could be removed if fast paint of scrolled wrapped alignment is coded in - * future (JAL-2609). + * Optionally, set the 'fastPaint' flag for a faster redraw if only the + * highlighted regions are modified. This speeds up highlighting across linked + * alignments. + *
+ * Currently fastPaint is not implemented for scrolled wrapped alignments. If + * a wrapped alignment had to be scrolled to show the highlighted region, then + * it should be fully redrawn, otherwise a fast paint can be performed. This + * argument could be removed if fast paint of scrolled wrapped alignment is + * coded in future (JAL-2609). * * @param results - * @param noFastPaint + * @param doFastPaint + * if true, sets a flag so the next repaint only redraws the modified + * image * @return */ public boolean highlightSearchResults(SearchResultsI results, - boolean noFastPaint) + boolean doFastPaint) { if (fastpainting) { @@ -1519,7 +1554,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI boolean wrapped = av.getWrapAlignment(); try { - fastPaint = !noFastPaint; + fastPaint = doFastPaint; fastpainting = fastPaint; /* @@ -1576,7 +1611,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ protected boolean drawMappedPositions(SearchResultsI results) { - if (results == null) + if ((results == null) || (img == null)) // JAL-2784 check gg is not null { return false; } @@ -1598,9 +1633,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { firstVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(firstVisibleColumn); + .visibleToAbsoluteColumn(firstVisibleColumn); lastVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(lastVisibleColumn); + .visibleToAbsoluteColumn(lastVisibleColumn); } for (int seqNo = ranges.getStartSeq(); seqNo <= ranges @@ -1643,14 +1678,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { firstCol = alignment.getHiddenColumns() - .findColumnPosition(firstCol); - lastCol = alignment.getHiddenColumns().findColumnPosition(lastCol); + .absoluteToVisibleColumn(firstCol); + lastCol = alignment.getHiddenColumns() + .absoluteToVisibleColumn(lastCol); } int transX = (firstCol - ranges.getStartRes()) * av.getCharWidth(); int transY = (firstSeq - ranges.getStartSeq()) * av.getCharHeight(); + Graphics gg = img.getGraphics(); gg.translate(transX, transY); - drawPanel(gg, firstCol, lastCol, firstSeq, lastSeq, 0); + drawPanel(seqRdr, gg, firstCol, lastCol, firstSeq, lastSeq, 0); gg.translate(-transX, -transY); + gg.dispose(); } return matchFound; @@ -1660,13 +1698,22 @@ public class SeqCanvas extends JComponent implements ViewportListenerI public void propertyChange(PropertyChangeEvent evt) { String eventName = evt.getPropertyName(); - + // jalview.bin.Console.errPrintln(">>SeqCanvas propertyChange " + + // eventName); if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED)) { fastPaint = true; repaint(); return; } + else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT)) + { + fastPaint = false; + // jalview.bin.Console.errPrintln("!!!! fastPaint false from + // MOVE_VIEWPORT"); + repaint(); + return; + } int scrollX = 0; if (eventName.equals(ViewportRanges.STARTRES) @@ -1685,7 +1732,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } ViewportRanges vpRanges = av.getRanges(); - int range = vpRanges.getEndRes() - vpRanges.getStartRes(); + int range = vpRanges.getEndRes() - vpRanges.getStartRes() + 1; if (scrollX > range) { scrollX = range; @@ -1695,7 +1742,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI scrollX = -range; } } - // Both scrolling and resizing change viewport ranges: scrolling changes // both start and end points, but resize only changes end values. // Here we only want to fastpaint on a scroll, with resize using a normal @@ -1719,11 +1765,26 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) { - fastPaint(scrollX, 0); - // bizarrely, we only need to scroll on the x value here as fastpaint - // copies the full height of the image anyway. Passing in the y value - // causes nasty repaint artefacts, which only disappear on a full - // repaint. + if (av.getWrapAlignment()) + { + fastPaintWrapped(scrollX); + } + else + { + fastPaint(scrollX, 0); + } + } + else if (eventName.equals(ViewportRanges.STARTSEQ)) + { + // scroll + fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); + } + else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) + { + if (av.getWrapAlignment()) + { + fastPaintWrapped(scrollX); + } } } @@ -1740,10 +1801,10 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { ViewportRanges ranges = av.getRanges(); - if (Math.abs(scrollX) > ranges.getViewportWidth()) + if (Math.abs(scrollX) >= ranges.getViewportWidth()) { /* - * shift of more than one view width is + * shift of one view width or more is * overcomplicated to handle in this method */ fastPaint = false; @@ -1751,7 +1812,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI return; } - if (fastpainting || gg == null) + if (fastpainting || img == null) { return; } @@ -1761,6 +1822,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI try { + + Graphics gg = img.getGraphics(); + calculateWrappedGeometry(getWidth(), getHeight()); /* @@ -1776,8 +1840,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (scrollX < 0) { int startRes = ranges.getStartRes(); - drawWrappedWidth(gg, wrappedSpaceAboveAlignment, startRes, startRes - - scrollX - 1, getHeight()); + drawWrappedWidth(seqRdr, gg, wrappedSpaceAboveAlignment, startRes, + startRes - scrollX - 1, getHeight()); } else { @@ -1789,6 +1853,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ drawWrappedDecorators(gg, ranges.getStartRes()); + gg.dispose(); + repaint(); } finally { @@ -1812,6 +1878,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI return; } + Graphics gg = img.getGraphics(); + ViewportRanges ranges = av.getRanges(); int viewportWidth = ranges.getViewportWidth(); int charWidth = av.getCharWidth(); @@ -1822,7 +1890,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ int visibleWidths = wrappedVisibleWidths; int canvasHeight = getHeight(); - boolean lastWidthPartHeight = (wrappedVisibleWidths * wrappedRepeatHeightPx) > canvasHeight; + boolean lastWidthPartHeight = (wrappedVisibleWidths + * wrappedRepeatHeightPx) > canvasHeight; if (lastWidthPartHeight) { @@ -1838,13 +1907,15 @@ public class SeqCanvas extends JComponent implements ViewportListenerI /* * white fill first to erase annotations */ + gg.translate(xOffset, 0); gg.setColor(Color.white); - gg.fillRect(labelWidthWest, ypos, - (endRes - startRes + 1) * charWidth, wrappedRepeatHeightPx); + gg.fillRect(labelWidthWest, ypos, (endRes - startRes + 1) * charWidth, + wrappedRepeatHeightPx); gg.translate(-xOffset, 0); - drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight); + drawWrappedWidth(seqRdr, gg, ypos, startRes, endRes, canvasHeight); + } /* @@ -1876,7 +1947,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (startRes < ranges.getVisibleAlignmentWidth()) { - drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight); + drawWrappedWidth(seqRdr, gg, ypos, startRes, endRes, canvasHeight); } /* @@ -1888,6 +1959,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI gg.setColor(Color.white); gg.fillRect(0, canvasHeight - heightBelow, getWidth(), heightBelow); } + gg.dispose(); } /** @@ -1904,6 +1976,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { return; } + + Graphics gg = img.getGraphics(); + int charWidth = av.getCharWidth(); int canvasHeight = getHeight(); @@ -1934,10 +2009,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI while (y >= 0) { + /* + * shift 'widthToCopy' residues by 'positions' places to the right + */ gg.copyArea(copyFromLeftStart, y, widthToCopy, heightToCopy, positions * charWidth, 0); if (y > 0) { + /* + * copy 'positions' residue from the row above (right hand end) + * to this row's left hand end + */ gg.copyArea(copyFromRightStart, y - wrappedRepeatHeightPx, positions * charWidth, heightToCopy, -widthToCopy, wrappedRepeatHeightPx); @@ -1966,18 +2048,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (y + wrappedRepeatHeightPx < canvasHeight - wrappedRepeatHeightPx && (xpos + viewportWidth <= xMax)) { - gg.copyArea(labelWidthWest, y + wrappedRepeatHeightPx, -positions - * charWidth, heightToCopy, widthToCopy, + gg.copyArea(labelWidthWest, y + wrappedRepeatHeightPx, + -positions * charWidth, heightToCopy, widthToCopy, -wrappedRepeatHeightPx); } - y += wrappedRepeatHeightPx; xpos += viewportWidth; } } + gg.dispose(); } - /** * Redraws any positions in the search results in the visible region of a * wrapped alignment. Any highlights are drawn depending on the search results @@ -1990,7 +2071,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ protected boolean drawMappedPositionsWrapped(SearchResultsI results) { - if (results == null) + if ((results == null) || (img == null)) // JAL-2784 check gg is not null { return false; } @@ -2011,20 +2092,22 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } int firstVisibleColumn = ranges.getStartRes(); - int lastVisibleColumn = ranges.getStartRes() + repeats - * ranges.getViewportWidth() - 1; + int lastVisibleColumn = ranges.getStartRes() + + repeats * ranges.getViewportWidth() - 1; AlignmentI alignment = av.getAlignment(); if (av.hasHiddenColumns()) { firstVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(firstVisibleColumn); + .visibleToAbsoluteColumn(firstVisibleColumn); lastVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(lastVisibleColumn); + .visibleToAbsoluteColumn(lastVisibleColumn); } int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1); + Graphics gg = img.getGraphics(); + for (int seqNo = ranges.getStartSeq(); seqNo <= ranges .getEndSeq(); seqNo++) { @@ -2059,15 +2142,15 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { displayColumn = alignment.getHiddenColumns() - .findColumnPosition(displayColumn); + .absoluteToVisibleColumn(displayColumn); } /* * transX: offset from left edge of canvas to residue position */ int transX = labelWidthWest - + ((displayColumn - ranges.getStartRes()) % wrappedWidth) - * av.getCharWidth(); + + ((displayColumn - ranges.getStartRes()) + % wrappedWidth) * av.getCharWidth(); /* * transY: offset from top edge of canvas to residue position @@ -2085,8 +2168,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { matchFound = true; gg.translate(transX, transY); - drawPanel(gg, displayColumn, displayColumn, seqNo, seqNo, - yOffset); + drawPanel(seqRdr, gg, displayColumn, displayColumn, seqNo, + seqNo, yOffset); gg.translate(-transX, -transY); } } @@ -2094,7 +2177,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } } } - + + gg.dispose(); + return matchFound; } @@ -2107,4 +2192,5 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { return labelWidthWest; } + }