X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSeqCanvas.java;h=2d83e9e2c733d878243728661fa1960ee546b804;hb=0481d6e44a06a650bfc16684e04ff1c0d8656c84;hp=31c8a478841496f4523262c810d2be107cf2742a;hpb=83c47970701adc1cd6100332544f7f563e71f8f5;p=jalview.git diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 31c8a47..2d83e9e 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -38,14 +38,14 @@ 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; /** * The Swing component on which the alignment sequences, and annotations (if @@ -53,7 +53,8 @@ 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 { /* * pixels gap between sequences and annotations when in wrapped mode @@ -74,7 +75,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI private final SequenceRenderer seqRdr; - private boolean fastPaint = false; + boolean fastPaint = false; private boolean fastpainting = false; @@ -87,13 +88,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. @@ -114,7 +116,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI public SequenceRenderer getSequenceRenderer() { - return seqRdr; + return seqRdr; } public FeatureRenderer getFeatureRenderer() @@ -200,7 +202,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int yPos = ypos + charHeight; int startX = startx; int endX = endx; - + if (av.hasHiddenColumns()) { HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns(); @@ -236,6 +238,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } } + /* * white fill the space for the scale */ @@ -260,6 +263,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI g.drawString(valueAsString, xOffset, y); } } + } /** @@ -273,6 +277,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI *
  • scrolling by trackpad, middle mouse button, or other device
  • *
  • by moving the box in the Overview window
  • *
  • programmatically to make a highlighted position visible
  • + *
  • pasting a block of sequences
  • * * * @param horizontal @@ -282,18 +287,21 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ public void fastPaint(int horizontal, int vertical) { - if (fastpainting || gg == null || img == null) + + // effectively: + // if (horizontal != 0 && vertical != 0) + // throw new InvalidArgumentException(); + if (fastpainting || img == null) { return; } fastpainting = true; fastPaint = true; - try { int charHeight = av.getCharHeight(); int charWidth = av.getCharWidth(); - + ViewportRanges ranges = av.getRanges(); int startRes = ranges.getStartRes(); int endRes = ranges.getEndRes(); @@ -301,10 +309,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int endSeq = ranges.getEndSeq(); int transX = 0; int transY = 0; - - gg.copyArea(horizontal * charWidth, vertical * charHeight, - img.getWidth(), img.getHeight(), -horizontal * charWidth, - -vertical * charHeight); if (horizontal > 0) // scrollbar pulled right, image to the left { @@ -339,13 +343,24 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } } + + // System.err.println(">>> FastPaint to " + transX + " " + transY + " " + // + horizontal + " " + vertical + " " + startRes + " " + endRes + // + " " + startSeq + " " + endSeq); + + Graphics gg = img.getGraphics(); + gg.copyArea(horizontal * charWidth, vertical * charHeight, + img.getWidth(), img.getHeight(), -horizontal * charWidth, + -vertical * charHeight); gg.translate(transX, transY); drawPanel(gg, startRes, endRes, startSeq, endSeq, 0); gg.translate(-transX, -transY); + gg.dispose(); // Call repaint on alignment panel so that repaints from other alignment // panel components can be aggregated. Otherwise performance of the // overview window and others may be adversely affected. + // System.out.println("SeqCanvas fastPaint() repaint() request..."); av.getAlignPanel().repaint(); } finally { @@ -356,73 +371,105 @@ public class SeqCanvas extends JComponent implements ViewportListenerI @Override public void paintComponent(Graphics g) { - super.paintComponent(g); - + int charHeight = av.getCharHeight(); int charWidth = av.getCharWidth(); - + + int availWidth = getWidth(); + int availHeight = getHeight(); + + availWidth -= (availWidth % charWidth); + availHeight -= (availHeight % charHeight); + + // BH 2019 can't possibly fastPaint if either width or height is 0 + + if (availWidth == 0 || availHeight == 0) + { + return; + } + ViewportRanges ranges = av.getRanges(); - - int width = getWidth(); - int height = getHeight(); - - width -= (width % charWidth); - height -= (height % charHeight); - - if ((img != null) && (fastPaint - || (getVisibleRect().width != g.getClipBounds().width) - || (getVisibleRect().height != g.getClipBounds().height))) + int startRes = ranges.getStartRes(); + int startSeq = ranges.getStartSeq(); + int endRes = ranges.getEndRes(); + int endSeq = ranges.getEndSeq(); + + // [JAL-3226] problem that JavaScript (or Java) may consolidate multiple + // repaint() requests in unpredictable ways. In this case, the issue was + // that in response to a CTRL-C/CTRL-V paste request, in Java a fast + // repaint request preceded two full requests, thus resulting + // in a full request for paint. In constrast, in JavaScript, the three + // requests were bundled together into one, so the fastPaint flag was + // still present for the second and third request. + // + // This resulted in incomplete painting. + // + // The solution was to set seqCanvas.fastPaint and idCanvas.fastPaint false + // in PaintRefresher when the target to be painted is one of those two + // components. + // + // BH 2019.04.22 + // + // An initial idea; can be removed once we determine this issue is closed: + // if (av.isFastPaintDisabled()) + // { + // fastPaint = false; + // } + + Rectangle vis, clip; + if (img != null + && (fastPaint + || (vis = getVisibleRect()).width != (clip = g + .getClipBounds()).width + || vis.height != clip.height)) { g.drawImage(img, 0, 0, this); - - drawSelectionGroup((Graphics2D) g, ranges.getStartRes(), - ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq()); - + drawSelectionGroup((Graphics2D) g, startRes, endRes, startSeq, + endSeq); fastPaint = false; } - else if (width > 0 && height > 0) + else { - /* - * img is a cached version of the last view we drew, if any - * if we have no img or the size has changed, make a new one - */ - if (img == null || width != img.getWidth() - || height != img.getHeight()) + // img is a cached version of the last view we drew. + // If we have no img or the size has changed, make a new one. + // + if (img == null || availWidth != img.getWidth() + || availHeight != img.getHeight()) { - img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - gg = (Graphics2D) img.getGraphics(); - gg.setFont(av.getFont()); + img = new BufferedImage(availWidth, availHeight, + BufferedImage.TYPE_INT_RGB); } - + + Graphics2D gg = (Graphics2D) img.getGraphics(); + gg.setFont(av.getFont()); + if (av.antiAlias) { gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } - + gg.setColor(Color.white); - gg.fillRect(0, 0, img.getWidth(), img.getHeight()); - + gg.fillRect(0, 0, availWidth, availHeight); + if (av.getWrapAlignment()) { - drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes()); + drawWrappedPanel(gg, availWidth, availHeight, ranges.getStartRes()); } else { - drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(), - ranges.getStartSeq(), ranges.getEndSeq(), 0); + drawPanel(gg, startRes, endRes, startSeq, endSeq, 0); } - drawSelectionGroup(gg, ranges.getStartRes(), - ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq()); + drawSelectionGroup(gg, startRes, endRes, startSeq, endSeq); g.drawImage(img, 0, 0, this); + gg.dispose(); } if (av.cursorMode) { - drawCursor(g, ranges.getStartRes(), ranges.getEndRes(), - ranges.getStartSeq(), ranges.getEndSeq()); + drawCursor(g, startRes, endRes, startSeq, endSeq); } } @@ -475,32 +522,31 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } /** - * Returns the visible width of the canvas in residues, after allowing for - * East or West scales (if shown) + * Using the current font, determine fields labelWidthEast and labelWidthWest, + * and return the number of residues that can fill the remaining width. * - * @param canvasWidth + * @param width * the width in pixels (possibly including scales) * - * @return + * @return the visible width in residues, after allowing for East or West + * scales (if shown) + * */ - public int getWrappedCanvasWidth(int canvasWidth) + public int getWrappedCanvasWidth(int width) { int charWidth = av.getCharWidth(); FontMetrics fm = getFontMetrics(av.getFont()); - int labelWidth = 0; - - if (av.getScaleRightWrapped() || av.getScaleLeftWrapped()) - { - labelWidth = getLabelWidth(fm); - } + int labelWidth = (av.getScaleRightWrapped() || av.getScaleLeftWrapped() + ? getLabelWidth(fm) + : 0); labelWidthEast = av.getScaleRightWrapped() ? labelWidth : 0; labelWidthWest = av.getScaleLeftWrapped() ? labelWidth : 0; - return (canvasWidth - labelWidthEast - labelWidthWest) / charWidth; + return (width - labelWidthEast - labelWidthWest) / charWidth; } /** @@ -526,6 +572,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI maxWidth = Math.max(maxWidth, alignment.getSequenceAt(i).getEnd()); } + // quick int log10 int length = 0; for (int i = maxWidth; i > 0; i /= 10) { @@ -540,18 +587,18 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * window * * @param g - * @param canvasWidth + * @param availWidth * available width in pixels - * @param canvasHeight + * @param availHeight * available height in pixels * @param startColumn * the first column (0...) of the alignment to draw */ - public void drawWrappedPanel(Graphics g, int canvasWidth, - int canvasHeight, final int startColumn) + public void drawWrappedPanel(Graphics g, int availWidth, int availHeight, + final int startColumn) { - int wrappedWidthInResidues = calculateWrappedGeometry(canvasWidth, - canvasHeight); + int wrappedWidthInResidues = calculateWrappedGeometry(availWidth, + availHeight); av.setWrappedWidth(wrappedWidthInResidues); @@ -561,10 +608,10 @@ public class SeqCanvas extends JComponent implements ViewportListenerI // we need to call this again to make sure the startColumn + // wrappedWidthInResidues values are used to calculate wrappedVisibleWidths // correctly. - calculateWrappedGeometry(canvasWidth, canvasHeight); + calculateWrappedGeometry(availWidth, availHeight); /* - * draw one width at a time (excluding any scales or annotation shown), + * draw one width at a time (excluding any scales shown), * until we have run out of either alignment or vertical space available */ int ypos = wrappedSpaceAboveAlignment; @@ -576,7 +623,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { int endColumn = Math .min(maxWidth, start + wrappedWidthInResidues - 1); - drawWrappedWidth(g, ypos, start, endColumn, canvasHeight); + drawWrappedWidth(g, ypos, start, endColumn, availHeight); ypos += wrappedRepeatHeightPx; start += wrappedWidthInResidues; currentWidth++; @@ -595,11 +642,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI *
  • whether scales are shown left, right or above the alignment
  • * * - * @param canvasWidth - * @param canvasHeight + * @param availWidth + * @param availHeight * @return the number of residue columns in each width */ - protected int calculateWrappedGeometry(int canvasWidth, int canvasHeight) + protected int calculateWrappedGeometry(int availWidth, int availHeight) { int charHeight = av.getCharHeight(); @@ -611,22 +658,30 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * (av.getScaleAboveWrapped() ? 2 : 1); /* - * height in pixels of the wrapped widths + * compute height in pixels of the wrapped widths + * - start with space above plus sequences */ wrappedRepeatHeightPx = wrappedSpaceAboveAlignment; - // add sequences wrappedRepeatHeightPx += av.getAlignment().getHeight() * charHeight; - // add annotations panel height if shown - wrappedRepeatHeightPx += getAnnotationHeight(); + + /* + * add annotations panel height if shown + * also gap between sequences and annotations + */ + if (av.isShowAnnotation()) + { + wrappedRepeatHeightPx += getAnnotationHeight(); + wrappedRepeatHeightPx += SEQS_ANNOTATION_GAP; // 3px + } /* * number of visible widths (the last one may be part height), * ensuring a part height includes at least one sequence */ ViewportRanges ranges = av.getRanges(); - wrappedVisibleWidths = canvasHeight / wrappedRepeatHeightPx; - int remainder = canvasHeight % wrappedRepeatHeightPx; + wrappedVisibleWidths = availHeight / wrappedRepeatHeightPx; + int remainder = availHeight % wrappedRepeatHeightPx; if (remainder >= (wrappedSpaceAboveAlignment + charHeight)) { wrappedVisibleWidths++; @@ -635,7 +690,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI /* * compute width in residues; this also sets East and West label widths */ - int wrappedWidthInResidues = getWrappedCanvasWidth(canvasWidth); + int wrappedWidthInResidues = getWrappedCanvasWidth(availWidth); /* * limit visibleWidths to not exceed width of alignment @@ -662,8 +717,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * @param endColumn * @param canvasHeight */ - protected void drawWrappedWidth(Graphics g, int ypos, int startColumn, - int endColumn, int canvasHeight) + protected void drawWrappedWidth(Graphics g, final int ypos, + final int startColumn, final int endColumn, + final int canvasHeight) { ViewportRanges ranges = av.getRanges(); int viewportWidth = ranges.getViewportWidth(); @@ -679,21 +735,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int xOffset = labelWidthWest + ((startColumn - ranges.getStartRes()) % viewportWidth) * charWidth; - g.translate(xOffset, 0); - // When printing we have an extra clipped region, - // the Printable page which we need to account for here - Shape clip = g.getClip(); - - if (clip == null) - { - g.setClip(0, 0, viewportWidth * charWidth, canvasHeight); - } - else - { - g.setClip(0, (int) clip.getBounds().getY(), - viewportWidth * charWidth, (int) clip.getBounds().getHeight()); - } + g.translate(xOffset, 0); /* * white fill the region to be drawn (so incremental fast paint doesn't @@ -710,7 +753,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.isShowAnnotation()) { - g.translate(0, cHeight + ypos + SEQS_ANNOTATION_GAP); + final int yShift = cHeight + ypos + SEQS_ANNOTATION_GAP; + g.translate(0, yShift); if (annotations == null) { annotations = new AnnotationPanel(av); @@ -718,9 +762,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI annotations.renderer.drawComponent(annotations, av, g, -1, startColumn, endx + 1); - g.translate(0, -cHeight - ypos - SEQS_ANNOTATION_GAP); + g.translate(0, -yShift); } - g.setClip(clip); g.translate(-xOffset, 0); } @@ -736,6 +779,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int charWidth = av.getCharWidth(); g.setFont(av.getFont()); + g.setColor(Color.black); int ypos = wrappedSpaceAboveAlignment; @@ -757,6 +801,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.getScaleRightWrapped()) { int x = labelWidthWest + viewportWidth * charWidth; + g.translate(x, 0); drawVerticalScale(g, startCol, endColumn, ypos, false); g.translate(-x, 0); @@ -860,13 +905,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int startx = startRes; int endx; int ypos = hgap; // vertical offset - int maxwidth = av.getAlignment().getWidth(); - - if (av.hasHiddenColumns()) - { - maxwidth = av.getAlignment().getHiddenColumns() - .absoluteToVisibleColumn(maxwidth); - } + int maxwidth = av.getAlignment().getVisibleWidth(); // chop the wrapped alignment extent up into panel-sized blocks and treat // each block as if it were a block from an unwrapped alignment @@ -1095,23 +1134,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI do { g.setColor(group.getOutlineColour()); - drawPartialGroupOutline(g, group, startRes, endRes, startSeq, endSeq, offset); groupIndex++; - if (groupIndex >= av.getAlignment().getGroups().size()) { break; } - group = av.getAlignment().getGroups().get(groupIndex); - } while (groupIndex < av.getAlignment().getGroups().size()); - } - } /** @@ -1457,20 +1490,42 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * Highlights search results in the visible region by rendering as white text * on a black background. Any previous highlighting is removed. Answers true * if any highlight was left on the visible alignment (so status bar should be + * set to match), else false. This method does _not_ set the 'fastPaint' flag, + * so allows the next repaint to update the whole display. + * + * @param results + * @return + */ + public boolean highlightSearchResults(SearchResultsI results) + { + return highlightSearchResults(results, false); + + } + + /** + * Highlights search results in the visible region by rendering as white text + * on a black background. Any previous highlighting is removed. Answers true + * if any highlight was left on the visible alignment (so status bar should be * set to match), else false. *

    - * 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) { @@ -1479,7 +1534,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI boolean wrapped = av.getWrapAlignment(); try { - fastPaint = !noFastPaint; + fastPaint = doFastPaint; fastpainting = fastPaint; /* @@ -1536,7 +1591,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ protected boolean drawMappedPositions(SearchResultsI results) { - if ((results == null) || (gg == null)) // JAL-2784 check gg is not null + if ((results == null) || (img == null)) // JAL-2784 check gg is not null { return false; } @@ -1608,9 +1663,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } 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); gg.translate(-transX, -transY); + gg.dispose(); } return matchFound; @@ -1621,90 +1678,149 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { String eventName = evt.getPropertyName(); - if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED)) + // BH 2019.07.27 removes dead code introduced in aad3650 and simplifies + // logic, emphasizing no check for ENDRES or ENDSEQ + + // 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 + // paint, so scroll events are identified as changes to the horizontal or + // vertical start value. + + // Make sure we're not trying to draw a panel + // larger than the visible window + int scrollX = 0; + switch (eventName) { + case SequenceGroup.SEQ_GROUP_CHANGED: fastPaint = true; repaint(); return; - } - else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT)) - { + case ViewportRanges.MOVE_VIEWPORT: fastPaint = false; repaint(); return; - } - - int scrollX = 0; - if (eventName.equals(ViewportRanges.STARTRES) - || eventName.equals(ViewportRanges.STARTRESANDSEQ)) - { - // Make sure we're not trying to draw a panel - // larger than the visible window - if (eventName.equals(ViewportRanges.STARTRES)) - { - scrollX = (int) evt.getNewValue() - (int) evt.getOldValue(); - } - else - { - scrollX = ((int[]) evt.getNewValue())[0] - - ((int[]) evt.getOldValue())[0]; - } - ViewportRanges vpRanges = av.getRanges(); - - int range = vpRanges.getEndRes() - vpRanges.getStartRes(); - if (scrollX > range) - { - scrollX = range; - } - else if (scrollX < -range) - { - 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 - // paint, so scroll events are identified as changes to the horizontal or - // vertical start value. - if (eventName.equals(ViewportRanges.STARTRES)) - { - 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); - } - else - { - fastPaint(scrollX, 0); - } - } - else if (eventName.equals(ViewportRanges.STARTSEQ)) - { - // scroll + case ViewportRanges.STARTSEQ: + // meaning STARTOREND + // typically scroll, but possibly just the end changed fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); + return; + case ViewportRanges.ENDRES: + case ViewportRanges.ENDSEQ: + // meaning second event along with "START" -- ENDONLY,NOTSTART + // TODO: ignore?? + return; + case ViewportRanges.STARTRES: + // meaning STARTOREND + scrollX = (int) evt.getNewValue() - (int) evt.getOldValue(); + break; + case ViewportRanges.STARTRESANDSEQ: + scrollX = ((int[]) evt.getNewValue())[0] + - ((int[]) evt.getOldValue())[0]; + break; + } + ViewportRanges vpRanges = av.getRanges(); + int range = vpRanges.getEndRes() - vpRanges.getStartRes() + 1; + scrollX = Math.max(Math.min(scrollX, range), -range); + // only STARTRES or STARTRESANDSEQ: + if (av.getWrapAlignment()) + { + fastPaintWrapped(scrollX); } - else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) + else { - if (av.getWrapAlignment()) - { - fastPaintWrapped(scrollX); - } - } + fastPaint(scrollX, 0); + } + + // BH 2019.07.27 was: + // if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED)) + // { + // fastPaint = true; + // repaint(); + // return; + // } + // else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT)) + // { + // fastPaint = false; + // // System.err.println("!!!! fastPaint false from MOVE_VIEWPORT"); + // repaint(); + // return; + // } + // + // if (eventName.equals(ViewportRanges.STARTRES) + // || eventName.equals(ViewportRanges.STARTRESANDSEQ)) + // { + // // Make sure we're not trying to draw a panel + // // larger than the visible window + // if (eventName.equals(ViewportRanges.STARTRES)) + // { + // scrollX = (int) evt.getNewValue() - (int) evt.getOldValue(); + // } + // else + // { + // scrollX = ((int[]) evt.getNewValue())[0] + // - ((int[]) evt.getOldValue())[0]; + // } + // ViewportRanges vpRanges = av.getRanges(); + // + // int range = vpRanges.getEndRes() - vpRanges.getStartRes() + 1; + // if (scrollX > range) + // { + // scrollX = range; + // } + // else if (scrollX < -range) + // { + // 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 + // paint, so scroll events are identified as changes to the horizontal or + // vertical start value. + // BH 2019.07.27 was: + // if (eventName.equals(ViewportRanges.STARTRES)) + // { + // 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); + // } + // else + // { + // fastPaint(scrollX, 0); + // } + // } + // + // BH oops! + // + // 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); + // } + // } } /** @@ -1720,10 +1836,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; @@ -1731,7 +1847,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI return; } - if (fastpainting || gg == null) + if (fastpainting || img == null) { return; } @@ -1741,6 +1857,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI try { + + Graphics gg = img.getGraphics(); + calculateWrappedGeometry(getWidth(), getHeight()); /* @@ -1769,6 +1888,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ drawWrappedDecorators(gg, ranges.getStartRes()); + gg.dispose(); + repaint(); } finally { @@ -1792,6 +1913,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(); @@ -1818,6 +1941,8 @@ 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, @@ -1825,6 +1950,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI gg.translate(-xOffset, 0); drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight); + } /* @@ -1868,7 +1994,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI gg.setColor(Color.white); gg.fillRect(0, canvasHeight - heightBelow, getWidth(), heightBelow); } - } + gg.dispose(); + } /** * Shifts the visible alignment by the specified number of columns - left if @@ -1884,6 +2011,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { return; } + + Graphics gg = img.getGraphics(); + int charWidth = av.getCharWidth(); int canvasHeight = getHeight(); @@ -1914,10 +2044,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); @@ -1950,11 +2087,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * charWidth, heightToCopy, widthToCopy, -wrappedRepeatHeightPx); } - y += wrappedRepeatHeightPx; xpos += viewportWidth; } } + gg.dispose(); } @@ -1970,7 +2107,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI */ protected boolean drawMappedPositionsWrapped(SearchResultsI results) { - if ((results == null) || (gg == null)) // JAL-2784 check gg is not null + if ((results == null) || (img == null)) // JAL-2784 check gg is not null { return false; } @@ -2005,6 +2142,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1); + + Graphics gg = img.getGraphics(); + for (int seqNo = ranges.getStartSeq(); seqNo <= ranges .getEndSeq(); seqNo++) { @@ -2075,6 +2215,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI } } + gg.dispose(); + return matchFound; } @@ -2087,4 +2229,5 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { return labelWidthWest; } + }