JAL-1858 fastpaint highlights on wrapped alignment
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 5 Jul 2017 14:43:28 +0000 (15:43 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Wed, 5 Jul 2017 14:43:28 +0000 (15:43 +0100)
src/jalview/gui/SeqCanvas.java

index e2401d2..6099897 100755 (executable)
@@ -414,14 +414,15 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   }
 
   /**
-   * DOCUMENT ME!
+   * Returns the visible width of the canvas in residues, after allowing for
+   * East or West scales (if shown)
    * 
-   * @param cwidth
-   *          DOCUMENT ME!
+   * @param canvasWidth
+   *          the width in pixels (possibly including scales)
    * 
-   * @return DOCUMENT ME!
+   * @return
    */
-  public int getWrappedCanvasWidth(int cwidth)
+  public int getWrappedCanvasWidth(int canvasWidth)
   {
     FontMetrics fm = getFontMetrics(av.getFont());
 
@@ -435,10 +436,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
     if (av.getScaleLeftWrapped())
     {
-      labelWidthWest = getLabelWidth(fm);
+      labelWidthWest = labelWidthEast > 0 ? labelWidthEast
+              : getLabelWidth(fm);
     }
 
-    return (cwidth - labelWidthEast - labelWidthWest) / charWidth;
+    return (canvasWidth - labelWidthEast - labelWidthWest) / charWidth;
   }
 
   /**
@@ -451,11 +453,15 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    */
   protected int getLabelWidth(FontMetrics fm)
   {
+    /*
+     * find the biggest sequence end position we need to show
+     * (note this is not necessarily the sequence length)
+     */
     int maxWidth = 0;
-    for (int i = 0; i < av.getAlignment().getHeight(); i++)
+    AlignmentI alignment = av.getAlignment();
+    for (int i = 0; i < alignment.getHeight(); i++)
     {
-      maxWidth = Math.max(maxWidth, av.getAlignment().getSequenceAt(i)
-              .getEnd());
+      maxWidth = Math.max(maxWidth, alignment.getSequenceAt(i).getEnd());
     }
 
     int length = 2;
@@ -1002,21 +1008,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   {
     updateViewport();
 
-    /*
-     * for now, don't attempt fastpaint if wrapped format
-     */
     boolean wrapped = av.getWrapAlignment();
-    if (wrapped)
-    {
-      // drawWrappedMappedPositions(results);
-      // img = null;
-      // av.setSearchResults(results);
-      // repaint();
-      // return;
-    }
-    
-    fastpainting = true;
-    fastPaint = true;
 
     try
     {
@@ -1031,8 +1023,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       boolean drawn = false;
       if (wrapped)
       {
-        redrawn = drawWrappedMappedPositions(previous);
-        drawn = drawWrappedMappedPositions(results);
+        redrawn = drawMappedPositionsWrapped(previous);
+        drawn = drawMappedPositionsWrapped(results);
         redrawn |= drawn;
       }
       else
@@ -1199,16 +1191,16 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   }
 
   /**
-   * Redraws any positions in the search results in the visible region. Any
-   * highlights are drawn depending on the search results set on the Viewport,
-   * not the results parameter. This allows this method to be called to either
-   * clear highlighting (passing the previous search results), or set new
-   * highlighting.
+   * Redraws any positions in the search results in the visible region of a
+   * wrapped alignment. Any highlights are drawn depending on the search results
+   * set on the Viewport, not the <code>results</code> argument. This allows
+   * this method to be called either to clear highlights (passing the previous
+   * search results), or to draw new highlights.
    * 
    * @param results
    * @return
    */
-  protected boolean drawWrappedMappedPositions(SearchResultsI results)
+  protected boolean drawMappedPositionsWrapped(SearchResultsI results)
   {
     if (results == null)
     {
@@ -1216,15 +1208,22 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     }
   
     boolean matchFound = false;
-  
-    /*
-     * Viewport ranges are set for the 'row' of the wrapped alignment
-     * the cursor is in, not the whole visible region; really we want
-     * the latter; +-6 a temporary fudge for codons wrapping across lines
-     */
+
+    int wrappedWidth = av.getWrappedWidth();
+    int wrappedHeight = getRepeatHeightWrapped();
+
     ViewportRanges ranges = av.getRanges();
-    int firstVisibleColumn = ranges.getStartRes() - 6;
-    int lastVisibleColumn = ranges.getEndRes() + 6;
+    int canvasHeight = getHeight();
+    int repeats = wrappedHeight / canvasHeight;
+    if (wrappedHeight % canvasHeight > 0)
+    {
+      repeats++;
+    }
+
+    int firstVisibleColumn = ranges.getStartRes();
+    int lastVisibleColumn = ranges.getStartRes() + repeats
+            * ranges.getViewportWidth() - 1;
+
     AlignmentI alignment = av.getAlignment();
     if (av.hasHiddenColumns())
     {
@@ -1233,17 +1232,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
       lastVisibleColumn = alignment.getHiddenColumns()
               .adjustForHiddenColumns(lastVisibleColumn);
     }
-  
-    /*
-     * find width of alignment in residues, and height of alignment, 
-     * so we can calculate where to render each matched position
-     */
-    int wrappedWidth = av.getWrappedWidth();
-    int wrappedHeight = av.getAlignment().getHeight() * av.getCharHeight();
-    int gapHeight = av.getCharHeight()
-            * (av.getScaleAboveWrapped() ? 2 : 1);
-    wrappedHeight += gapHeight;
-    wrappedHeight += getAnnotationHeight();
+
+    int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
 
     for (int seqNo = ranges.getStartSeq(); seqNo <= ranges
             .getEndSeq(); seqNo++)
@@ -1316,4 +1306,25 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
   
     return matchFound;
   }
+
+  /**
+   * Answers the height in pixels of a repeating section of the wrapped
+   * alignment, including space above, scale above if shown, sequences, and
+   * annotation panel if shown
+   * 
+   * @return
+   */
+  protected int getRepeatHeightWrapped()
+  {
+    // gap (and maybe scale) above
+    int repeatHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
+
+    // add sequences
+    repeatHeight += av.getRanges().getViewportHeight() * charHeight;
+
+    // add annotations panel height if shown
+    repeatHeight += getAnnotationHeight();
+
+    return repeatHeight;
+  }
 }