X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSeqCanvas.java;h=11371531549941169b306f1e84e1cf7c235972f8;hb=d043ce47fc710d3eb2629ba926a8a7417bd67d8c;hp=d15cdcf376b50ba2fe0d3c08738935304c85d260;hpb=04c8f7bff663aa469127e9eed4164e02933782f1;p=jalview.git diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index d15cdcf..1137153 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -20,6 +20,18 @@ */ 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.datamodel.VisibleContigsIterator; +import jalview.renderer.ScaleRenderer; +import jalview.renderer.ScaleRenderer.ScaleMark; +import jalview.util.Comparison; +import jalview.viewmodel.ViewportListenerI; +import jalview.viewmodel.ViewportRanges; + import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; @@ -35,18 +47,6 @@ import java.util.List; import javax.swing.JPanel; -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 * shown), are drawn. This includes scales above, left and right (if shown) in @@ -76,7 +76,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI private final SequenceRenderer seqRdr; - boolean fastPaint = false; + private boolean fastPaint = false; private boolean fastpainting = false; @@ -95,6 +95,11 @@ public class SeqCanvas extends JPanel implements ViewportListenerI private int wrappedVisibleWidths; // number of wrapped widths displayed + private int availWidth; + + private int availHeight; + + private boolean allowFastPaint; // Don't do this! Graphics handles are supposed to be transient // private Graphics2D gg; @@ -203,7 +208,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI int yPos = ypos + charHeight; int startX = startx; int endX = endx; - + if (av.hasHiddenColumns()) { HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns(); @@ -343,6 +348,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI } } + // System.err.println(">>> FastPaint to " + transX + " " + transY + " " // + horizontal + " " + vertical + " " + startRes + " " + endRes // + " " + startSeq + " " + endSeq); @@ -352,7 +358,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI img.getWidth(), img.getHeight(), -horizontal * charWidth, -vertical * charHeight); - /** @j2sNative xxi = this.img */ gg.translate(transX, transY); drawPanel(gg, startRes, endRes, startSeq, endSeq, 0); @@ -362,7 +367,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI // 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 { @@ -373,19 +377,14 @@ public class SeqCanvas extends JPanel implements ViewportListenerI @Override public void paintComponent(Graphics g) { + if (av.getAlignPanel().getHoldRepaint()) + { + return; + } - int charHeight = av.getCharHeight(); - int charWidth = av.getCharWidth(); - - int width = getWidth(); - int height = getHeight(); - - width -= (width % charWidth); - height -= (height % charHeight); - - // BH 2019 can't possibly fastPaint if either width or height is 0 + getAvailSizes(); - if (width == 0 || height == 0) + if (availWidth == 0 || availHeight == 0) { return; } @@ -419,11 +418,9 @@ public class SeqCanvas extends JPanel implements ViewportListenerI // } Rectangle vis, clip; - if (img != null - && (fastPaint - || (vis = getVisibleRect()).width != (clip = g - .getClipBounds()).width - || vis.height != clip.height)) + if (allowFastPaint && img != null + && (fastPaint || (vis = getVisibleRect()).width != (clip = g.getClipBounds()).width + || vis.height != clip.height)) { g.drawImage(img, 0, 0, this); drawSelectionGroup((Graphics2D) g, startRes, endRes, startSeq, @@ -432,13 +429,15 @@ public class SeqCanvas extends JPanel implements ViewportListenerI } else { + allowFastPaint = true; // 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 || width != img.getWidth() - || height != img.getHeight()) + if (img == null || availWidth != img.getWidth() + || availHeight != img.getHeight()) { - img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + img = new BufferedImage(availWidth, availHeight, + BufferedImage.TYPE_INT_RGB); } Graphics2D gg = (Graphics2D) img.getGraphics(); @@ -451,11 +450,11 @@ public class SeqCanvas extends JPanel implements ViewportListenerI } 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 { @@ -473,7 +472,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI drawCursor(g, startRes, endRes, startSeq, endSeq); } } - /** * Draw an alignment panel for printing * @@ -537,7 +535,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI FontMetrics fm = getFontMetrics(av.getFont()); int labelWidth = 0; - + if (av.getScaleRightWrapped() || av.getScaleLeftWrapped()) { labelWidth = getLabelWidth(fm); @@ -573,6 +571,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI maxWidth = Math.max(maxWidth, alignment.getSequenceAt(i).getEnd()); } + // quick int log10 int length = 0; for (int i = maxWidth; i > 0; i /= 10) { @@ -587,18 +586,17 @@ public class SeqCanvas extends JPanel 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(); av.setWrappedWidth(wrappedWidthInResidues); @@ -608,7 +606,7 @@ public class SeqCanvas extends JPanel 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(); /* * draw one width at a time (excluding any scales shown), @@ -623,7 +621,7 @@ public class SeqCanvas extends JPanel 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++; @@ -632,6 +630,15 @@ public class SeqCanvas extends JPanel implements ViewportListenerI drawWrappedDecorators(g, startColumn); } + private void getAvailSizes() + { + int charHeight = av.getCharHeight(); + int charWidth = av.getCharWidth(); + availWidth = getWidth(); + availHeight = getHeight(); + availWidth -= (availWidth % charWidth); + availHeight -= (availHeight % charHeight); + } /** * Calculates and saves values needed when rendering a wrapped alignment. * These depend on many factors, including @@ -642,11 +649,24 @@ public class SeqCanvas extends JPanel implements ViewportListenerI *
  • whether scales are shown left, right or above the alignment
  • * * + * @param availWidth + * @param availHeight + * @return the number of residue columns in each width + */ + protected int calculateWrappedGeometry() + { + getAvailSizes(); + return calculateWrappedGeometry(availWidth, availHeight); + + } + + /** + * for test only * @param canvasWidth * @param canvasHeight - * @return the number of residue columns in each width + * @return */ - protected int calculateWrappedGeometry(int canvasWidth, int canvasHeight) + public int calculateWrappedGeometry(int canvasWidth, int canvasHeight) { int charHeight = av.getCharHeight(); @@ -661,8 +681,8 @@ public class SeqCanvas extends JPanel implements ViewportListenerI * compute height in pixels of the wrapped widths * - start with space above plus sequences */ - wrappedRepeatHeightPx = wrappedSpaceAboveAlignment; - wrappedRepeatHeightPx += av.getAlignment().getHeight() * charHeight; + wrappedRepeatHeightPx = wrappedSpaceAboveAlignment + + av.getAlignment().getHeight() * charHeight; /* * add annotations panel height if shown @@ -690,7 +710,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI * compute width in residues; this also sets East and West label widths */ int wrappedWidthInResidues = getWrappedCanvasWidth(canvasWidth); - av.setWrappedWidth(wrappedWidthInResidues); // update model accordingly + /* * limit visibleWidths to not exceed width of alignment */ @@ -800,7 +820,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI if (av.getScaleRightWrapped()) { int x = labelWidthWest + viewportWidth * charWidth; - g.translate(x, 0); drawVerticalScale(g, startCol, endColumn, ypos, false); g.translate(-x, 0); @@ -881,6 +900,11 @@ public class SeqCanvas extends JPanel implements ViewportListenerI } } + private final static BasicStroke dottedStroke = new BasicStroke(1, + BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 3f, new float[] + { 5f, 3f }, 0f); + + private final static BasicStroke basicStroke = new BasicStroke(); /* * Draw a selection group over a wrapped alignment */ @@ -889,9 +913,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI { // chop the wrapped alignment extent up into panel-sized blocks and treat // each block as if it were a block from an unwrapped alignment - g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_ROUND, 3f, new float[] - { 5f, 3f }, 0f)); + g.setStroke(dottedStroke); g.setColor(Color.RED); int charWidth = av.getCharWidth(); @@ -899,6 +921,20 @@ public class SeqCanvas extends JPanel implements ViewportListenerI / charWidth; int startx = startRes; int maxwidth = av.getAlignment().getVisibleWidth(); + // JAL-3253-applet had this: + // // height gap above each panel + // int charHeight = av.getCharHeight(); + // int hgap = charHeight; + // if (av.getScaleAboveWrapped()) + // { + // hgap += charHeight; + // } + // int dy = getAnnotationHeight() + hgap + // + av.getAlignment().getHeight() * charHeight; + // int ypos = hgap; // vertical offset + + // this is from 0b573ed (gmungoc) + int dy = wrappedRepeatHeightPx; int ypos = wrappedSpaceAboveAlignment; while ((ypos <= canvasHeight) && (startx < maxwidth)) @@ -916,11 +952,13 @@ public class SeqCanvas extends JPanel implements ViewportListenerI av.getAlignment().getHeight() - 1, ypos); g.translate(-labelWidthWest, 0); - ypos += wrappedRepeatHeightPx; + // update vertical offset + ypos += dy; + // update horizontal offset startx += cWidth; } - g.setStroke(new BasicStroke()); + g.setStroke(basicStroke); } /** @@ -1257,6 +1295,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI } } + /** * Draw a selection group over an unwrapped alignment * @@ -1279,7 +1318,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI int startRes, int endRes, int startSeq, int endSeq, int offset) { int charWidth = av.getCharWidth(); - if (!av.hasHiddenColumns()) { drawPartialGroupOutline(g, group, startRes, endRes, startSeq, endSeq, @@ -1472,7 +1510,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI g.drawLine(sx + xwidth, oldY, sx + xwidth, sy); } } - /** * Highlights search results in the visible region by rendering as white text * on a black background. Any previous highlighting is removed. Answers true @@ -1488,7 +1525,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI 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 @@ -1665,92 +1701,157 @@ public class SeqCanvas extends JPanel implements ViewportListenerI public void propertyChange(PropertyChangeEvent evt) { String eventName = evt.getPropertyName(); - // System.err.println(">>SeqCanvas propertyChange " + eventName); - 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; + int scrollY = 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; - // System.err.println("!!!! fastPaint false from MOVE_VIEWPORT"); 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 + case ViewportRanges.STARTSEQ: + // meaning STARTOREND + // typically scroll, but possibly just the end changed + fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); + 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]; + scrollY = ((int[]) evt.getNewValue())[1] + - ((int[]) evt.getOldValue())[1]; + if (scrollX != 0 && scrollY != 0) { - scrollX = ((int[]) evt.getNewValue())[0] - - ((int[]) evt.getOldValue())[0]; - } - ViewportRanges vpRanges = av.getRanges(); + // all sorts of problems in JavaScript if this is commented out. + repaint(); + return; - int range = vpRanges.getEndRes() - vpRanges.getStartRes() + 1; - if (scrollX > range) - { - scrollX = range; - } - else if (scrollX < -range) - { - scrollX = -range; } + break; + default: + return; + } + + 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 + { + fastPaint(scrollX, scrollY); } + + // 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. - 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 - fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); - } - else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) - { - if (av.getWrapAlignment()) - { - fastPaintWrapped(scrollX); - } - } + // 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); + // } + // } } /** @@ -1787,10 +1888,8 @@ public class SeqCanvas extends JPanel implements ViewportListenerI try { - Graphics gg = img.getGraphics(); - - calculateWrappedGeometry(getWidth(), getHeight()); + calculateWrappedGeometry(); /* * relocate the regions of the alignment that are still visible @@ -1819,7 +1918,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI drawWrappedDecorators(gg, ranges.getStartRes()); gg.dispose(); - repaint(); } finally { @@ -1844,7 +1942,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI } Graphics gg = img.getGraphics(); - ViewportRanges ranges = av.getRanges(); int viewportWidth = ranges.getViewportWidth(); int charWidth = av.getCharWidth(); @@ -1872,7 +1969,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI /* * white fill first to erase annotations */ - gg.translate(xOffset, 0); gg.setColor(Color.white); gg.fillRect(labelWidthWest, ypos, (endRes - startRes + 1) * charWidth, @@ -1880,7 +1976,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI gg.translate(-xOffset, 0); drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight); - } /* @@ -2044,7 +2139,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI boolean matchFound = false; - calculateWrappedGeometry(getWidth(), getHeight()); + calculateWrappedGeometry(); int wrappedWidth = av.getWrappedWidth(); int wrappedHeight = wrappedRepeatHeightPx; @@ -2142,7 +2237,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI } } } - gg.dispose(); return matchFound; @@ -2158,4 +2252,13 @@ public class SeqCanvas extends JPanel implements ViewportListenerI return labelWidthWest; } + /** + * Clears the flag that allows a 'fast paint' on the next repaint, so + * requiring a full repaint + */ + public void setNoFastPaint() + { + allowFastPaint = false; + } + }