JAL-1858 fast paint wrapped highlights unless view was scrolled
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 6 Jul 2017 16:39:37 +0000 (17:39 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 6 Jul 2017 16:39:37 +0000 (17:39 +0100)
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java

index 3994c29..027dd0f 100644 (file)
@@ -343,19 +343,11 @@ public class AlignmentPanel extends GAlignmentPanel implements
    */
   public void highlightSearchResults(SearchResultsI results)
   {
-    scrollToPosition(results);
-    getSeqPanel().seqCanvas.highlightSearchResults(results);
-  }
+    boolean scrolled = scrollToPosition(results, 0, true, false);
 
-  /**
-   * Scroll the view to show the position of the highlighted region in results
-   * (if any) and redraw the overview
-   * 
-   * @param results
-   */
-  public boolean scrollToPosition(SearchResultsI results)
-  {
-    return scrollToPosition(results, 0, true, false);
+    boolean noFastPaint = scrolled && av.getWrapAlignment();
+
+    getSeqPanel().seqCanvas.highlightSearchResults(results, noFastPaint);
   }
 
   /**
@@ -373,8 +365,10 @@ public class AlignmentPanel extends GAlignmentPanel implements
   }
 
   /**
-   * Scroll the view to show the position of the highlighted region in results
-   * (if any)
+   * Scrolls the view (if necessary) to show the position of the first
+   * highlighted region in results (if any). Answers true if the view was
+   * scrolled, or false if no matched region was found, or it is already
+   * visible.
    * 
    * @param results
    * @param verticalOffset
@@ -384,116 +378,117 @@ public class AlignmentPanel extends GAlignmentPanel implements
    *          - when set, the overview will be recalculated (takes longer)
    * @param centre
    *          if true, try to centre the search results horizontally in the view
-   * @return false if results were not found
+   * @return
    */
-  public boolean scrollToPosition(SearchResultsI results,
+  protected boolean scrollToPosition(SearchResultsI results,
           int verticalOffset, boolean redrawOverview, boolean centre)
   {
     int startv, endv, starts, ends;
-    // TODO: properly locate search results in view when large numbers of hidden
-    // columns exist before highlighted region
-    // do we need to scroll the panel?
-    // TODO: tons of nullpointerexceptions raised here.
-    if (results != null && results.getSize() > 0 && av != null
-            && av.getAlignment() != null)
-    {
-      int seqIndex = av.getAlignment().findIndex(results);
-      if (seqIndex == -1)
-      {
-        return false;
-      }
-      SequenceI seq = av.getAlignment().getSequenceAt(seqIndex);
 
-      int[] r = results.getResults(seq, 0, av.getAlignment().getWidth());
-      if (r == null)
-      {
-        return false;
-      }
-      int start = r[0];
-      int end = r[1];
+    if (results == null || results.isEmpty() || av == null
+            || av.getAlignment() == null)
+    {
+      return false;
+    }
+    int seqIndex = av.getAlignment().findIndex(results);
+    if (seqIndex == -1)
+    {
+      return false;
+    }
+    SequenceI seq = av.getAlignment().getSequenceAt(seqIndex);
 
-      /*
-       * To centre results, scroll to positions half the visible width
-       * left/right of the start/end positions
-       */
-      if (centre)
-      {
-        int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2
-                - 1;
-        start = Math.max(start - offset, 0);
-        end = end + offset - 1;
-      }
-      if (start < 0)
-      {
-        return false;
-      }
-      if (end == seq.getEnd())
-      {
-        return false;
-      }
-      if (av.hasHiddenColumns())
+    int[] r = results.getResults(seq, 0, av.getAlignment().getWidth());
+    if (r == null)
+    {
+      return false;
+    }
+    int start = r[0];
+    int end = r[1];
+
+    /*
+     * To centre results, scroll to positions half the visible width
+     * left/right of the start/end positions
+     */
+    if (centre)
+    {
+      int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1;
+      start = Math.max(start - offset, 0);
+      end = end + offset - 1;
+    }
+    if (start < 0)
+    {
+      return false;
+    }
+    if (end == seq.getEnd())
+    {
+      return false;
+    }
+
+    if (av.hasHiddenColumns())
+    {
+      HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+      start = hidden.findColumnPosition(start);
+      end = hidden.findColumnPosition(end);
+      if (start == end)
       {
-        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
-        start = hidden.findColumnPosition(start);
-        end = hidden.findColumnPosition(end);
-        if (start == end)
+        if (!hidden.isVisible(r[0]))
         {
-          if (!hidden.isVisible(r[0]))
-          {
-            // don't scroll - position isn't visible
-            return false;
-          }
+          // don't scroll - position isn't visible
+          return false;
         }
       }
+    }
 
-      /*
-       * allow for offset of target sequence (actually scroll to one above it)
-       */
-      seqIndex = Math.max(0, seqIndex - verticalOffset);
+    /*
+     * allow for offset of target sequence (actually scroll to one above it)
+     */
+    seqIndex = Math.max(0, seqIndex - verticalOffset);
+    boolean scrollNeeded = true;
 
-      if (!av.getWrapAlignment())
+    if (!av.getWrapAlignment())
+    {
+      if ((startv = vpRanges.getStartRes()) >= start)
       {
-        if ((startv = vpRanges.getStartRes()) >= start)
-        {
-          /*
-           * Scroll left to make start of search results visible
-           */
-          setScrollValues(start, seqIndex);
-        }
-        else if ((endv = vpRanges.getEndRes()) <= end)
-        {
-          /*
-           * Scroll right to make end of search results visible
-           */
-          setScrollValues(startv + end - endv, seqIndex);
-        }
-        else if ((starts = vpRanges.getStartSeq()) > seqIndex)
-        {
-          /*
-           * Scroll up to make start of search results visible
-           */
-          setScrollValues(vpRanges.getStartRes(), seqIndex);
-        }
-        else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
-        {
-          /*
-           * Scroll down to make end of search results visible
-           */
-          setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends
-                  + 1);
-        }
         /*
-         * Else results are already visible - no need to scroll
+         * Scroll left to make start of search results visible
          */
+        setScrollValues(start, seqIndex);
       }
-      else
+      else if ((endv = vpRanges.getEndRes()) <= end)
       {
-        vpRanges.scrollToWrappedVisible(start);
+        /*
+         * Scroll right to make end of search results visible
+         */
+        setScrollValues(startv + end - endv, seqIndex);
+      }
+      else if ((starts = vpRanges.getStartSeq()) > seqIndex)
+      {
+        /*
+         * Scroll up to make start of search results visible
+         */
+        setScrollValues(vpRanges.getStartRes(), seqIndex);
       }
+      else if ((ends = vpRanges.getEndSeq()) <= seqIndex)
+      {
+        /*
+         * Scroll down to make end of search results visible
+         */
+        setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends
+                + 1);
+      }
+      /*
+       * Else results are already visible - no need to scroll
+       */
+      scrollNeeded = false;
+    }
+    else
+    {
+      scrollNeeded = vpRanges.scrollToWrappedVisible(start);
     }
 
     paintAlignment(redrawOverview);
-    return true;
+
+    return scrollNeeded;
   }
 
   /**
@@ -1815,7 +1810,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @param verticalOffset
    *          the number of visible sequences to show above the mapped region
    */
-  public void scrollToCentre(SearchResultsI sr, int verticalOffset)
+  protected void scrollToCentre(SearchResultsI sr, int verticalOffset)
   {
     /*
      * To avoid jumpy vertical scrolling (if some sequences are gapped or not
index 5c7bd4e..6f6bc02 100644 (file)
@@ -271,7 +271,8 @@ public class FeatureRenderer extends
             highlight.addResult(sequences.get(0), sf.getBegin(),
                     sf.getEnd());
 
-            alignPanel.getSeqPanel().seqCanvas.highlightSearchResults(highlight);
+            alignPanel.getSeqPanel().seqCanvas.highlightSearchResults(
+                    highlight, false);
 
           }
           FeatureColourI col = getFeatureStyle(name.getText());
index 6099897..47ef7cf 100755 (executable)
@@ -1000,18 +1000,33 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
    * on a black background. Any previous highlighting is removed. Answers true
    * if any highlight was left on the visible alignment (so status bar should be
    * set to match), else false.
+   * <p>
+   * Currently fastPaint is not implemented for wrapped alignments. If a wrapped
+   * alignment had to be scrolled to show the highlighted region, then it should
+   * be fully redrawn, otherwise a fast paint can be performed. This argument
+   * could be removed if fast paint of scrolled wrapped alignment is coded in
+   * future (JAL-2609).
    * 
    * @param results
+   * @param noFastPaint
    * @return
    */
-  public boolean highlightSearchResults(SearchResultsI results)
+  public boolean highlightSearchResults(SearchResultsI results,
+          boolean noFastPaint)
   {
-    updateViewport();
-
+    if (fastpainting)
+    {
+      return false;
+    }
     boolean wrapped = av.getWrapAlignment();
 
     try
     {
+      fastPaint = !noFastPaint;
+      fastpainting = fastPaint;
+
+      updateViewport();
+
       /*
        * to avoid redrawing the whole visible region, we instead
        * redraw just the minimal regions to remove previous highlights
@@ -1051,7 +1066,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
     {
       fastpainting = false;
     }
-
   }
 
   /**
@@ -1214,8 +1228,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
 
     ViewportRanges ranges = av.getRanges();
     int canvasHeight = getHeight();
-    int repeats = wrappedHeight / canvasHeight;
-    if (wrappedHeight % canvasHeight > 0)
+    int repeats = canvasHeight / wrappedHeight;
+    if (canvasHeight / wrappedHeight > 0)
     {
       repeats++;
     }
@@ -1283,7 +1297,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI
                * transY: offset from top edge of canvas to residue position
                */
               int transY = gapHeight;
-              transY += (displayColumn / wrappedWidth) * wrappedHeight;
+              transY += (displayColumn - ranges.getStartRes())
+                      / wrappedWidth * wrappedHeight;
               transY += (seqNo - ranges.getStartSeq()) * av.getCharHeight();
 
               /*
index 1a3081f..ca79c73 100644 (file)
@@ -681,6 +681,8 @@ public class SeqPanel extends JPanel implements MouseListener,
     }
     lastSearchResults = results;
 
+    boolean wasScrolled = false;
+
     if (av.isFollowHighlight())
     {
       // don't allow highlight of protein/cDNA to also scroll a complementary
@@ -688,13 +690,16 @@ public class SeqPanel extends JPanel implements MouseListener,
       // over residue to change abruptly, causing highlighted residue in panel 2
       // to change, causing a scroll in panel 1 etc)
       ap.setToScrollComplementPanel(false);
-      if (ap.scrollToPosition(results, false))
+      wasScrolled = ap.scrollToPosition(results, false);
+      if (wasScrolled)
       {
         seqCanvas.revalidate();
       }
       ap.setToScrollComplementPanel(true);
     }
-    if (seqCanvas.highlightSearchResults(results))
+
+    boolean noFastPaint = wasScrolled && av.getWrapAlignment();
+    if (seqCanvas.highlightSearchResults(results, noFastPaint))
     {
       setStatusMessage(results);
     }
@@ -1594,7 +1599,7 @@ public class SeqPanel extends JPanel implements MouseListener,
         SearchResultsI highlight = new SearchResults();
         highlight.addResult(sequence, features.get(0).getBegin(), features
                 .get(0).getEnd());
-        seqCanvas.highlightSearchResults(highlight);
+        seqCanvas.highlightSearchResults(highlight, false);
 
         /*
          * open the Amend Features dialog; clear highlighting afterwards,