Merge branch 'Jalview-JS/develop' into merge_js_develop
[jalview.git] / src / jalview / gui / SeqCanvas.java
index b27208a..59a6cb1 100755 (executable)
@@ -57,7 +57,8 @@ import javax.swing.JPanel;
 public class SeqCanvas extends JPanel implements ViewportListenerI
 {
   /**
-   * vertical gap in pixels between sequences and annotations when in wrapped mode
+   * vertical gap in pixels between sequences and annotations when in wrapped
+   * mode
    */
   static final int SEQS_ANNOTATION_GAP = 3;
 
@@ -75,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;
 
@@ -94,8 +95,14 @@ 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;
+  // private Graphics2D gg;
 
   /**
    * Creates a new SeqCanvas object.
@@ -116,7 +123,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
 
   public SequenceRenderer getSequenceRenderer()
   {
-    return seqRdr; 
+    return seqRdr;
   }
 
   public FeatureRenderer getFeatureRenderer()
@@ -202,7 +209,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();
@@ -238,7 +245,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
         }
       }
 
-      
       /*
        * white fill the space for the scale
        */
@@ -343,7 +349,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
         }
       }
 
-
       // System.err.println(">>> FastPaint to " + transX + " " + transY + " "
       // + horizontal + " " + vertical + " " + startRes + " " + endRes
       // + " " + startSeq + " " + endSeq);
@@ -352,9 +357,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
       gg.copyArea(horizontal * charWidth, vertical * charHeight,
               img.getWidth(), img.getHeight(), -horizontal * charWidth,
               -vertical * charHeight);
-
-      /** @j2sNative xxi = this.img */
-
       gg.translate(transX, transY);
       drawPanel(gg, startRes, endRes, startSeq, endSeq, 0);
       gg.translate(-transX, -transY);
@@ -363,7 +365,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
     {
@@ -374,23 +375,17 @@ 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;
     }
-
     ViewportRanges ranges = av.getRanges();
     int startRes = ranges.getStartRes();
     int startSeq = ranges.getStartSeq();
@@ -420,11 +415,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,
@@ -433,13 +426,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();
@@ -452,11 +447,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, width, height, ranges.getStartRes());
+        drawWrappedPanel(gg, availWidth, availHeight, ranges.getStartRes());
       }
       else
       {
@@ -474,7 +469,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
       drawCursor(g, startRes, endRes, startSeq, endSeq);
     }
   }
-  
+
   /**
    * Draw an alignment panel for printing
    * 
@@ -494,8 +489,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
   {
     drawPanel(g1, startRes, endRes, startSeq, endSeq, 0);
 
-    drawSelectionGroup((Graphics2D) g1, startRes, endRes,
-            startSeq, endSeq);
+    drawSelectionGroup((Graphics2D) g1, startRes, endRes, startSeq, endSeq);
   }
 
   /**
@@ -519,37 +513,36 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
     if (group != null)
     {
       drawWrappedSelection((Graphics2D) g, group, canvasWidth, canvasHeight,
-                startRes);
+              startRes);
     }
   }
 
   /**
-   * 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 w
    *          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 w)
   {
     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 (w - labelWidthEast - labelWidthWest) / charWidth;
   }
 
   /**
@@ -575,6 +568,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)
     {
@@ -589,28 +583,25 @@ 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);
-
     ViewportRanges ranges = av.getRanges();
     ranges.setViewportStartAndWidth(startColumn, wrappedWidthInResidues);
 
     // 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,9 +614,9 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
     int currentWidth = 0;
     while ((currentWidth < wrappedVisibleWidths) && (start < maxWidth))
     {
-      int endColumn = Math
-              .min(maxWidth, start + wrappedWidthInResidues - 1);
-      drawWrappedWidth(g, ypos, start, endColumn, canvasHeight);
+      int endColumn = Math.min(maxWidth,
+              start + wrappedWidthInResidues - 1);
+      drawWrappedWidth(g, ypos, start, endColumn, availHeight);
       ypos += wrappedRepeatHeightPx;
       start += wrappedWidthInResidues;
       currentWidth++;
@@ -634,6 +625,16 @@ 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
@@ -644,12 +645,26 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
    * <li>whether scales are shown left, right or above the alignment</li>
    * </ul>
    * 
+   * @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();
 
     /*
@@ -663,9 +678,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
@@ -736,7 +750,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
     int charWidth = av.getCharWidth();
     int xOffset = labelWidthWest
             + ((startColumn - ranges.getStartRes()) % viewportWidth)
-            * charWidth;
+                    * charWidth;
 
     g.translate(xOffset, 0);
 
@@ -803,7 +817,7 @@ 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);
@@ -815,8 +829,9 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
        */
       g.translate(labelWidthWest, 0);
       g.setColor(Color.white);
-      g.fillRect(0, ypos - wrappedSpaceAboveAlignment, viewportWidth
-              * charWidth + labelWidthWest, wrappedSpaceAboveAlignment);
+      g.fillRect(0, ypos - wrappedSpaceAboveAlignment,
+              viewportWidth * charWidth + labelWidthWest,
+              wrappedSpaceAboveAlignment);
       g.setColor(Color.black);
       g.translate(-labelWidthWest, 0);
 
@@ -883,18 +898,21 @@ 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
    */
   private void drawWrappedSelection(Graphics2D g, SequenceGroup group,
-          int canvasWidth,
-          int canvasHeight, int startRes)
+          int canvasWidth, int canvasHeight, int startRes)
   {
     // 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();
@@ -902,6 +920,21 @@ 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))
@@ -915,21 +948,24 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
       }
 
       g.translate(labelWidthWest, 0);
+
       drawUnwrappedSelection(g, group, startx, endx, 0,
-              av.getAlignment().getHeight() - 1,
-              ypos);
+              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);
   }
 
   /**
-   * Answers zero if annotations are not shown, otherwise recalculates and answers
-   * the total height of all annotation rows in pixels
+   * Answers zero if annotations are not shown, otherwise recalculates and
+   * answers the total height of all annotation rows in pixels
    * 
    * @return
    */
@@ -1190,8 +1226,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
    *         the cursor drawn on it, if any
    */
   private void drawCursor(Graphics g, int startRes, int endRes,
-          int startSeq,
-          int endSeq)
+          int startSeq, int endSeq)
   {
     // convert the cursorY into a position on the visible alignment
     int cursor_ypos = cursorY;
@@ -1262,7 +1297,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
     }
   }
 
-
   /**
    * Draw a selection group over an unwrapped alignment
    * 
@@ -1285,7 +1319,7 @@ 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,
@@ -1308,8 +1342,8 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
         blockStart = region[0];
 
         g.translate(screenY * charWidth, 0);
-        drawPartialGroupOutline(g, group,
-                blockStart, blockEnd, startSeq, endSeq, offset);
+        drawPartialGroupOutline(g, group, blockStart, blockEnd, startSeq,
+                endSeq, offset);
 
         g.translate(-screenY * charWidth, 0);
         screenY += blockEnd - blockStart + 1;
@@ -1478,7 +1512,7 @@ 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
@@ -1494,7 +1528,7 @@ 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
@@ -1652,7 +1686,8 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
       {
         firstCol = alignment.getHiddenColumns()
                 .absoluteToVisibleColumn(firstCol);
-        lastCol = alignment.getHiddenColumns().absoluteToVisibleColumn(lastCol);
+        lastCol = alignment.getHiddenColumns()
+                .absoluteToVisibleColumn(lastCol);
       }
       int transX = (firstCol - ranges.getStartRes()) * av.getCharWidth();
       int transY = (firstSeq - ranges.getStartSeq()) * av.getCharHeight();
@@ -1670,92 +1705,158 @@ 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))
-    {
-      fastPaint = true;
-      repaint();
-      return;
-    }
-    else if (eventName.equals(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
-      {
-        scrollX = ((int[]) evt.getNewValue())[0]
-                - ((int[]) evt.getOldValue())[0];
-      }
-      ViewportRanges vpRanges = av.getRanges();
+    // BH 2019.07.27 removes dead code introduced in aad3650 and simplifies
+    // logic, emphasizing no check for ENDRES or ENDSEQ
 
-      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))
+
+    // Make sure we're not trying to draw a panel
+    // larger than the visible window
+    int scrollX = 0;
+    int scrollY = 0;
+    switch (eventName)
     {
-      // scroll
+    case SequenceGroup.SEQ_GROUP_CHANGED:
+      fastPaint = true;
+      repaint();
+      return;
+    case ViewportRanges.MOVE_VIEWPORT:
+      fastPaint = false;
+      repaint();
+      return;
+    case ViewportRanges.STARTSEQ:
+      // meaning STARTOREND
+      // typically scroll, but possibly just the end changed
       fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
-    }
-    else if (eventName.equals(ViewportRanges.STARTRESANDSEQ))
-    {
-      if (av.getWrapAlignment())
-      {
-        fastPaintWrapped(scrollX);
-      }
-      else
+      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)
       {
-        fastPaint(scrollX, 0);
+        // all sorts of problems in JavaScript if this is commented out.
+        repaint();
+        return;
+
       }
+      break;
+    default:
+      return;
     }
-    else if (eventName.equals(ViewportRanges.STARTSEQ))
+
+    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())
     {
-      // scroll
-      fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+      fastPaintWrapped(scrollX);
     }
-    else if (eventName.equals(ViewportRanges.STARTRESANDSEQ))
+    else
     {
-      if (av.getWrapAlignment())
-      {
-        fastPaintWrapped(scrollX);
-      }
+      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.
+    // 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);
+    // }
+    // }
   }
 
   /**
@@ -1792,10 +1893,10 @@ 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
@@ -1810,8 +1911,8 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
       if (scrollX < 0)
       {
         int startRes = ranges.getStartRes();
-        drawWrappedWidth(gg, wrappedSpaceAboveAlignment, startRes, startRes
-                - scrollX - 1, getHeight());
+        drawWrappedWidth(gg, wrappedSpaceAboveAlignment, startRes,
+                startRes - scrollX - 1, getHeight());
       }
       else
       {
@@ -1824,7 +1925,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
       drawWrappedDecorators(gg, ranges.getStartRes());
 
       gg.dispose();
-      
+
       repaint();
     } finally
     {
@@ -1849,7 +1950,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
     }
 
     Graphics gg = img.getGraphics();
-    
+
     ViewportRanges ranges = av.getRanges();
     int viewportWidth = ranges.getViewportWidth();
     int charWidth = av.getCharWidth();
@@ -1860,7 +1961,8 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
      */
     int visibleWidths = wrappedVisibleWidths;
     int canvasHeight = getHeight();
-    boolean lastWidthPartHeight = (wrappedVisibleWidths * wrappedRepeatHeightPx) > canvasHeight;
+    boolean lastWidthPartHeight = (wrappedVisibleWidths
+            * wrappedRepeatHeightPx) > canvasHeight;
 
     if (lastWidthPartHeight)
     {
@@ -1876,16 +1978,15 @@ 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, wrappedRepeatHeightPx);
+      gg.fillRect(labelWidthWest, ypos, (endRes - startRes + 1) * charWidth,
+              wrappedRepeatHeightPx);
       gg.translate(-xOffset, 0);
 
       drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight);
-      
+
     }
 
     /*
@@ -1930,7 +2031,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
       gg.fillRect(0, canvasHeight - heightBelow, getWidth(), heightBelow);
     }
     gg.dispose();
- }
+  }
 
   /**
    * Shifts the visible alignment by the specified number of columns - left if
@@ -2018,8 +2119,8 @@ public class SeqCanvas extends JPanel 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;
@@ -2029,7 +2130,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
     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
@@ -2050,7 +2150,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
 
     boolean matchFound = false;
 
-    calculateWrappedGeometry(getWidth(), getHeight());
+    calculateWrappedGeometry();
     int wrappedWidth = av.getWrappedWidth();
     int wrappedHeight = wrappedRepeatHeightPx;
 
@@ -2063,8 +2163,8 @@ public class SeqCanvas extends JPanel 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())
@@ -2077,7 +2177,6 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
 
     int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
 
-    
     Graphics gg = img.getGraphics();
 
     for (int seqNo = ranges.getStartSeq(); seqNo <= ranges
@@ -2121,8 +2220,8 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
                * 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
@@ -2149,7 +2248,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
         }
       }
     }
-  
+
     gg.dispose();
 
     return matchFound;
@@ -2165,4 +2264,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;
+  }
+
 }