JAL-2609 progress on scroll left draw new columns
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 1 Aug 2017 09:30:15 +0000 (11:30 +0200)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 1 Aug 2017 09:30:15 +0000 (11:30 +0200)
src/jalview/gui/SeqCanvas.java

index 8c8b1d8..6836531 100755 (executable)
@@ -119,10 +119,12 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   }
 
   /**
-   * DOCUMENT ME!
+   * Draws the scale above a region of a wrapped alignment, consisting of a
+   * column number every 10 columns.
    * 
    * @param g
-   *          DOCUMENT ME!
+   *          the graphics context to draw on, positioned at the start (bottom
+   *          left) of the
    * @param startx
    *          DOCUMENT ME!
    * @param endx
@@ -133,8 +135,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   private void drawNorthScale(Graphics g, int startx, int endx, int ypos)
   {
     updateViewport();
-    for (ScaleMark mark : new ScaleRenderer().calculateMarks(av, startx,
-            endx))
+    List<ScaleMark> marks = new ScaleRenderer().calculateMarks(av, startx,
+            endx);
+    for (ScaleMark mark : marks)
     {
       int mpos = mark.column; // (i - startx - 1)
       if (mpos < 0)
@@ -149,9 +152,13 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
         {
           g.drawString(mstring, mpos * charWidth, ypos - (charHeight / 2));
         }
-        g.drawLine((mpos * charWidth) + (charWidth / 2), (ypos + 2)
-                - (charHeight / 2), (mpos * charWidth) + (charWidth / 2),
-                ypos - 2);
+
+        /*
+         * draw a tick mark below the column number, centred on the column;
+         * height of tick mark is 4 pixels less than half a character
+         */
+        int xpos = (mpos * charWidth) + (charWidth / 2);
+        g.drawLine(xpos, (ypos + 2) - (charHeight / 2), xpos, ypos - 2);
       }
     }
   }
@@ -222,7 +229,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
         g.setColor(Color.white);
         int y = (ypos + (i * charHeight)) - (charHeight / 5);
-        g.fillRect(xpos, y, justify, charHeight);
+        y -= charHeight; // fillRect starts from top right of rectangle
+        g.fillRect(xpos, y, justify - charWidth, charHeight + 1);
+        y += charHeight; // drawString starts from bottom right of text
         g.setColor(Color.black);
         g.drawString(valueAsString, xpos, y);
       }
@@ -230,13 +239,22 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   }
 
   /**
-   * need to make this thread safe move alignment rendering in response to
-   * slider adjustment
+   * Does a fast paint of an alignment in response to a scroll. Most of the
+   * visible region is simply copied and shifted, and then any newly visible
+   * columns or rows are drawn. The scroll may be horizontal or vertical, but
+   * not both at once. Scrolling may be the result of
+   * <ul>
+   * <li>dragging a scroll bar</li>
+   * <li>clicking in the scroll bar</li>
+   * <li>scrolling by trackpad, middle mouse button, or other device</li>
+   * <li>by moving the box in the Overview window</li>
+   * <li>programmatically to make a highlighted position visible</li>
+   * </ul>
    * 
    * @param horizontal
-   *          shift along
+   *          columns to shift right (positive) or left (negative)
    * @param vertical
-   *          shift up or down in repaint
+   *          rows to shift down (positive) or up (negative)
    */
   public void fastPaint(int horizontal, int vertical)
   {
@@ -433,16 +451,16 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   }
 
   /**
-   * DOCUMENT ME!
+   * Draws as many widths of a wrapped alignment as can fit in the visible
+   * window
    * 
    * @param g
-   *          DOCUMENT ME!
    * @param canvasWidth
-   *          DOCUMENT ME!
+   *          available width in pixels
    * @param canvasHeight
-   *          DOCUMENT ME!
+   *          available height in pixels
    * @param startRes
-   *          DOCUMENT ME!
+   *          the first visible column (0...) of the alignment to draw
    */
   public void drawWrappedPanel(Graphics g, int canvasWidth,
           int canvasHeight, int startRes)
@@ -482,6 +500,10 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     int annotationHeight = getAnnotationHeight();
     int sequencesHeight = av.getAlignment().getHeight() * charHeight;
 
+    /*
+     * draw one width at a time (including any scales or annotation shown),
+     * until we have run out of alignment or vertical space available
+     */
     while ((ypos <= canvasHeight) && (startRes < maxwidth))
     {
       drawWrappedWidth(g, startRes, canvasHeight, cWidth, maxwidth, ypos);
@@ -524,13 +546,31 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       drawVerticalScale(g, startRes, endx, ypos, false);
     }
 
+    drawWrappedRegion(g, startRes, endx, canvasHeight, canvasWidth, ypos);
+  }
+
+  /**
+   * Draws columns of a wrapped alignment from startRes to endRes, including
+   * scale above and annotations if shown, but not scale left or right.
+   * 
+   * @param g
+   * @param startRes
+   * @param endRes
+   * @param canvasHeight
+   * @param canvasWidth
+   * @param ypos
+   */
+  protected void drawWrappedRegion(Graphics g, int startRes, int endRes,
+          int canvasHeight, int canvasWidth, int ypos)
+  {
     g.translate(labelWidthWest, 0);
 
     if (av.getScaleAboveWrapped())
     {
-      drawNorthScale(g, startRes, endx, ypos);
+      drawNorthScale(g, startRes, endRes, ypos);
     }
 
+    // todo can we let drawPanel() handle this?
     if (av.hasHiddenColumns() && av.getShowHiddenMarkers())
     {
       g.setColor(Color.blue);
@@ -540,7 +580,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       {
         int res = pos - startRes;
 
-        if (res < 0 || res > endx - startRes)
+        if (res < 0 || res > endRes - startRes)
         {
           continue;
         }
@@ -549,7 +589,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
             res * charWidth + charHeight / 4, res * charWidth }, new int[] {
             ypos - (charHeight / 2), ypos - (charHeight / 2),
             ypos - (charHeight / 2) + 8 }, 3);
-
       }
     }
 
@@ -567,7 +606,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
               (int) clip.getBounds().getHeight());
     }
 
-    drawPanel(g, startRes, endx, 0, av.getAlignment().getHeight() - 1, ypos);
+    drawPanel(g, startRes, endRes, 0, av.getAlignment().getHeight() - 1, ypos);
 
     int cHeight = av.getAlignment().getHeight() * charHeight;
 
@@ -580,7 +619,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       }
 
       annotations.renderer.drawComponent(annotations, av, g, -1, startRes,
-              endx + 1);
+              endRes + 1);
       g.translate(0, -cHeight - ypos - 3);
     }
     g.setClip(clip);
@@ -611,14 +650,15 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    * marker.
    * 
    * @param g1
+   *          the graphics context, positioned at the first residue to be drawn
    * @param startRes
-   *          offset of the first column in the visible region (0..)
+   *          offset of the first column to draw (0..)
    * @param endRes
-   *          offset of the last column in the visible region (0..)
+   *          offset of the last column to draw (0..)
    * @param startSeq
-   *          offset of the first sequence in the visible region (0..)
+   *          offset of the first sequence to draw (0..)
    * @param endSeq
-   *          offset of the last sequence in the visible region (0..)
+   *          offset of the last sequence to draw (0..)
    * @param yOffset
    *          vertical offset at which to draw (for wrapped alignments)
    */
@@ -1134,7 +1174,14 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   {
     String eventName = evt.getPropertyName();
 
-    if (true/*!av.getWrapAlignment()*/)
+    // if (av.getWrapAlignment())
+    // {
+    // if (eventName.equals(ViewportRanges.STARTRES))
+    // {
+    // repaint();
+    // }
+    // }
+    // else
     {
       int scrollX = 0;
       if (eventName.equals(ViewportRanges.STARTRES))
@@ -1165,6 +1212,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
         if (av.getWrapAlignment())
         {
           fastPaintWrapped(scrollX);
+          // fastPaintWrapped(scrollX > 0 ? 1 : -1); // to debug: 1 at a time
         }
         else
         {
@@ -1173,7 +1221,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       }
       else if (eventName.equals(ViewportRanges.STARTSEQ))
       {
-        // scroll
         fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
       }
     }
@@ -1193,8 +1240,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     if (Math.abs(scrollX) > av.getRanges().getViewportWidth())
     {
       /*
-       * shift of more than one view width is too much
-       * to handle in this method
+       * shift of more than one view width is 
+       * too complicated to handle in this method
        */
       fastPaint = false;
       repaint();
@@ -1202,15 +1249,106 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     }
 
     fastPaint = true;
+
+    /*
+     * relocate the regions of the alignment that are still visible
+     */
     shiftWrappedAlignment(-scrollX);
 
-    // add new columns (scale above, sequence, annotation)
-    // at top left if scrollX < 0 or bottom right if scrollX > 0
+    /*
+     * add new columns (scale above, sequence, annotation)
+     * at top left if scrollX < 0 or bottom right if scrollX > 0
+     * also West scale top left or East scale bottom right if shown
+     */
+    if (scrollX < 0)
+    {
+      fastPaintWrappedTopLeft(-scrollX);
+    }
+    else
+    {
+      // fastPaintWrappedBottomRight(scrollX);
+    }
 
     repaint();
   }
 
   /**
+   * 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
+   * 
+   * @param columns
+   */
+  protected void fastPaintWrappedBottomRight(int columns)
+  {
+    if (columns == 0)
+    {
+      return;
+    }
+
+    int repeatHeight = getRepeatHeightWrapped();
+    ViewportRanges ranges = av.getRanges();
+    int visibleWidths = getHeight() / repeatHeight;
+    if (getHeight() % repeatHeight > 0)
+    {
+      visibleWidths++;
+    }
+    int viewportWidth = ranges.getViewportWidth();
+    int hgap = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
+
+    int startRes = av.getRanges().getStartRes();
+    int endx = startRes + columns - 1;
+    int ypos = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
+    ypos += repeatHeight * (visibleWidths - 1);
+
+    gg.setFont(av.getFont());
+    gg.setColor(Color.black);
+
+    int cWidth = (getWidth() - labelWidthEast - labelWidthWest) / charWidth;
+
+    drawWrappedRegion(gg, startRes, endx, getHeight(), cWidth, ypos);
+
+    if (av.getScaleRightWrapped())
+    {
+      drawVerticalScale(gg, startRes, endx, ypos, false);
+    }
+  }
+
+  /**
+   * Draws the specified number of columns at the 'start' (top left) of a
+   * wrapped alignment view, including scale above and left and annotations if
+   * shown
+   * 
+   * @param columns
+   */
+  protected void fastPaintWrappedTopLeft(int columns)
+  {
+    int startRes = av.getRanges().getStartRes();
+    int endx = startRes + columns - 1;
+    int ypos = 0;
+
+    /*
+     * white fill the region to be drawn including scale left or above
+     */
+    gg.setColor(Color.white);
+    int height = getRepeatHeightWrapped();
+    gg.fillRect(0, ypos, labelWidthWest + columns * charWidth, height);
+    ypos += charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
+
+    gg.setFont(av.getFont());
+    gg.setColor(Color.black);
+
+    if (av.getScaleLeftWrapped())
+    {
+      drawVerticalScale(gg, startRes, endx, ypos, true);
+    }
+
+    int cWidth = (getWidth() - labelWidthEast - labelWidthWest) / charWidth;
+
+    drawWrappedRegion(gg, startRes, endx, getHeight(), cWidth, ypos);
+  }
+
+  /**
    * Shifts the visible alignment by the specified number of columns - left if
    * negative, right if positive. Includes scale above, left or right and
    * annotations (if shown). Does not draw newly visible columns.
@@ -1256,7 +1394,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
       while (y >= 0)
       {
-        // todo limit repeatHeight for a last part height width
+        // todo limit repeatHeight for a last part height width?
         gg.copyArea(copyFromLeftStart, y, widthToCopy, repeatHeight,
                 positions * charWidth, 0);
         if (y > 0)
@@ -1293,7 +1431,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
       while (y < getHeight())
       {
-        // todo limit repeatHeight for a last part height width
+        // todo limit repeatHeight for a last part height width?
         gg.copyArea(copyFromRightStart, y, widthToCopy, repeatHeight,
                 positions * charWidth, 0);
         if (y + repeatHeight < getHeight())