Merge branch 'develop' into feature/JAL-2759
[jalview.git] / src / jalview / appletgui / SeqCanvas.java
index 9de5452..2c90047 100755 (executable)
@@ -25,6 +25,7 @@ import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResultsI;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.VisibleContigsIterator;
 import jalview.renderer.ScaleRenderer;
 import jalview.renderer.ScaleRenderer.ScaleMark;
 import jalview.viewmodel.AlignmentViewport;
@@ -37,7 +38,7 @@ import java.awt.Graphics;
 import java.awt.Image;
 import java.awt.Panel;
 import java.beans.PropertyChangeEvent;
-import java.util.List;
+import java.util.Iterator;
 
 public class SeqCanvas extends Panel implements ViewportListenerI
 {
@@ -113,12 +114,12 @@ public class SeqCanvas extends Panel implements ViewportListenerI
       {
         if (mstring != null)
         {
-          g.drawString(mstring, mpos * avcharWidth, ypos
-                  - (avcharHeight / 2));
+          g.drawString(mstring, mpos * avcharWidth,
+                  ypos - (avcharHeight / 2));
         }
-        g.drawLine((mpos * avcharWidth) + (avcharWidth / 2), (ypos + 2)
-                - (avcharHeight / 2), (mpos * avcharWidth)
-                + (avcharWidth / 2), ypos - 2);
+        g.drawLine((mpos * avcharWidth) + (avcharWidth / 2),
+                (ypos + 2) - (avcharHeight / 2),
+                (mpos * avcharWidth) + (avcharWidth / 2), ypos - 2);
       }
     }
   }
@@ -167,8 +168,8 @@ public class SeqCanvas extends Panel implements ViewportListenerI
       {
         int x = LABEL_WEST - fm.stringWidth(String.valueOf(value))
                 - avcharWidth / 2;
-        g.drawString(value + "", x, (ypos + (i * avcharHeight))
-                - (avcharHeight / 5));
+        g.drawString(value + "", x,
+                (ypos + (i * avcharHeight)) - (avcharHeight / 5));
       }
     }
   }
@@ -207,8 +208,8 @@ public class SeqCanvas extends Panel implements ViewportListenerI
 
       if (value != -1)
       {
-        g.drawString(String.valueOf(value), 0, (ypos + (i * avcharHeight))
-                - (avcharHeight / 5));
+        g.drawString(String.valueOf(value), 0,
+                (ypos + (i * avcharHeight)) - (avcharHeight / 5));
       }
     }
   }
@@ -237,14 +238,14 @@ public class SeqCanvas extends Panel implements ViewportListenerI
     lastsr = ranges.getStartRes();
 
     fastPaint = true;
-    gg.copyArea(horizontal * avcharWidth, vertical * avcharHeight, imgWidth
-            - horizontal * avcharWidth,
+    gg.copyArea(horizontal * avcharWidth, vertical * avcharHeight,
+            imgWidth - horizontal * avcharWidth,
             imgHeight - vertical * avcharHeight, -horizontal * avcharWidth,
             -vertical * avcharHeight);
 
-    int sr = ranges.getStartRes(), er = ranges.getEndRes(), ss = ranges
-            .getStartSeq(), es = ranges
-            .getEndSeq(), transX = 0, transY = 0;
+    int sr = ranges.getStartRes(), er = ranges.getEndRes(),
+            ss = ranges.getStartSeq(), es = ranges.getEndSeq(), transX = 0,
+            transY = 0;
 
     if (horizontal > 0) // scrollbar pulled right, image to the left
     {
@@ -261,7 +262,7 @@ public class SeqCanvas extends Panel implements ViewportListenerI
       ss = es - vertical;
       if (ss < ranges.getStartSeq()) // ie scrolling too fast, more than a page
                                      // at a
-                                 // time
+      // time
       {
         ss = ranges.getStartSeq();
       }
@@ -307,8 +308,8 @@ public class SeqCanvas extends Panel implements ViewportListenerI
   {
 
     if (img != null
-            && (fastPaint || (getSize().width != g.getClipBounds().width) || (getSize().height != g
-                    .getClipBounds().height)))
+            && (fastPaint || (getSize().width != g.getClipBounds().width)
+                    || (getSize().height != g.getClipBounds().height)))
     {
       g.drawImage(img, 0, 0, this);
       fastPaint = false;
@@ -417,71 +418,71 @@ public class SeqCanvas extends Panel implements ViewportListenerI
           int canvasHeight, int startRes)
   {
     AlignmentI al = av.getAlignment();
-
+  
     FontMetrics fm = getFontMetrics(av.getFont());
-
+  
     LABEL_EAST = 0;
     LABEL_WEST = 0;
-
+  
     if (av.getScaleRightWrapped())
     {
       LABEL_EAST = fm.stringWidth(getMask());
     }
-
+  
     if (av.getScaleLeftWrapped())
     {
       LABEL_WEST = fm.stringWidth(getMask());
     }
-
+  
     int hgap = avcharHeight;
     if (av.getScaleAboveWrapped())
     {
       hgap += avcharHeight;
     }
-
+  
     int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / avcharWidth;
     int cHeight = av.getAlignment().getHeight() * avcharHeight;
-
+  
     av.setWrappedWidth(cWidth);
-
+  
     av.getRanges().setViewportStartAndWidth(startRes, cWidth);
-
+  
     int endx;
     int ypos = hgap;
-
+  
     int maxwidth = av.getAlignment().getWidth();
-
+  
     if (av.hasHiddenColumns())
     {
       maxwidth = av.getAlignment().getHiddenColumns()
               .findColumnPosition(maxwidth);
     }
-
+  
     while ((ypos <= canvasHeight) && (startRes < maxwidth))
     {
       endx = startRes + cWidth - 1;
-
+  
       if (endx > maxwidth)
       {
         endx = maxwidth;
       }
-
+  
       g.setColor(Color.black);
-
+  
       if (av.getScaleLeftWrapped())
       {
         drawWestScale(g, startRes, endx, ypos);
       }
-
+  
       if (av.getScaleRightWrapped())
       {
         g.translate(canvasWidth - LABEL_EAST, 0);
         drawEastScale(g, startRes, endx, ypos);
         g.translate(-(canvasWidth - LABEL_EAST), 0);
       }
-
+  
       g.translate(LABEL_WEST, 0);
-
+  
       if (av.getScaleAboveWrapped())
       {
         drawNorthScale(g, startRes, endx, ypos);
@@ -491,33 +492,27 @@ public class SeqCanvas extends Panel implements ViewportListenerI
         HiddenColumns hidden = av.getAlignment().getHiddenColumns();
         g.setColor(Color.blue);
         int res;
-        List<Integer> positions = hidden.findHiddenRegionPositions();
-        for (int pos : positions)
+        Iterator<Integer> it = hidden.getBoundedStartIterator(startRes,
+                endx + 1);
+        while (it.hasNext())
         {
-          res = pos - startRes;
-
-          if (res < 0 || res > endx - startRes)
-          {
-            continue;
-          }
-
-          gg.fillPolygon(new int[] { res * avcharWidth - avcharHeight / 4,
-              res * avcharWidth + avcharHeight / 4, res * avcharWidth },
-                  new int[] { ypos - (avcharHeight / 2),
-                      ypos - (avcharHeight / 2),
-                      ypos - (avcharHeight / 2) + 8 }, 3);
-
+          res = it.next() - startRes;
+          gg.fillPolygon(
+                  new int[]
+                  { res * avcharWidth - avcharHeight / 4, res * avcharWidth + avcharHeight / 4, res * avcharWidth },
+                  new int[]
+                  { ypos - (avcharHeight / 2), ypos - (avcharHeight / 2), ypos - (avcharHeight / 2) + 8 }, 3);
         }
       }
-
+  
       if (g.getClip() == null)
       {
         g.setClip(0, 0, cWidth * avcharWidth, canvasHeight);
       }
-
+  
       drawPanel(g, startRes, endx, 0, al.getHeight() - 1, ypos);
       g.setClip(null);
-
+  
       if (av.isShowAnnotation())
       {
         g.translate(0, cHeight + ypos + 4);
@@ -525,17 +520,17 @@ public class SeqCanvas extends Panel implements ViewportListenerI
         {
           annotations = new AnnotationPanel(av);
         }
-
+  
         annotations.drawComponent(g, startRes, endx + 1);
         g.translate(0, -cHeight - ypos - 4);
       }
       g.translate(-LABEL_WEST, 0);
-
+  
       ypos += cHeight + getAnnotationHeight() + hgap;
-
+  
       startRes += cWidth;
     }
-
+  
   }
 
   AnnotationPanel annotations;
@@ -555,8 +550,8 @@ public class SeqCanvas extends Panel implements ViewportListenerI
     return annotations.adjustPanelHeight();
   }
 
-  private void drawPanel(Graphics g1, int startRes, int endRes,
-          int startSeq, int endSeq, int offset)
+  private void drawPanel(Graphics g1, final int startRes, final int endRes,
+          final int startSeq, final int endSeq, final int offset)
   {
 
     if (!av.hasHiddenColumns())
@@ -565,62 +560,45 @@ public class SeqCanvas extends Panel implements ViewportListenerI
     }
     else
     {
-
       int screenY = 0;
-      int blockStart = startRes;
-      int blockEnd = endRes;
-
-      if (av.hasHiddenColumns())
-      {
-        HiddenColumns hidden = av.getAlignment().getHiddenColumns();
-        for (int[] region : hidden.getHiddenColumnsCopy())
-        {
-          int hideStart = region[0];
-          int hideEnd = region[1];
-
-          if (hideStart <= blockStart)
-          {
-            blockStart += (hideEnd - hideStart) + 1;
-            continue;
-          }
-
-          blockEnd = hideStart - 1;
-
-          g1.translate(screenY * avcharWidth, 0);
-
-          draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
-
-          if (av.getShowHiddenMarkers())
-          {
-            g1.setColor(Color.blue);
-            g1.drawLine((blockEnd - blockStart + 1) * avcharWidth - 1,
-                    0 + offset, (blockEnd - blockStart + 1) * avcharWidth
-                            - 1, (endSeq - startSeq + 1) * avcharHeight
-                            + offset);
-          }
+      int blockStart;
+      int blockEnd;
 
-          g1.translate(-screenY * avcharWidth, 0);
-          screenY += blockEnd - blockStart + 1;
-          blockStart = hideEnd + 1;
+      HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+      VisibleContigsIterator regions = (VisibleContigsIterator) hidden
+              .getVisibleBlocksIterator(startRes, endRes, true);
 
-          if (screenY > (endRes - startRes))
-          {
-            // already rendered last block
-            return;
-          }
-        }
-      }
-      if (screenY <= (endRes - startRes))
+      while (regions.hasNext())
       {
-        // remaining visible region to render
-        blockEnd = blockStart + (endRes - startRes) - screenY;
+        int[] region = regions.next();
+        blockEnd = region[1];
+        blockStart = region[0];
+
+        /*
+         * draw up to just before the next hidden region, or the end of
+         * the visible region, whichever comes first
+         */
         g1.translate(screenY * avcharWidth, 0);
+
         draw(g1, blockStart, blockEnd, startSeq, endSeq, offset);
 
+        /*
+         * draw the downline of the hidden column marker (ScalePanel draws the
+         * triangle on top) if we reached it
+         */
+        if (av.getShowHiddenMarkers()
+                && (regions.hasNext() || regions.endsAtHidden()))
+        {
+          g1.setColor(Color.blue);
+          g1.drawLine((blockEnd - blockStart + 1) * avcharWidth - 1,
+                  0 + offset, (blockEnd - blockStart + 1) * avcharWidth - 1,
+                  (endSeq - startSeq + 1) * avcharHeight + offset);
+        }
+
         g1.translate(-screenY * avcharWidth, 0);
+        screenY += blockEnd - blockStart + 1;
       }
     }
-
   }
 
   // int startRes, int endRes, int startSeq, int endSeq, int x, int y,
@@ -649,8 +627,8 @@ public class SeqCanvas extends Panel implements ViewportListenerI
 
       if (av.isShowSequenceFeatures())
       {
-        fr.drawSequence(g, nextSeq, startRes, endRes, offset
-                + ((i - startSeq) * avcharHeight), false);
+        fr.drawSequence(g, nextSeq, startRes, endRes,
+                offset + ((i - startSeq) * avcharHeight), false);
       }
 
       // / Highlight search Results once all sequences have been drawn
@@ -658,16 +636,15 @@ public class SeqCanvas extends Panel implements ViewportListenerI
       if (av.hasSearchResults())
       {
         int[] visibleResults = av.getSearchResults().getResults(nextSeq,
-                startRes,
-                endRes);
+                startRes, endRes);
         if (visibleResults != null)
         {
           for (int r = 0; r < visibleResults.length; r += 2)
           {
             sr.drawHighlightedText(nextSeq, visibleResults[r],
-                    visibleResults[r + 1], (visibleResults[r] - startRes)
-                            * avcharWidth, offset
-                            + ((i - startSeq) * avcharHeight));
+                    visibleResults[r + 1],
+                    (visibleResults[r] - startRes) * avcharWidth,
+                    offset + ((i - startSeq) * avcharHeight));
           }
         }
       }
@@ -723,7 +700,8 @@ public class SeqCanvas extends Panel implements ViewportListenerI
         {
           sx = (group.getStartRes() - startRes) * avcharWidth;
           sy = offset + ((i - startSeq) * avcharHeight);
-          ex = (((group.getEndRes() + 1) - group.getStartRes()) * avcharWidth) - 1;
+          ex = (((group.getEndRes() + 1) - group.getStartRes())
+                  * avcharWidth) - 1;
 
           if (sx + ex < 0 || sx > imgWidth)
           {
@@ -731,22 +709,20 @@ public class SeqCanvas extends Panel implements ViewportListenerI
           }
 
           if ((sx <= (endRes - startRes) * avcharWidth)
-                  && group.getSequences(null).contains(
-                          av.getAlignment().getSequenceAt(i)))
+                  && group.getSequences(null)
+                          .contains(av.getAlignment().getSequenceAt(i)))
           {
             if ((bottom == -1)
-                    && (i >= alHeight || !group.getSequences(null)
-                            .contains(
-                                    av.getAlignment().getSequenceAt(i + 1))))
+                    && (i >= alHeight || !group.getSequences(null).contains(
+                            av.getAlignment().getSequenceAt(i + 1))))
             {
               bottom = sy + avcharHeight;
             }
 
             if (!inGroup)
             {
-              if (((top == -1) && (i == 0))
-                      || !group.getSequences(null).contains(
-                              av.getAlignment().getSequenceAt(i - 1)))
+              if (((top == -1) && (i == 0)) || !group.getSequences(null)
+                      .contains(av.getAlignment().getSequenceAt(i - 1)))
               {
                 top = sy;
               }
@@ -878,15 +854,37 @@ public class SeqCanvas extends Panel implements ViewportListenerI
   {
     String eventName = evt.getPropertyName();
 
+    if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED))
+    {
+      fastPaint = true;
+      repaint();
+      return;
+    }
+    else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT))
+    {
+      fastPaint = false;
+      repaint();
+      return;
+    }
+
     if (!av.getWrapAlignment())
     {
       int scrollX = 0;
-      if (eventName.equals(ViewportRanges.STARTRES))
+      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();
-        scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
         int range = vpRanges.getEndRes() - vpRanges.getStartRes();
         if (scrollX > range)
         {
@@ -913,6 +911,10 @@ public class SeqCanvas extends Panel implements ViewportListenerI
         // scroll
         fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
       }
+      else if (eventName.equals(ViewportRanges.STARTRESANDSEQ))
+      {
+        fastPaint(scrollX, 0);
+      }
     }
   }