JAL-3253-applet JAL-3383
authorhansonr <hansonr@STO24954W.ad.stolaf.edu>
Mon, 29 Jul 2019 21:05:34 +0000 (16:05 -0500)
committerhansonr <hansonr@STO24954W.ad.stolaf.edu>
Tue, 30 Jul 2019 18:09:10 +0000 (13:09 -0500)
Significant improvement to Overview rendering. See JAL-3383 issue for
details.

27 files changed:
src/jalview/api/AlignmentColsCollectionI.java
src/jalview/appletgui/OverviewCanvas.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/AllColsCollection.java
src/jalview/datamodel/HiddenColumns.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceI.java
src/jalview/datamodel/VisibleColsCollection.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignmentPanel.java
src/jalview/gui/FeatureRenderer.java
src/jalview/gui/OverviewCanvas.java
src/jalview/gui/OverviewPanel.java
src/jalview/gui/ScalePanel.java
src/jalview/gui/SeqCanvas.java
src/jalview/gui/SeqPanel.java
src/jalview/io/AlignFile.java
src/jalview/io/FeaturesFile.java
src/jalview/jbgui/GAlignmentPanel.java
src/jalview/renderer/OverviewRenderer.java
src/jalview/renderer/OverviewResColourFinder.java
src/jalview/renderer/ResidueColourFinder.java
src/jalview/renderer/seqfeatures/FeatureColourFinder.java
src/jalview/viewmodel/OverviewDimensions.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java

index 06b1675..70dda87 100644 (file)
@@ -20,6 +20,8 @@
  */
 package jalview.api;
 
+import java.util.BitSet;
+
 public interface AlignmentColsCollectionI extends Iterable<Integer>
 {
   /**
@@ -37,4 +39,20 @@ public interface AlignmentColsCollectionI extends Iterable<Integer>
    * @return true if there is at least 1 hidden column
    */
   public boolean hasHidden();
+
+  /**
+   * Get the visible-column bitset, possibly containing hidden columns (which
+   * may or may not be hidden in the overview).
+   * 
+   * @return a BitSet
+   */
+  public BitSet getOverviewBitSet();
+
+  /**
+   * Get the hidden-column bitset, (which may or may not be hidden in the
+   * overview).
+   * 
+   * @return
+   */
+  BitSet getHiddenBitSet();
 }
index 5ea9c04..7f4e962 100644 (file)
@@ -129,8 +129,7 @@ public class OverviewCanvas extends Component
     or = new OverviewRenderer(panel.ap, fr, od, av.getAlignment(),
             av.getResidueShading(), new OverviewResColourFinder());
     offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
-    or.draw(od.getRows(av.getAlignment()),
-            od.getColumns(av.getAlignment()));
+    or.drawMiniMe();
   }
 
   @Override
@@ -163,18 +162,6 @@ public class OverviewCanvas extends Component
 
   public void finalizeDraw(BufferedImage miniMe)
   {
-    Graphics mg = miniMe.getGraphics();
-
-    // checks for conservation annotation to make sure overview works for DNA
-    // too
-    if (showAnnotation)
-    {
-      mg.translate(0, od.getSequencesHeight());
-      or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
-              od.getGraphHeight(), od.getColumns(av.getAlignment()));
-      mg.translate(0, -od.getSequencesHeight());
-    }
-
     if (restart)
     {
       restart = false;
@@ -182,7 +169,15 @@ public class OverviewCanvas extends Component
     }
     else
     {
+      this.miniMe = miniMe;
+      // checks for conservation annotation to make sure overview works for DNA
+      // too
+      if (showAnnotation)
+      {
+        or.drawGraph(av.getAlignmentConservationAnnotation());
+      }
       updaterunning = false;
+      repaint();
     }
   }
 
index ef684f7..328841c 100755 (executable)
@@ -255,11 +255,11 @@ public class OverviewPanel extends Panel implements Runnable,
   @Override
   public void run()
   {
+    setBoxPosition();
     canvas.draw(av.isShowSequenceFeatures(),
             (av.isShowAnnotation()
                     && av.getAlignmentConservationAnnotation() != null),
             ap.seqPanel.seqCanvas.getFeatureRenderer());
-    setBoxPosition();
   }
 
   /**
index 91b29da..98510e3 100755 (executable)
@@ -414,12 +414,12 @@ public class Alignment implements AlignmentI
 
     synchronized (groups)
     {
-      temp.clear();
       int gSize = groups.size();
       if (gSize == 0)
       {
         return noGroups;
       }
+      temp.clear();
       for (int i = 0; i < gSize; i++)
       {
         SequenceGroup sg = groups.get(i);
@@ -2034,4 +2034,17 @@ public class Alignment implements AlignmentI
     }
   }
 
+  @Override
+  public void resetColors()
+  {
+    for (int i = getHeight(); --i >= 0;)
+    {
+      sequences.get(i).resetColors();
+    }
+    // if (dataset != null)
+    // {
+    // dataset.resetColors();
+    // }
+  }
+
 }
index 93a2456..ebf4da3 100755 (executable)
@@ -624,4 +624,10 @@ public interface AlignmentI extends AnnotatedCollectionI
   public HiddenColumns propagateInsertions(SequenceI profileseq,
           AlignmentView input);
 
+  /**
+   * Remove all color already assigned to sequences, causing them to be be
+   * recalculated.
+   */
+  void resetColors();
+
 }
index e216c46..f3077fa 100644 (file)
@@ -22,6 +22,7 @@ package jalview.datamodel;
 
 import jalview.api.AlignmentColsCollectionI;
 
+import java.util.BitSet;
 import java.util.Iterator;
 
 public class AllColsCollection implements AlignmentColsCollectionI
@@ -56,4 +57,26 @@ public class AllColsCollection implements AlignmentColsCollectionI
   {
     return hidden.hasHiddenColumns();
   }
+
+  private BitSet bsVisible;
+
+  @Override
+  public BitSet getHiddenBitSet()
+  {
+    return hidden.getBitset();
+  }
+
+  /**
+   * return ALL columns, not just the truly visible ones
+   */
+  @Override
+  public BitSet getOverviewBitSet()
+  {
+    if (bsVisible == null)
+    {
+      bsVisible = new BitSet(end + 1);
+      bsVisible.set(0, end + 1);
+    }
+    return bsVisible;
+  }
 }
index 2d43f02..458bde7 100644 (file)
@@ -86,6 +86,20 @@ public class HiddenColumns
    */
   private List<int[]> hiddenColumns = new ArrayList<>();
 
+  private BitSet hiddenBitSet;
+
+  public BitSet getBitset()
+  {
+    if (hiddenBitSet == null)
+    {
+      hiddenBitSet = new BitSet();
+      for (int[] range : hiddenColumns)
+      {
+        hiddenBitSet.set(range[0], range[1] + 1);
+      }
+    }
+    return hiddenBitSet;
+  }
   /**
    * Constructor
    */
@@ -213,6 +227,7 @@ public class HiddenColumns
               prevHiddenCount);
     } finally
     {
+      hiddenBitSet = null;
       LOCK.writeLock().unlock();
     }
   }
@@ -264,6 +279,7 @@ public class HiddenColumns
       insertRangeAtOverlap(i, start, end, region);
       added = true;
     }
+    hiddenBitSet = null;
     return added;
   }
 
@@ -310,6 +326,7 @@ public class HiddenColumns
     }
     numColumns += region[1] - oldend;
     hiddenColumns.subList(i + 1, endi + 1).clear();
+    hiddenBitSet = null;
   }
 
   /**
@@ -330,6 +347,7 @@ public class HiddenColumns
 
     } finally
     {
+      hiddenBitSet = null;
       LOCK.writeLock().unlock();
     }
   }
@@ -356,6 +374,7 @@ public class HiddenColumns
 
     } finally
     {
+      hiddenBitSet = null;
       LOCK.writeLock().unlock();
     }
   }
@@ -399,6 +418,7 @@ public class HiddenColumns
       }
     } finally
     {
+      hiddenBitSet = null;
       LOCK.writeLock().unlock();
     }
   }
@@ -620,6 +640,7 @@ public class HiddenColumns
 
     } finally
     {
+      hiddenBitSet = null;
       LOCK.readLock().unlock();
     }
   }
@@ -798,7 +819,7 @@ public class HiddenColumns
       for (int firstSet = tohide
               .nextSetBit(start), lastSet = start; firstSet >= start
                       && lastSet <= end; firstSet = tohide
-                      .nextSetBit(lastSet))
+                              .nextSetBit(lastSet))
       {
         lastSet = tohide.nextClearBit(firstSet);
         if (lastSet <= end)
@@ -813,6 +834,7 @@ public class HiddenColumns
       cursor = new HiddenColumnsCursor(hiddenColumns);
     } finally
     {
+      hiddenBitSet = null;
       LOCK.writeLock().unlock();
     }
   }
@@ -894,6 +916,7 @@ public class HiddenColumns
       }
     } finally
     {
+      hiddenBitSet = null;
       LOCK.writeLock().unlock();
     }
   }
@@ -909,16 +932,12 @@ public class HiddenColumns
     {
       LOCK.writeLock().lock();
 
-      BitSet hiddenBitSet = new BitSet();
-      for (int[] range : hiddenColumns)
-      {
-        hiddenBitSet.set(range[0], range[1] + 1);
-      }
-      hiddenBitSet.andNot(updates);
+      getBitset().andNot(updates);
       hiddenColumns.clear();
       hideColumns(hiddenBitSet);
     } finally
     {
+      hiddenBitSet = null;
       LOCK.writeLock().unlock();
     }
   }
index 4c46522..6b52480 100755 (executable)
@@ -28,7 +28,6 @@ import jalview.util.DBRefUtils;
 import jalview.util.MapList;
 import jalview.util.StringUtils;
 
-import java.awt.Color;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -2027,6 +2026,7 @@ public class Sequence extends ASequence implements SequenceI
   @Override
   public void sequenceChanged()
   {
+    argb = null;
     changeCount++;
   }
 
@@ -2129,20 +2129,27 @@ public class Sequence extends ASequence implements SequenceI
     return 0;
   }
 
+  private int[] argb;
+
   @Override
-  public Color getColor(int i)
+  public int getColor(int i)
   {
-    return null;
+    return argb == null ? 0 : argb[i];
   }
 
   @Override
-  public Color setColor(int i, Color c)
+  public int setColor(int i, int rgb)
   {
-    return c;
+    if (argb == null)
+    {
+      argb = new int[this.sequence.length];
+    }
+    return (argb[i] = rgb);
   }
 
   @Override
   public void resetColors()
   {
+    argb = null;
   }
 }
index 5e2355d..e521029 100755 (executable)
@@ -25,7 +25,6 @@ import jalview.datamodel.features.SequenceFeaturesI;
 import jalview.util.MapList;
 import jalview.ws.params.InvalidArgumentException;
 
-import java.awt.Color;
 import java.util.BitSet;
 import java.util.Iterator;
 import java.util.List;
@@ -585,9 +584,9 @@ public interface SequenceI extends ASequenceI
    */
   public int firstResidueOutsideIterator(Iterator<int[]> it);
 
-  public Color getColor(int i);
+  public int getColor(int i);
 
-  public Color setColor(int i, Color c);
+  public int setColor(int i, int rgb);
 
   public void resetColors();
 
index 4ca51b5..cd812a1 100644 (file)
@@ -22,6 +22,7 @@ package jalview.datamodel;
 
 import jalview.api.AlignmentColsCollectionI;
 
+import java.util.BitSet;
 import java.util.Iterator;
 
 public class VisibleColsCollection implements AlignmentColsCollectionI
@@ -32,6 +33,8 @@ public class VisibleColsCollection implements AlignmentColsCollectionI
 
   HiddenColumns hidden;
 
+  private BitSet bsVisible;
+
   public VisibleColsCollection(int s, int e, HiddenColumns h)
   {
     start = s;
@@ -57,4 +60,27 @@ public class VisibleColsCollection implements AlignmentColsCollectionI
     return false;
   }
 
+  /**
+   * Only the visible columns.
+   */
+  @Override
+  public BitSet getOverviewBitSet()
+  {
+    if (bsVisible == null)
+    {
+      bsVisible = new BitSet(end + 1);
+    }
+    bsVisible.clear();
+    bsVisible.set(start, end + 1);
+    bsVisible.andNot(hidden.getBitset());
+
+    return bsVisible;
+  }
+
+  @Override
+  public BitSet getHiddenBitSet()
+  {
+    return new BitSet();
+  }
+
 }
index 4fa8408..bac06e9 100644 (file)
@@ -4525,6 +4525,7 @@ public class AlignFrame extends GAlignFrame
     {
       viewport.setShowSequenceFeatures(true);
       showSeqFeatures.setSelected(true);
+      alignPanel.getAlignment().resetColors();
     }
 
   }
index d305183..c8f0194 100644 (file)
@@ -70,7 +70,14 @@ import java.util.List;
 import javax.swing.SwingUtilities;
 
 /**
- * DOCUMENT ME!
+ * The main panel of an AlignFrame, containing holders for the IdPanel,
+ * SeqPanel, AnnotationLabels (a JPanel), and AnnotationPanel.
+ * 
+ * Additional holders contain an IdPanelWidthAdjuster space above the idPanel,
+ * AnnotationScroller (JScrollPane for AnnotationPanel), and vertical and
+ * horizontal scrollbars.
+ * 
+ * 
  * 
  * @author $author$
  * @version $Revision: 1.161 $
@@ -838,6 +845,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
       if (overviewPanel != null)
       {
+        getAlignment().resetColors();
         overviewPanel.updateOverviewImage();
       }
     }
index 2c54906..cc034dd 100644 (file)
@@ -45,11 +45,11 @@ public class FeatureRenderer
   {
     super(alignPanel.av);
     this.ap = alignPanel;
-    if (alignPanel.getSeqPanel() != null
-            && alignPanel.getSeqPanel().seqCanvas != null
-            && alignPanel.getSeqPanel().seqCanvas.fr != null)
+    SeqPanel sp = alignPanel.getSeqPanel();
+    if (sp != null && sp.seqCanvas != null && sp.seqCanvas.fr != null)
     {
-      transferSettings(alignPanel.getSeqPanel().seqCanvas.fr);
+      sp.clearColors();
+      transferSettings(sp.seqCanvas.fr);
     }
   }
 }
index aafac38..b6df722 100644 (file)
@@ -73,15 +73,18 @@ public class OverviewCanvas extends JPanel
 
   private OverviewPanel panel;
 
+  private boolean showProgress;
+
   public OverviewCanvas(OverviewPanel panel,
           OverviewDimensions overviewDims,
           AlignViewportI alignvp, ProgressPanel pp)
   {
     this.panel = panel;
     od = overviewDims;
+    lastMiniMe = null;
     av = alignvp;
     progressPanel = pp;
-
+    showProgress = (pp != null);
     sr = new SequenceRenderer(av);
     sr.renderGaps = false;
     fr = new jalview.renderer.seqfeatures.FeatureRenderer(av);
@@ -106,6 +109,7 @@ public class OverviewCanvas extends JPanel
   public void resetOviewDims(OverviewDimensions overviewDims)
   {
     od = overviewDims;
+    lastMiniMe = null;
   }
 
   /**
@@ -123,6 +127,7 @@ public class OverviewCanvas extends JPanel
       else
       {
         updaterunning = true;
+        restart = false;
       }
       return restart;
     }
@@ -154,46 +159,35 @@ public class OverviewCanvas extends JPanel
     this.showSequenceFeatures = showSequenceFeatures;
     this.showAnnotation = showAnnotation;
     this.featureRenderer = featureRenderer;
-
-    // System.out.println("OC draw " + ++ndraw + " showseqf="
-    // + showSequenceFeatures + " showAnno=" + showAnnotation);
-
     if (showSequenceFeatures)
     {
       fr.transferSettings(featureRenderer);
     }
-
     setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
-
     AlignmentI al = av.getAlignment();
-    or = new OverviewRenderer(panel.ap, fr, od, al,
-            av.getResidueShading(), cf,
-            progressPanel != null);
-    if (progressPanel != null)
+    or = new OverviewRenderer(panel.ap, fr, od, al, av.getResidueShading(),
+            cf, showProgress);
+    if (showProgress)
     {
       or.addPropertyChangeListener(progressPanel);
     }
-    or.draw(od.getRows(al), od.getColumns(al));
+    or.drawMiniMe();
   }
 
-  void finalizeDraw(BufferedImage miniMe)
+  synchronized void finalizeDraw(BufferedImage miniMe)
   {
-    Graphics mg = miniMe.getGraphics();
-    if (showAnnotation)
+
+    if (or == null)
     {
-      mg.translate(0, od.getSequencesHeight());
-      or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
-              od.getGraphHeight(), od.getColumns(av.getAlignment()));
-      mg.translate(0, -od.getSequencesHeight());
+      System.out.println("OC or is null");
     }
-    mg.dispose(); // BH 2019
-    if (progressPanel != null)
+    else if (showProgress)
     {
       or.removePropertyChangeListener(progressPanel);
     }
-    or = null;
     if (restart)
     {
+      or = null;
       restart = false;
       if (!disposed)
       {
@@ -202,12 +196,17 @@ public class OverviewCanvas extends JPanel
     }
     else
     {
+      if (showAnnotation)
+      {
+        or.drawGraph(av.getAlignmentConservationAnnotation());
+      }
+      or = null;
       updaterunning = false;
       lastMiniMe = miniMe;
       repaint();
     }
-
   }
+
   @Override
   public void paintComponent(Graphics g)
   {
@@ -240,40 +239,56 @@ public class OverviewCanvas extends JPanel
     else if (drawMe)
     {
       // is this a resize?
-      if (w != od.getWidth() ||  h != od.getHeight()) {
-      // if there is annotation, scale the alignment and annotation
-      // separately
-      if (od.getGraphHeight() <= 0 && od.getSequencesHeight() <= 0)
+      if (w != od.getWidth() || h != od.getHeight())
       {
-        od.setWidth(w);
-        od.setHeight(h);
+
+        lastMiniMe = null;
         return;
-      }
-        // System.out.println("OC new subimages");
-      BufferedImage topImage = lastMiniMe.getSubimage(0, 0, od.getWidth(),
-              od.getSequencesHeight());
-      BufferedImage bottomImage = lastMiniMe.getSubimage(0,
-              od.getSequencesHeight(), od.getWidth(), od.getGraphHeight());
-
-      // must be done at this point as we rely on using old width/height
-      // above, and new width/height below
-      od.setWidth(w);
-      od.setHeight(h);
-
-      // stick the images back together so lastMiniMe is consistent in the
-      // event of a repaint - BUT probably not thread safe
-      // System.out.println("OC new lastminime " + w + " " + h);
-      lastMiniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
-      Graphics lg = lastMiniMe.getGraphics();
-      lg.drawImage(topImage, 0, 0, w, od.getSequencesHeight(), null);
-      lg.drawImage(bottomImage, 0, od.getSequencesHeight(), w,
-              od.getGraphHeight(), this);
-      lg.dispose();
-      // BH 2019: removed -- this is now taken care of using vpbox in
-      // OverviewDimension
-      // // make sure the box is in the right place
-      // od.setBoxPosition(av.getAlignment().getHiddenSequences(),
-      // av.getAlignment().getHiddenColumns());
+        // // if there is annotation, scale the alignment and annotation
+        // // separately
+        // if (od.getGraphHeight() <= 0 && od.getSequencesHeight() <= 0)
+        // {
+        // od.setWidth(w);
+        // od.setHeight(h);
+        // return;
+        // }
+        // try
+        // {
+        // BufferedImage topImage = lastMiniMe.getSubimage(0, 0,
+        // od.getWidth(), od.getSequencesHeight());
+        //
+        // BufferedImage bottomImage = lastMiniMe.getSubimage(0,
+        // od.getSequencesHeight(), od.getWidth(),
+        // od.getGraphHeight());
+        //
+        // // must be done at this point as we rely on using old width/height
+        // // above, and new width/height below
+        // od.setWidth(w);
+        // od.setHeight(h);
+        //
+        // // stick the images back together so lastMiniMe is consistent in the
+        // // event of a repaint - BUT probably not thread safe
+        //
+        // // right -- this fails with fast user action.
+        //
+        // lastMiniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+        // Graphics lg = lastMiniMe.getGraphics();
+        // lg.drawImage(topImage, 0, 0, w, od.getSequencesHeight(), null);
+        // lg.drawImage(bottomImage, 0, od.getSequencesHeight(), w,
+        // od.getGraphHeight(), this);
+        // lg.dispose();
+        //
+        // } catch (RasterFormatException e)
+        // {
+        // System.out.println("OC Raster Exception " + lastMiniMe.getWidth()
+        // + "/" + w + "," + lastMiniMe.getHeight() + "/" + h + " "
+        // + od.getSequencesHeight() + " " + od.getGraphHeight());
+        // }
+        // BH 2019: removed -- this is now taken care of using vpbox in
+        // OverviewDimension
+        // // make sure the box is in the right place
+        // od.setBoxPosition(av.getAlignment().getHiddenSequences(),
+        // av.getAlignment().getHiddenColumns());
       }
     }
 
@@ -301,6 +316,7 @@ public class OverviewCanvas extends JPanel
   {
     disposed = true;
     od = null;
+    lastMiniMe = null;
     synchronized (this)
     {
       setRestart("dispose");
index 387d3dd..cc647a8 100755 (executable)
@@ -130,6 +130,7 @@ public class OverviewPanel extends JPanel
         if (getWidth() == od.getWidth()
                 && getHeight() == od.getHeight() + ph)
         {
+          // BH: resizing is now exceptionally fast.
           updateOverviewImage();
         }
         else
@@ -144,7 +145,8 @@ public class OverviewPanel extends JPanel
             }
             od.setWidth(w);
             od.setHeight(h - ph);
-            repaint();
+            updateOverviewImage();
+            // repaint();
           }
           // BH 2019.07.29 this is unnecessary -- it is what layout managers are
           // for:
@@ -330,6 +332,15 @@ public class OverviewPanel extends JPanel
    * 
    * Cases:
    * 
+   * AlignFrame.setFeatureGroupState
+   * 
+   * AlignmentPanel.paintAlignment(true,...) (117 references)
+   * 
+   * OverviewPanel..componentResized() OverviewPanel.toggleHiddenColumns()
+   * 
+   * PopupMenu for action.reveal_sequences, action.reveal_all
+   * 
+   * SliderPanel.mouseReleased()
    * 
    */
   public void updateOverviewImage()
@@ -367,11 +378,11 @@ public class OverviewPanel extends JPanel
   {
     if (canvas != null)
     {
+      setBoxPosition();
       canvas.draw(av.isShowSequenceFeatures(),
               (av.isShowAnnotation()
                       && av.getAlignmentConservationAnnotation() != null),
               ap.getFeatureRenderer());
-      setBoxPosition();
     }
   }
 
index aa58a88..b06647d 100755 (executable)
@@ -569,31 +569,29 @@ public class ScalePanel extends JPanel
   @Override
   public void propertyChange(PropertyChangeEvent evt)
   {
-    // Respond to viewport change events (e.g. alignment panel was scrolled)
-    // Both scrolling and resizing change viewport ranges: scrolling changes
-    // both start and end points, but resize only changes end values.
-    // Here we only want to fastpaint on a scroll, with resize using a normal
-    // paint, so scroll events are identified as changes to the horizontal or
-    // vertical start value.
     switch (evt.getPropertyName())
     {
     case ViewportRanges.STARTRES:
     case ViewportRanges.STARTRESANDSEQ:
     case ViewportRanges.MOVE_VIEWPORT:
       // scroll event, repaint panel
-      // TODO: check this?
-      // BH: This is actually quite strange. AlignmentPanel is taking care of
-      // all of
-      // this with fast paint, so why indirectly trigger a repaint from the
-      // ScalePanel?
-
+      // original comment:
       // Call repaint on alignment panel so that repaints from other alignment
       // panel components can be aggregated. Otherwise performance of the
       // overview
       // window and others may be adversely affected.
-      // av.getAlignPanel().repaint();
-      System.out.println("ScalePanel propertyChange disabled "
-              + evt.getPropertyName());
+
+      // TODO: check this?
+      // BH: This is actually quite strange. AlignmentPanel is taking care of
+      // all of this with fast paint, so why indirectly trigger a repaint from
+      // the ScalePanel? Where do we see this behavior necessary?
+      // I have set this to check for a trigger from some other ViewportRanges,
+      // but I don't actually think that is possible.
+
+      if (evt.getSource() != av.getRanges())
+      {
+        av.getAlignPanel().repaint();
+      }
       break;
     }
   }
index 0d27354..2d83e9e 100755 (executable)
@@ -375,15 +375,15 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
     int charHeight = av.getCharHeight();
     int charWidth = av.getCharWidth();
 
-    int width = getWidth();
-    int height = getHeight();
+    int availWidth = getWidth();
+    int availHeight = getHeight();
 
-    width -= (width % charWidth);
-    height -= (height % charHeight);
+    availWidth -= (availWidth % charWidth);
+    availHeight -= (availHeight % charHeight);
 
     // BH 2019 can't possibly fastPaint if either width or height is 0
 
-    if (width == 0 || height == 0)
+    if (availWidth == 0 || availHeight == 0)
     {
       return;
     }
@@ -433,10 +433,11 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
       // img is a cached version of the last view we drew.
       // If we have no img or the size has changed, make a new one.
       //
-      if (img == null || width != img.getWidth()
-              || height != img.getHeight())
+      if (img == null || availWidth != img.getWidth()
+              || availHeight != img.getHeight())
       {
-        img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        img = new BufferedImage(availWidth, availHeight,
+                BufferedImage.TYPE_INT_RGB);
       }
 
       Graphics2D gg = (Graphics2D) img.getGraphics();
@@ -449,11 +450,11 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
       }
 
       gg.setColor(Color.white);
-      gg.fillRect(0, 0, img.getWidth(), img.getHeight());
+      gg.fillRect(0, 0, availWidth, availHeight);
 
       if (av.getWrapAlignment())
       {
-        drawWrappedPanel(gg, width, height, ranges.getStartRes());
+        drawWrappedPanel(gg, availWidth, availHeight, ranges.getStartRes());
       }
       else
       {
@@ -521,32 +522,31 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
   }
 
   /**
-   * Returns the visible width of the canvas in residues, after allowing for
-   * East or West scales (if shown)
+   * Using the current font, determine fields labelWidthEast and labelWidthWest,
+   * and return the number of residues that can fill the remaining width.
    * 
-   * @param canvasWidth
+   * @param width
    *          the width in pixels (possibly including scales)
    * 
-   * @return
+   * @return the visible width in residues, after allowing for East or West
+   *         scales (if shown)
+   * 
    */
-  public int getWrappedCanvasWidth(int canvasWidth)
+  public int getWrappedCanvasWidth(int width)
   {
     int charWidth = av.getCharWidth();
 
     FontMetrics fm = getFontMetrics(av.getFont());
 
-    int labelWidth = 0;
-    
-    if (av.getScaleRightWrapped() || av.getScaleLeftWrapped())
-    {
-      labelWidth = getLabelWidth(fm);
-    }
+    int labelWidth = (av.getScaleRightWrapped() || av.getScaleLeftWrapped()
+            ? getLabelWidth(fm)
+            : 0);
 
     labelWidthEast = av.getScaleRightWrapped() ? labelWidth : 0;
 
     labelWidthWest = av.getScaleLeftWrapped() ? labelWidth : 0;
 
-    return (canvasWidth - labelWidthEast - labelWidthWest) / charWidth;
+    return (width - labelWidthEast - labelWidthWest) / charWidth;
   }
 
   /**
@@ -572,6 +572,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
       maxWidth = Math.max(maxWidth, alignment.getSequenceAt(i).getEnd());
     }
 
+    // quick int log10
     int length = 0;
     for (int i = maxWidth; i > 0; i /= 10)
     {
@@ -586,18 +587,18 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
    * window
    * 
    * @param g
-   * @param canvasWidth
+   * @param availWidth
    *          available width in pixels
-   * @param canvasHeight
+   * @param availHeight
    *          available height in pixels
    * @param startColumn
    *          the first column (0...) of the alignment to draw
    */
-  public void drawWrappedPanel(Graphics g, int canvasWidth,
-          int canvasHeight, final int startColumn)
+  public void drawWrappedPanel(Graphics g, int availWidth, int availHeight,
+          final int startColumn)
   {
-    int wrappedWidthInResidues = calculateWrappedGeometry(canvasWidth,
-            canvasHeight);
+    int wrappedWidthInResidues = calculateWrappedGeometry(availWidth,
+            availHeight);
 
     av.setWrappedWidth(wrappedWidthInResidues);
 
@@ -607,7 +608,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
     // we need to call this again to make sure the startColumn +
     // wrappedWidthInResidues values are used to calculate wrappedVisibleWidths
     // correctly.
-    calculateWrappedGeometry(canvasWidth, canvasHeight);
+    calculateWrappedGeometry(availWidth, availHeight);
 
     /*
      * draw one width at a time (excluding any scales shown),
@@ -622,7 +623,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
     {
       int endColumn = Math
               .min(maxWidth, start + wrappedWidthInResidues - 1);
-      drawWrappedWidth(g, ypos, start, endColumn, canvasHeight);
+      drawWrappedWidth(g, ypos, start, endColumn, availHeight);
       ypos += wrappedRepeatHeightPx;
       start += wrappedWidthInResidues;
       currentWidth++;
@@ -641,11 +642,11 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
    * <li>whether scales are shown left, right or above the alignment</li>
    * </ul>
    * 
-   * @param canvasWidth
-   * @param canvasHeight
+   * @param availWidth
+   * @param availHeight
    * @return the number of residue columns in each width
    */
-  protected int calculateWrappedGeometry(int canvasWidth, int canvasHeight)
+  protected int calculateWrappedGeometry(int availWidth, int availHeight)
   {
     int charHeight = av.getCharHeight();
 
@@ -679,8 +680,8 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
      * ensuring a part height includes at least one sequence
      */
     ViewportRanges ranges = av.getRanges();
-    wrappedVisibleWidths = canvasHeight / wrappedRepeatHeightPx;
-    int remainder = canvasHeight % wrappedRepeatHeightPx;
+    wrappedVisibleWidths = availHeight / wrappedRepeatHeightPx;
+    int remainder = availHeight % wrappedRepeatHeightPx;
     if (remainder >= (wrappedSpaceAboveAlignment + charHeight))
     {
       wrappedVisibleWidths++;
@@ -689,7 +690,7 @@ public class SeqCanvas extends JPanel implements ViewportListenerI
     /*
      * compute width in residues; this also sets East and West label widths
      */
-    int wrappedWidthInResidues = getWrappedCanvasWidth(canvasWidth);
+    int wrappedWidthInResidues = getWrappedCanvasWidth(availWidth);
 
     /*
      *  limit visibleWidths to not exceed width of alignment
index de67c39..e5a5962 100644 (file)
@@ -74,7 +74,8 @@ import javax.swing.Timer;
 import javax.swing.ToolTipManager;
 
 /**
- * DOCUMENT ME!
+ * The main scrollable region containing the alignment and just to the right of
+ * the IDPanel.
  * 
  * @author $author$
  * @version $Revision: 1.130 $
@@ -223,7 +224,7 @@ public class SeqPanel extends JPanel
   SearchResultsI lastSearchResults;
 
   /**
-   * Creates a new SeqPanel object
+   * Create a new SeqPanel.
    * 
    * @param viewport
    * @param alignPanel
@@ -2811,4 +2812,11 @@ public class SeqPanel extends JPanel
             true);
   }
 
+  public void clearColors()
+  {
+    av.getAlignment().getSequences();
+    // TODO Auto-generated method stub
+
+  }
+
 }
index cea2870..c2cf667 100755 (executable)
@@ -323,14 +323,15 @@ public abstract class AlignFile extends FileParse
    */
   protected void initData()
   {
-    seqs = new Vector<SequenceI>();
-    annotations = new Vector<AlignmentAnnotation>();
-    seqGroups = new ArrayList<SequenceGroup>();
+    seqs = new Vector<>();
+    annotations = new Vector<>();
+    seqGroups = new ArrayList<>();
     parseCalled = false;
   }
 
   /**
-   * DOCUMENT ME!
+   * Create the seqs Vector from a set of parsed sequences in an AlignFile,
+   * FeaturesFile, RnamlFile, or StockholmFile.
    * 
    * @param s
    *          DOCUMENT ME!
@@ -338,7 +339,7 @@ public abstract class AlignFile extends FileParse
   @Override
   public void setSeqs(SequenceI[] s)
   {
-    seqs = new Vector<SequenceI>();
+    seqs = new Vector<>();
 
     for (int i = 0; i < s.length; i++)
     {
@@ -409,7 +410,7 @@ public abstract class AlignFile extends FileParse
   {
     if (newickStrings == null)
     {
-      newickStrings = new Vector<String[]>();
+      newickStrings = new Vector<>();
     }
     newickStrings.addElement(new String[] { treeName, newickString });
   }
index 1fb45bc..aa21b0f 100755 (executable)
@@ -829,14 +829,15 @@ public class FeaturesFile extends AlignFile implements FeaturesSourceI
     AlignViewportI av = getViewport();
     if (av != null)
     {
-      if (av.getAlignment() != null)
+      AlignmentI a = av.getAlignment();
+      if (a != null)
       {
-        dataset = av.getAlignment().getDataset();
+        dataset = a.getDataset();
       }
       if (dataset == null)
       {
         // working in the applet context ?
-        dataset = av.getAlignment();
+        dataset = a;
       }
     }
     else
index b703b47..3dd0205 100755 (executable)
@@ -123,6 +123,7 @@ public class GAlignmentPanel extends JPanel
     hscrollFillerPanel.setPreferredSize(new Dimension(70, 10));
     hscrollHolder.setBackground(Color.white);
     annotationScroller.setBorder(null);
+    annotationScroller.setBackground(Color.BLUE);
     annotationScroller.setPreferredSize(new Dimension(10, 80));
     this.setPreferredSize(new Dimension(220, 166));
 
index 45cc944..6defca7 100644 (file)
@@ -66,9 +66,17 @@ public class OverviewRenderer
   // image to render on
   private BufferedImage miniMe;
 
-  // raw number of pixels to allocate to each column
+  /**
+   * Number of pixelsPerCol;
+   */
   private float pixelsPerCol;
 
+  /**
+   * Number of visible columns per pixel.
+   * 
+   */
+  private float colsPerPixel;
+
   // raw number of pixels to allocate to each row
   private float pixelsPerSeq;
 
@@ -89,6 +97,8 @@ public class OverviewRenderer
 
   private AlignmentViewPanel panel;
 
+  private int sequencesHeight;
+
   public OverviewRenderer(AlignmentViewPanel panel, FeatureRenderer fr,
           OverviewDimensions od,
           AlignmentI alignment,
@@ -98,24 +108,28 @@ public class OverviewRenderer
   }
 
   public OverviewRenderer(AlignmentViewPanel panel,
-          jalview.api.FeatureRenderer fr,
-          OverviewDimensions od,
+          jalview.api.FeatureRenderer fr, OverviewDimensions od,
           AlignmentI alignment, ResidueShaderI resshader,
           OverviewResColourFinder colFinder, boolean showProgress)
   {
     this.panel = panel;
     finder = new FeatureColourFinder(fr);
-    resColFinder = colFinder;
-
     al = alignment;
     shader = resshader;
+    resColFinder = colFinder;
+    this.showProgress = showProgress;
 
-    pixelsPerCol = od.getPixelsPerCol();
-    pixelsPerSeq = od.getPixelsPerSeq();
+    w = od.getWidth();
+    h = od.getHeight();
+    rows = od.getRows(alignment);
+    cols = od.getColumns(alignment);
     graphHeight = od.getGraphHeight();
-    miniMe = new BufferedImage(od.getWidth(), od.getHeight(),
-            BufferedImage.TYPE_INT_RGB);
-    this.showProgress = showProgress;
+    alignmentHeight = od.getSequencesHeight();
+
+    pixelsPerSeq = od.getPixelsPerSeq();
+    pixelsPerCol = od.getPixelsPerCol();
+    colsPerPixel = Math.max(1, 1f / pixelsPerCol);
+
   }
 
   final static int STATE_INIT = 0;
@@ -135,65 +149,87 @@ public class OverviewRenderer
 
   private Integer row;
 
-  void mainLoop()
+  /**
+   * Draw alignment rows and columns onto an image. This method is asynchronous
+   * in JavaScript and interruptible in Java.
+   * 
+   * Whether hidden rows or columns are drawn depends upon the type of
+   * collection.
+   * 
+   * Updated to skip through high-density sequences, where columns/pixels > 1.
+   * 
+   * When the process is complete, the image is passed to the AlignmentViewPanel
+   * provided by the constructor.
+   * 
+   * @param rows
+   *          collection of rows to be drawn
+   * @param cols
+   *          collection of columns to be drawn
+   * @return image containing the drawing
+   * 
+   * @author Bob Hanson 2019.07.30
+   */
+  public void drawMiniMe()
   {
-    while (!redraw)
+    state = STATE_INIT;
+    mainLoop();
+  }
+
+  protected void mainLoop()
+  {
+    out: while (!redraw)
     {
       switch (state)
       {
       case STATE_INIT:
-        seqIndex = 0;
-        pixelRow = 0;
+        init();
         state = STATE_NEXT;
         continue;
       case STATE_NEXT:
-        if (iter.hasNext())
+        if (!rowIterator.hasNext())
         {
-          nextRow();
+          state = STATE_DONE;
+          continue;
         }
-        else
+        nextRow();
+        if (!loop())
         {
-          state = STATE_DONE;
+          continue;
         }
-        break;
-      case STATE_DONE:
-        done();
-        return;
-      }
-      if (delay > 0)
-      {
-        jsloop();
         return;
+      case STATE_DONE:
+        break out;
       }
+      // Java will continue without a timeout
     }
     done();
   }
 
-  private void jsloop()
+  private void init()
   {
-    if (timer == null)
-    {
-      timer = new Timer(delay, new ActionListener()
-      {
-        @Override
-        public void actionPerformed(ActionEvent e)
-        {
-          mainLoop();
-        }
+    rowIterator = rows.iterator();
+    seqIndex = 0;
+    pixelRow = 0;
+    lastRowUpdate = 0;
+    lastUpdate = 0;
+    totalPixels = w * alignmentHeight;
 
-      });
-      timer.setRepeats(false);
-      timer.start();
-    }
-    else
+    if (showProgress)
     {
-      timer.restart();
+      changeSupport.firePropertyChange(UPDATE, -1, 0);
     }
+
+    miniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+    WritableRaster raster = miniMe.getRaster();
+    DataBufferInt db = (DataBufferInt) raster.getDataBuffer();
+    Platform.timeCheck(null, Platform.TIME_MARK);
+    pixels = db.getBankData()[0];
+    bscol = cols.getOverviewBitSet();
   }
 
   private void nextRow()
   {
-    row = iter.next();
+    row = rowIterator.next();
     // System.out.println("OR row " + r);
     // get details of this alignment row
     SequenceI seq = rows.getSequence(row);
@@ -203,30 +239,32 @@ public class OverviewRenderer
 
     // calculate where this row extends to in pixels
     int endRow = Math.min(Math.round((++seqIndex) * pixelsPerSeq), h);
-
-    for (int pixelCol = 0, colIndex = 0, c = bscol
-            .nextSetBit(0); c >= 0; c = bscol.nextSetBit(c + 1))
+    for (int pixelCol = 0, colNext = 0, pixelEnd = 0, icol = bscol
+            .nextSetBit(0); icol >= 0; icol = getNextCol(icol, pixelEnd))
     {
       if (redraw)
       {
         break;
       }
 
-      // calculate where this column extends to in pixels
-      int endCol = Math.min(Math.round((++colIndex) * pixelsPerCol), w);
-
-      // don't do expensive colour determination if we're not going to use it
-      // NB this is important to avoid performance issues in the overview
-      // panel
+      ++colNext;
+      pixelEnd = getNextPixel(colNext, colNext);
 
-      if (pixelCol < endCol)
+      if (pixelCol == pixelEnd)
       {
-        // System.out.println("OR pc ec " + pixelCol + " " + endCol);
-        int rgb = getColumnColourFromSequence(allGroups, seq, c);
+        break;
+      }
+      else if (pixelCol < pixelEnd)
+      {
+        int rgb = getColumnColourFromSequence(allGroups, seq, icol);
         // fill in the appropriate number of pixels
+        // System.out.println(
+        // "OR colNext=" + colNext + " " + pixelCol
+        // + "-" + pixelEnd + " icol=" + icol + " " + rgb + " "
+        // + pixelsPerCol);
         for (int row = pixelRow; row < endRow; ++row)
         {
-          for (int col = pixelCol; col < endCol; ++col)
+          for (int col = pixelCol; col < pixelEnd; ++col)
           {
             // BH 2019.07.27 was:
             //
@@ -238,16 +276,16 @@ public class OverviewRenderer
             ndone++;
           }
         }
-        // }
-
-        pixelCol = endCol;
+        pixelCol = pixelEnd;
         // store last update value
         if (showProgress)
         {
-          lastUpdate = sendProgressUpdate(endCol * (endRow - 1 - pixelRow),
+          lastUpdate = sendProgressUpdate(
+                  pixelEnd * (endRow - 1 - pixelRow),
                   totalPixels, lastRowUpdate, lastUpdate);
         }
       }
+
     }
     if (pixelRow < endRow)
     {
@@ -264,6 +302,57 @@ public class OverviewRenderer
     }
   }
 
+  /**
+   * The next column is either the next set bit (when there are multiple pixels
+   * per column) or the next set bit for the column that aligns with the next
+   * pixel (when there are more columns than pixels).
+   * 
+   * @param icol
+   * @param pixel
+   * @return
+   */
+  private int getNextCol(int icol, int pixel)
+  {
+    return bscol.nextSetBit(
+            pixelsPerCol >= 1 ? icol + 1 : (int) (pixel * colsPerPixel));
+  }
+
+  private int getNextPixel(int icol, int pixel)
+  {
+    return Math.min(
+            pixelsPerCol >= 1 || pixel == 0
+                    ? Math.round(icol * pixelsPerCol)
+                    : pixel,
+            w);
+  }
+
+  private boolean loop()
+  {
+    if (delay <= 0)
+    {
+      return false;
+    }
+    if (timer == null)
+    {
+      timer = new Timer(delay, new ActionListener()
+      {
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          mainLoop();
+        }
+
+      });
+      timer.setRepeats(false);
+      timer.start();
+    }
+    else
+    {
+      timer.restart();
+    }
+    return true;
+  }
+
   private void done()
   {
     Platform.timeCheck(
@@ -271,7 +360,7 @@ public class OverviewRenderer
                     + redraw,
             Platform.TIME_MARK);
 
-    overlayHiddenRegions(rows, cols);
+    overlayHiddenRegions();
     if (showProgress)
     {
       // final update to progress bar if present
@@ -296,7 +385,7 @@ public class OverviewRenderer
 
   private AlignmentColsCollectionI cols;
 
-  Iterator<Integer> iter;
+  Iterator<Integer> rowIterator;
 
   int alignmentHeight;
 
@@ -308,53 +397,10 @@ public class OverviewRenderer
 
   int[] pixels;
 
-  BitSet bscol = new BitSet();
+  BitSet bscol;
 
   int w, h;
 
-  /**
-   * Draw alignment rows and columns onto an image
-   * 
-   * @param rit
-   *          Iterator over rows to be drawn
-   * @param cit
-   *          Iterator over columns to be drawn
-   * @return image containing the drawing
-   */
-  public BufferedImage draw(AlignmentRowsCollectionI rows,
-          AlignmentColsCollectionI cols)
-  {
-    this.rows = rows;
-    this.cols = cols;
-    iter = rows.iterator();
-
-    w = miniMe.getWidth();
-    h = miniMe.getHeight();
-    alignmentHeight = h - graphHeight;
-    totalPixels = w * alignmentHeight;
-    lastRowUpdate = 0;
-    lastUpdate = 0;
-
-    if (showProgress)
-    {
-      changeSupport.firePropertyChange(UPDATE, -1, 0);
-    }
-
-    WritableRaster raster = miniMe.getRaster();
-    DataBufferInt db = (DataBufferInt) raster.getDataBuffer();
-    Platform.timeCheck(null, Platform.TIME_MARK);
-    pixels = db.getBankData()[0];
-    bscol.clear();
-    for (int c : cols)
-    {
-      bscol.set(c);
-    }
-    state = STATE_INIT;
-    mainLoop();
-
-    return miniMe;
-  }
-
   /*
    * Calculate progress update value and fire event
    * @param rowOffset number of rows to offset calculation by
@@ -387,25 +433,19 @@ public class OverviewRenderer
   {
     return (seq == null || icol >= seq.getLength()
             ? resColFinder.GAP_COLOUR
-            : resColFinder.getResidueColour(true, shader, allGroups, seq,
-                    icol, finder)).getRGB();
+            : resColFinder.getResidueColourInt(true, shader, allGroups, seq,
+                    icol, finder));
   }
 
   /**
    * Overlay the hidden regions on the overview image
    * 
-   * @param rows
-   *          collection of rows the overview is built over
-   * @param cols
-   *          collection of columns the overview is built over
    */
-  private void overlayHiddenRegions(AlignmentRowsCollectionI rows,
-          AlignmentColsCollectionI cols)
+  private void overlayHiddenRegions()
   {
     if (cols.hasHidden() || rows.hasHidden())
     {
-      BufferedImage mask = buildHiddenImage(rows, cols, miniMe.getWidth(),
-              miniMe.getHeight());
+      BufferedImage mask = buildHiddenImage();
 
       Graphics2D g = (Graphics2D) miniMe.getGraphics();
       g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
@@ -429,17 +469,17 @@ public class OverviewRenderer
    *          height of overview in pixels
    * @return BufferedImage containing mask of hidden regions
    */
-  private BufferedImage buildHiddenImage(AlignmentRowsCollectionI rows,
-          AlignmentColsCollectionI cols, int width, int height)
+  private BufferedImage buildHiddenImage()
   {
     // new masking image
-    BufferedImage hiddenImage = new BufferedImage(width, height,
+    BufferedImage hiddenImage = new BufferedImage(w, h,
             BufferedImage.TYPE_INT_ARGB);
 
     Color hidden = resColFinder.getHiddenColour();
 
     Graphics2D g2d = (Graphics2D) hiddenImage.getGraphics();
 
+    g2d.setColor(hidden);
     // set background to transparent
     // g2d.setComposite(AlphaComposite.Clear);
     // g2d.fillRect(0, 0, width, height);
@@ -447,31 +487,26 @@ public class OverviewRenderer
     // set next colour to opaque
     g2d.setComposite(AlphaComposite.Src);
 
+    // System.out.println(cols.getClass().getName());
     if (cols.hasHidden())
     {
-      int colIndex = 0;
-      int pixelCol = 0;
-      for (int alignmentCol : cols)
+      // AllColsCollection only
+      BitSet bs = cols.getHiddenBitSet();
+      for (int pixelCol = -1, icol2 = 0, icol = bs
+              .nextSetBit(0); icol >= 0; icol = bs.nextSetBit(icol2))
       {
         if (redraw)
         {
           break;
         }
-
-        // calculate where this column extends to in pixels
-        int endCol = Math.min(Math.round((++colIndex) * pixelsPerCol),
-                width);
-
-        // endCol is one more than old endCol
-        if (pixelCol < endCol)
+        icol2 = bs.nextClearBit(icol + 1);
+        int pixelEnd = getNextPixel(icol2, 0);
+        if (pixelEnd > pixelCol)
         {
-          // determine the colour based on the sequence and column position
-          if (cols.isHidden(alignmentCol))
-          {
-            g2d.setColor(hidden);
-            g2d.fillRect(pixelCol, 0, endCol - pixelCol, height);
-          }
-          pixelCol = endCol;
+          pixelCol = getNextPixel(icol, 0);
+          g2d.fillRect(pixelCol, 0, Math.max(1, pixelEnd - pixelCol),
+                  h);
+          pixelCol = pixelEnd;
         }
       }
     }
@@ -488,13 +523,12 @@ public class OverviewRenderer
 
         // calculate where this row extends to in pixels
         int endRow = Math.min(Math.round((++seqIndex) * pixelsPerSeq),
-                height);
+                h);
 
         // get details of this alignment row
         if (rows.isHidden(alignmentRow))
         {
-          g2d.setColor(hidden);
-          g2d.fillRect(0, pixelRow, width, endRow - 1 - pixelRow);
+          g2d.fillRect(0, pixelRow, w, endRow - 1 - pixelRow);
         }
         pixelRow = endRow;
       }
@@ -506,27 +540,23 @@ public class OverviewRenderer
   /**
    * Draw the alignment annotation in the overview panel
    * 
-   * @param g
-   *          the graphics object to draw on
    * @param anno
    *          alignment annotation information
-   * @param y
-   *          y-position for the annotation graph
-   * @param cols
-   *          the collection of columns used in the overview panel
    */
-  public void drawGraph(Graphics g, AlignmentAnnotation anno, int y,
-          AlignmentColsCollectionI cols)
+  public void drawGraph(AlignmentAnnotation anno)
   {
+    int y = graphHeight;
+    Graphics g = miniMe.getGraphics();
+    g.translate(0, alignmentHeight);
+
     Annotation[] annotations = anno.annotations;
     float max = anno.graphMax;
     g.setColor(Color.white);
-    int width = miniMe.getWidth();
-    g.fillRect(0, 0, width, y);
+    g.fillRect(0, 0, w, y);
 
-    int colIndex = 0;
-    int pixelCol = 0;
-    for (int icol : cols)
+    for (int pixelCol = 0, colNext = 0, pixelEnd = 0, len = annotations.length, icol = bscol
+            .nextSetBit(0); icol >= 0
+                    && icol < len; icol = getNextCol(icol, pixelEnd))
     {
       if (redraw)
       {
@@ -537,27 +567,29 @@ public class OverviewRenderer
         break;
       }
 
-      if (icol >= annotations.length)
-      {
-        break; // no more annotations to draw here
-      }
-      int endCol = Math.min(Math.round((++colIndex) * pixelsPerCol), width);
+      ++colNext;
+      pixelEnd = getNextPixel(colNext, colNext);
       Annotation ann = annotations[icol];
       if (ann != null)
       {
         Color color = ann.colour;
         g.setColor(color == null ? Color.black : color);
-
         int height = Math.min(y, (int) ((ann.value / max) * y));
-        g.fillRect(pixelCol, y - height, endCol - pixelCol, height);
+        g.fillRect(pixelCol, y - height, Math.max(1, pixelEnd - pixelCol),
+                height);
       }
-      pixelCol = endCol;
+      pixelCol = pixelEnd;
     }
+
+    g.translate(0, -alignmentHeight);
+    g.dispose();
+
     if (showProgress)
     {
       changeSupport.firePropertyChange(UPDATE, MAX_PROGRESS - 1,
               MAX_PROGRESS);
     }
+
   }
 
   /**
index ff52f1d..b950542 100644 (file)
@@ -22,15 +22,16 @@ package jalview.renderer;
 
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
 import jalview.util.Comparison;
 
 import java.awt.Color;
 
 public class OverviewResColourFinder extends ResidueColourFinder
 {
-  final Color GAP_COLOUR; // default colour to use at gaps
+  final int GAP_COLOUR; // default colour to use at gaps
 
-  final Color RESIDUE_COLOUR; // default colour to use at residues
+  final int RESIDUE_COLOUR; // default colour to use at residues
 
   final Color HIDDEN_COLOUR; // colour for hidden regions
 
@@ -66,27 +67,19 @@ public class OverviewResColourFinder extends ResidueColourFinder
   {
     if (useLegacyColouring)
     {
-      GAP_COLOUR = Color.white;
-      RESIDUE_COLOUR = Color.lightGray;
-      HIDDEN_COLOUR = hiddenCol;
+      GAP_COLOUR = Color.white.getRGB();
+      RESIDUE_COLOUR = Color.lightGray.getRGB();
     }
     else
     {
-      GAP_COLOUR = gapCol;
-      RESIDUE_COLOUR = Color.white;
-      HIDDEN_COLOUR = hiddenCol;
+      GAP_COLOUR = gapCol.getRGB();
+      RESIDUE_COLOUR = Color.white.getRGB();
     }
+    HIDDEN_COLOUR = hiddenCol;
   }
 
-  @Override
-  public Color getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
+  public int getBoxColourInt(ResidueShaderI shader, SequenceI seq, int i)
   {
-    seq.resetColors();
-    Color c = seq.getColor(i);
-    if (c != null)
-    {
-      return c;
-    }
     char currentChar = seq.getCharAt(i);
     // In the overview window, gaps are coloured grey, unless the colour scheme
     // specifies a gap colour, in which case gaps honour the colour scheme
@@ -94,19 +87,39 @@ public class OverviewResColourFinder extends ResidueColourFinder
     boolean isGap = Comparison.isGap(currentChar);
     if (shader.getColourScheme() == null)
     {
-      return seq.setColor(i, isGap ? GAP_COLOUR : RESIDUE_COLOUR);
+      return (isGap ? GAP_COLOUR : RESIDUE_COLOUR);
     }
-    return seq.setColor(i,
-            isGap && !shader.getColourScheme().hasGapColour() ? GAP_COLOUR
-                    : shader.findColour(currentChar, i, seq));
+    return (isGap && !shader.getColourScheme().hasGapColour() ? GAP_COLOUR
+                    : shader.findColour(currentChar, i, seq).getRGB());
   }
 
+  public int getResidueColourInt(boolean showBoxes, ResidueShaderI shader,
+          SequenceGroup[] allGroups, final SequenceI seq, int i,
+          FeatureColourFinder finder)
+  {
+
+    int c = seq.getColor(i);
+    if (c != 0)
+    {
+      return c;
+    }
+
+    int col = getResidueBoxColourInt(showBoxes, shader, allGroups, seq,
+            i);
+
+
+    // if there's a FeatureColourFinder we might override the residue colour
+    // here with feature colouring
+    return seq.setColor(i,
+            finder == null || finder.noFeaturesDisplayed() ? col
+            : finder.findFeatureColourInt(col, seq, i));
+  }
+  
   /**
-   * {@inheritDoc} In the overview, the showBoxes setting is ignored, as the
-   * overview displays the colours regardless.
+   * In the overview, the showBoxes setting is ignored, as the overview displays
+   * the colours regardless.
    */
-  @Override
-  protected Color getResidueBoxColour(boolean showBoxes,
+  protected int getResidueBoxColourInt(boolean showBoxes,
           ResidueShaderI shader, SequenceGroup[] allGroups, SequenceI seq,
           int i)
   {
@@ -114,7 +127,7 @@ public class OverviewResColourFinder extends ResidueColourFinder
             i);
     ResidueShaderI currentShader = (currentSequenceGroup == null ? shader
             : currentSequenceGroup.getGroupColourScheme());
-    return getBoxColour(currentShader, seq, i);
+    return getBoxColourInt(currentShader, seq, i);
   }
 
   /**
index 2da7233..2e45117 100644 (file)
@@ -116,12 +116,13 @@ public class ResidueColourFinder
   public SequenceGroup getCurrentSequenceGroup(SequenceGroup[] allGroups,
           int res)
   {
-    if (allGroups == null)
+    int n;
+    if (allGroups == null || (n = allGroups.length) == 0)
     {
       return null;
     }
 
-    for (int i = 0; i < allGroups.length; i++)
+    for (int i = 0; i < n; i++)
     {
       if ((allGroups[i].getStartRes() <= res)
               && (allGroups[i].getEndRes() >= res))
index 7fce08b..8da880a 100644 (file)
@@ -117,13 +117,48 @@ public class FeatureColourFinder
     return c;
   }
 
+  public int findFeatureColourInt(int defaultColour, SequenceI seq,
+          int column)
+  {
+    // if (noFeaturesDisplayed())
+    // {
+    // return defaultColour;
+    // }
+
+    Graphics g = null;
+
+    /*
+     * if transparency applies, provide a notional 1x1 graphics context 
+     * that has been primed with the default colour
+     */
+    if (featureRenderer.getTransparency() != 1f)
+    {
+      g = goff;
+      if (defaultColour != 0)
+      {
+        offscreenImage.setRGB(0, 0, defaultColour);
+      }
+    }
+
+    Color c = featureRenderer.findFeatureColour(seq, column + 1, g);
+    if (c == null)
+    {
+      return defaultColour;
+    }
+
+    if (g != null)
+    {
+      return offscreenImage.getRGB(0, 0);
+    }
+    return c.getRGB();
+  }
   /**
    * Answers true if feature display is turned off, or there are no features
    * configured to be visible
    * 
    * @return
    */
-  boolean noFeaturesDisplayed()
+  public boolean noFeaturesDisplayed()
   {
     if (featureRenderer == null
             || !featureRenderer.getViewport().isShowSequenceFeatures())
index 3ac236d..8dc7dd8 100644 (file)
@@ -304,10 +304,10 @@ public abstract class OverviewDimensions
     boxY = Math.round(vpbox.y / heightRatio);
 
     // boxWidth is the width in residues translated to pixels
-    boxWidth = Math.round(vpbox.width / widthRatio);
+    boxWidth = Math.max(1, Math.round(vpbox.width / widthRatio));
 
     // boxHeight is the height in sequences translated to pixels
-    boxHeight = Math.round(vpbox.height / heightRatio);
+    boxHeight = Math.max(1, Math.round(vpbox.height / heightRatio));
   }
 
   /**
index 6bf1f45..5923e1f 100644 (file)
@@ -266,11 +266,14 @@ public abstract class FeatureRendererModel
 
   boolean findingFeatures = false;
 
+  int nup;
+
   protected boolean updateFeatures()
   {
     if (av.getFeaturesDisplayed() == null || renderOrder == null
             || newFeatureAdded)
     {
+      System.out.println("updateFeatures " + ++nup);
       findAllFeatures();
       if (av.getFeaturesDisplayed().getVisibleFeatureCount() < 1)
       {