JAL-2609 further progress towards scroll right fast paint...
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 2 Aug 2017 12:51:02 +0000 (14:51 +0200)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 2 Aug 2017 12:51:02 +0000 (14:51 +0200)
src/jalview/gui/SeqCanvas.java

index 9bab774..785b71d 100755 (executable)
@@ -120,17 +120,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
   /**
    * Draws the scale above a region of a wrapped alignment, consisting of a
-   * column number every 10 columns.
+   * column number every major interval (10 columns).
    * 
    * @param g
    *          the graphics context to draw on, positioned at the start (bottom
-   *          left) of the
+   *          left) of the line on which to draw any scale marks
    * @param startx
-   *          DOCUMENT ME!
+   *          start alignment column (0..)
    * @param endx
-   *          DOCUMENT ME!
+   *          end alignment column (0..)
    * @param ypos
-   *          DOCUMENT ME!
+   *          y offset to draw at
    */
   private void drawNorthScale(Graphics g, int startx, int endx, int ypos)
   {
@@ -509,8 +509,10 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     /*
      * draw one width at a time (including any scales or annotation shown),
      * until we have run out of alignment or vertical space available
+     * (stop if not enough room left for at least one sequence)
      */
-    while ((ypos <= canvasHeight) && (startRes < maxwidth))
+    int yposMax = canvasHeight;// - hgap - charHeight + 1;
+    while ((ypos <= yposMax) && (startRes < maxwidth))
     {
       drawWrappedWidth(g, startRes, canvasHeight, cWidth, maxwidth, ypos);
 
@@ -1266,16 +1268,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
     /*
      * add new columns (scale above, sequence, annotation)
-     * at top left if scrollX < 0 or bottom right if scrollX > 0
+     * - at top left if scrollX < 0 
+     * - at right of last two widths if scrollX > 0
      * also West scale top left or East scale bottom right if shown
      */
     if (scrollX < 0)
     {
-      fastPaintWrappedTopLeft(-scrollX);
+      fastPaintWrappedAddLeft(-scrollX);
     }
     else
     {
-      // fastPaintWrappedBottomRight(scrollX);
+      fastPaintWrappedAddRight(scrollX);
     }
 
     repaint();
@@ -1284,42 +1287,128 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   /**
    * Draws the specified number of columns at the 'end' (bottom right) of a
    * wrapped alignment view, including scale above and right and annotations if
-   * shown
+   * shown. Also draws the same number of columns at the right hand end of the
+   * second last width shown, if the last width is not full height (so cannot
+   * simply be copied from the graphics image).
    * 
    * @param columns
    */
-  protected void fastPaintWrappedBottomRight(int columns)
+  protected void fastPaintWrappedAddRight(int columns)
   {
     if (columns == 0)
     {
       return;
     }
 
+    /*
+     * how many widths are visible? we will be adding
+     * columns to the last visible width, right hand end
+     */
     int repeatHeight = getRepeatHeightWrapped();
-    ViewportRanges ranges = av.getRanges();
-    int visibleWidths = getHeight() / repeatHeight;
-    if (getHeight() % repeatHeight > 0)
+    int canvasHeight = getHeight();
+    int visibleWidths = canvasHeight / repeatHeight;
+    int remainder = canvasHeight % repeatHeight;
+    int hgap = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
+    boolean lastWidthPartHeight = false;
+    if (remainder >= (hgap + charHeight))
     {
       visibleWidths++;
+      lastWidthPartHeight = true;
     }
+
+    /*
+     * limit visible widths to max widths of alignment
+     */
+    ViewportRanges ranges = av.getRanges();
+    int visibleAlignmentWidth = ranges.getVisibleAlignmentWidth();
     int viewportWidth = ranges.getViewportWidth();
-    int hgap = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
+    int maxWidths = visibleAlignmentWidth / viewportWidth;
+    if (visibleAlignmentWidth % viewportWidth > 0)
+    {
+      maxWidths++;
+    }
+    visibleWidths = Math.min(visibleWidths, maxWidths);
+    int widthInColumns = (getWidth() - labelWidthEast - labelWidthWest)
+            / charWidth;
 
-    int startRes = av.getRanges().getStartRes();
-    int endx = startRes + columns - 1;
-    int ypos = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
-    ypos += repeatHeight * (visibleWidths - 1);
+    /**
+     * draw full height alignment in the second last row, last columns, if the
+     * last row was not full height
+     */
+    if (lastWidthPartHeight)
+    {
+      int widthsAbove = visibleWidths - 2;
+      int ypos = repeatHeight * widthsAbove + hgap;
+      int endRes = ranges.getEndRes();
+      endRes += widthsAbove * viewportWidth;
+      int startRes = endRes - columns;
+      int xOffset = ((startRes - ranges.getStartRes()) % viewportWidth)
+              * charWidth;
+      gg.translate(xOffset, 0);
+
+      /*
+       * white fill first to erase annotations
+       */
+      gg.setColor(Color.white);
+      gg.fillRect(labelWidthWest, ypos,
+              (endRes - startRes + 1) * charWidth, repeatHeight);
+
+      drawWrappedRegion(gg, startRes, endRes, canvasHeight, widthInColumns,
+              ypos);
+      gg.translate(-xOffset, 0);
+    }
+
+    /*
+     * y-offset for drawing is height of widths above,
+     * plus one gap row
+     */
+    int widthsAbove = visibleWidths - 1;
+    int ypos = repeatHeight * widthsAbove + hgap;
+    int endRes = ranges.getEndRes();
+    endRes += widthsAbove * viewportWidth;
+    endRes = Math.min(endRes, ranges.getVisibleAlignmentWidth());
+
+    /*
+     * draw one extra column than strictly needed - this is a (harmless)
+     * fudge to ensure scale marks get drawn (JAL-2636)
+     */
+    int startRes = endRes - columns;
+
+    /*
+     * x-offset is x-start modulo viewport start residue;
+     * doesn't include label West (offset is applied in drawWrappedRegion)
+     */
+
+    int leftEndColumn = ranges.getStartRes() + widthsAbove
+            * ranges.getViewportWidth();
+    // startRes = Math.max(startRes - 0, leftEndColumn);
+    int xOffset = ((startRes - ranges.getStartRes()) % viewportWidth)
+            * charWidth;
+    gg.translate(xOffset, 0);
+
+    /*
+     * white fill the region to be drawn including scale left or above;
+     * extend to right hand margin so as to erase scale above when
+     * scrolling right beyond end of alignment
+     */
+    gg.setColor(Color.white);
+    int width = getWidth() - labelWidthWest - xOffset;
+    gg.fillRect(labelWidthWest, ypos - hgap, width, repeatHeight);
 
     gg.setFont(av.getFont());
     gg.setColor(Color.black);
 
-    int cWidth = (getWidth() - labelWidthEast - labelWidthWest) / charWidth;
-
-    drawWrappedRegion(gg, startRes, endx, getHeight(), cWidth, ypos);
+    drawWrappedRegion(gg, startRes, endRes, canvasHeight, widthInColumns,
+            ypos);
+    gg.translate(-xOffset, 0);
 
+    /*
+     * draw scale right if shown, passing in the start/end columns
+     * for the whole line, not just the last few columns
+     */
     if (av.getScaleRightWrapped())
     {
-      drawVerticalScale(gg, startRes, endx, ypos, false);
+      drawVerticalScale(gg, leftEndColumn, endRes, ypos, false);
     }
   }
 
@@ -1330,7 +1419,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    * 
    * @param columns
    */
-  protected void fastPaintWrappedTopLeft(int columns)
+  protected void fastPaintWrappedAddLeft(int columns)
   {
     int startRes = av.getRanges().getStartRes();
 
@@ -1378,16 +1467,24 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
     int repeatHeight = getRepeatHeightWrapped();
     ViewportRanges ranges = av.getRanges();
+    int xMax = ranges.getVisibleAlignmentWidth();
     int widthToCopy = (ranges.getViewportWidth() - Math.abs(positions))
             * charWidth;
-    int visibleWidths = getHeight() / repeatHeight;
-    if (getHeight() % repeatHeight > 0)
+    int canvasHeight = getHeight();
+    int visibleWidths = canvasHeight / repeatHeight;
+    if (canvasHeight % repeatHeight > 0)
     {
       visibleWidths++;
     }
     int viewportWidth = ranges.getViewportWidth();
     int hgap = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
 
+    int remainder = canvasHeight % repeatHeight;
+    if (remainder >= (hgap + charHeight))
+    {
+      visibleWidths++;
+    }
+
     if (positions > 0)
     {
       /*
@@ -1402,13 +1499,12 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       /*
        * get y-offset of last wrapped width
        */
-      int y = getHeight() / repeatHeight * repeatHeight;
+      int y = canvasHeight / repeatHeight * repeatHeight;
       int copyFromLeftStart = labelWidthWest;
       int copyFromRightStart = copyFromLeftStart + widthToCopy;
 
       while (y >= 0)
       {
-        // todo limit repeatHeight for a last part height width?
         gg.copyArea(copyFromLeftStart, y, widthToCopy, repeatHeight,
                 positions * charWidth, 0);
         if (y > 0)
@@ -1445,12 +1541,12 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       int y = 0;
       int copyFromRightStart = labelWidthWest - positions * charWidth;
 
-      while (y < getHeight())
+      while (y < canvasHeight)
       {
-        // todo limit repeatHeight for a last part height width?
         gg.copyArea(copyFromRightStart, y, widthToCopy, repeatHeight,
                 positions * charWidth, 0);
-        if (y + repeatHeight < getHeight())
+        if (y + repeatHeight < canvasHeight - repeatHeight
+                && (xpos + viewportWidth <= xMax))
         {
           gg.copyArea(labelWidthWest, y + repeatHeight, -positions
                   * charWidth, repeatHeight, widthToCopy, -repeatHeight);
@@ -1466,7 +1562,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
         }
 
         y += repeatHeight;
-        xpos += ranges.getViewportWidth();
+        xpos += viewportWidth;
       }
     }
   }