From: hansonr Date: Mon, 29 Jul 2019 21:05:34 +0000 (-0500) Subject: JAL-3253-applet JAL-3383 X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=4435c731351c802772dd1355fdb5747cfacd7838;hp=2d241446c80365862d31e76f2ecccaab33a1547f JAL-3253-applet JAL-3383 Significant improvement to Overview rendering. See JAL-3383 issue for details. --- diff --git a/src/jalview/api/AlignmentColsCollectionI.java b/src/jalview/api/AlignmentColsCollectionI.java index 06b1675..70dda87 100644 --- a/src/jalview/api/AlignmentColsCollectionI.java +++ b/src/jalview/api/AlignmentColsCollectionI.java @@ -20,6 +20,8 @@ */ package jalview.api; +import java.util.BitSet; + public interface AlignmentColsCollectionI extends Iterable { /** @@ -37,4 +39,20 @@ public interface AlignmentColsCollectionI extends Iterable * @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(); } diff --git a/src/jalview/appletgui/OverviewCanvas.java b/src/jalview/appletgui/OverviewCanvas.java index 5ea9c04..7f4e962 100644 --- a/src/jalview/appletgui/OverviewCanvas.java +++ b/src/jalview/appletgui/OverviewCanvas.java @@ -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(); } } diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index ef684f7..328841c 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -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(); } /** diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index 91b29da..98510e3 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -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(); + // } + } + } diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index 93a2456..ebf4da3 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -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(); + } diff --git a/src/jalview/datamodel/AllColsCollection.java b/src/jalview/datamodel/AllColsCollection.java index e216c46..f3077fa 100644 --- a/src/jalview/datamodel/AllColsCollection.java +++ b/src/jalview/datamodel/AllColsCollection.java @@ -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; + } } diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java index 2d43f02..458bde7 100644 --- a/src/jalview/datamodel/HiddenColumns.java +++ b/src/jalview/datamodel/HiddenColumns.java @@ -86,6 +86,20 @@ public class HiddenColumns */ private List 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(); } } diff --git a/src/jalview/datamodel/Sequence.java b/src/jalview/datamodel/Sequence.java index 4c46522..6b52480 100755 --- a/src/jalview/datamodel/Sequence.java +++ b/src/jalview/datamodel/Sequence.java @@ -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; } } diff --git a/src/jalview/datamodel/SequenceI.java b/src/jalview/datamodel/SequenceI.java index 5e2355d..e521029 100755 --- a/src/jalview/datamodel/SequenceI.java +++ b/src/jalview/datamodel/SequenceI.java @@ -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 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(); diff --git a/src/jalview/datamodel/VisibleColsCollection.java b/src/jalview/datamodel/VisibleColsCollection.java index 4ca51b5..cd812a1 100644 --- a/src/jalview/datamodel/VisibleColsCollection.java +++ b/src/jalview/datamodel/VisibleColsCollection.java @@ -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(); + } + } diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 4fa8408..bac06e9 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -4525,6 +4525,7 @@ public class AlignFrame extends GAlignFrame { viewport.setShowSequenceFeatures(true); showSeqFeatures.setSelected(true); + alignPanel.getAlignment().resetColors(); } } diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index d305183..c8f0194 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -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(); } } diff --git a/src/jalview/gui/FeatureRenderer.java b/src/jalview/gui/FeatureRenderer.java index 2c54906..cc034dd 100644 --- a/src/jalview/gui/FeatureRenderer.java +++ b/src/jalview/gui/FeatureRenderer.java @@ -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); } } } diff --git a/src/jalview/gui/OverviewCanvas.java b/src/jalview/gui/OverviewCanvas.java index aafac38..b6df722 100644 --- a/src/jalview/gui/OverviewCanvas.java +++ b/src/jalview/gui/OverviewCanvas.java @@ -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"); diff --git a/src/jalview/gui/OverviewPanel.java b/src/jalview/gui/OverviewPanel.java index 387d3dd..cc647a8 100755 --- a/src/jalview/gui/OverviewPanel.java +++ b/src/jalview/gui/OverviewPanel.java @@ -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(); } } diff --git a/src/jalview/gui/ScalePanel.java b/src/jalview/gui/ScalePanel.java index aa58a88..b06647d 100755 --- a/src/jalview/gui/ScalePanel.java +++ b/src/jalview/gui/ScalePanel.java @@ -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; } } diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 0d27354..2d83e9e 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -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 *
  • whether scales are shown left, right or above the alignment
  • * * - * @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 diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index de67c39..e5a5962 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -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 + + } + } diff --git a/src/jalview/io/AlignFile.java b/src/jalview/io/AlignFile.java index cea2870..c2cf667 100755 --- a/src/jalview/io/AlignFile.java +++ b/src/jalview/io/AlignFile.java @@ -323,14 +323,15 @@ public abstract class AlignFile extends FileParse */ protected void initData() { - seqs = new Vector(); - annotations = new Vector(); - seqGroups = new ArrayList(); + 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(); + 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(); + newickStrings = new Vector<>(); } newickStrings.addElement(new String[] { treeName, newickString }); } diff --git a/src/jalview/io/FeaturesFile.java b/src/jalview/io/FeaturesFile.java index 1fb45bc..aa21b0f 100755 --- a/src/jalview/io/FeaturesFile.java +++ b/src/jalview/io/FeaturesFile.java @@ -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 diff --git a/src/jalview/jbgui/GAlignmentPanel.java b/src/jalview/jbgui/GAlignmentPanel.java index b703b47..3dd0205 100755 --- a/src/jalview/jbgui/GAlignmentPanel.java +++ b/src/jalview/jbgui/GAlignmentPanel.java @@ -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)); diff --git a/src/jalview/renderer/OverviewRenderer.java b/src/jalview/renderer/OverviewRenderer.java index 45cc944..6defca7 100644 --- a/src/jalview/renderer/OverviewRenderer.java +++ b/src/jalview/renderer/OverviewRenderer.java @@ -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 iter; + Iterator 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); } + } /** diff --git a/src/jalview/renderer/OverviewResColourFinder.java b/src/jalview/renderer/OverviewResColourFinder.java index ff52f1d..b950542 100644 --- a/src/jalview/renderer/OverviewResColourFinder.java +++ b/src/jalview/renderer/OverviewResColourFinder.java @@ -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); } /** diff --git a/src/jalview/renderer/ResidueColourFinder.java b/src/jalview/renderer/ResidueColourFinder.java index 2da7233..2e45117 100644 --- a/src/jalview/renderer/ResidueColourFinder.java +++ b/src/jalview/renderer/ResidueColourFinder.java @@ -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)) diff --git a/src/jalview/renderer/seqfeatures/FeatureColourFinder.java b/src/jalview/renderer/seqfeatures/FeatureColourFinder.java index 7fce08b..8da880a 100644 --- a/src/jalview/renderer/seqfeatures/FeatureColourFinder.java +++ b/src/jalview/renderer/seqfeatures/FeatureColourFinder.java @@ -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()) diff --git a/src/jalview/viewmodel/OverviewDimensions.java b/src/jalview/viewmodel/OverviewDimensions.java index 3ac236d..8dc7dd8 100644 --- a/src/jalview/viewmodel/OverviewDimensions.java +++ b/src/jalview/viewmodel/OverviewDimensions.java @@ -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)); } /** diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index 6bf1f45..5923e1f 100644 --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@ -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) {