import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.VisibleContigsIterator;
import jalview.renderer.ScaleRenderer;
import jalview.renderer.ScaleRenderer.ScaleMark;
import jalview.util.Comparison;
import jalview.viewmodel.ViewportListenerI;
import jalview.viewmodel.ViewportRanges;
-import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
+import java.awt.Rectangle;
import java.awt.RenderingHints;
-import java.awt.Shape;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
+import java.util.Iterator;
import java.util.List;
-import javax.swing.JComponent;
+import javax.swing.JPanel;
/**
* The Swing component on which the alignment sequences, and annotations (if
* Wrapped mode, but not the scale above in Unwrapped mode.
*
*/
-public class SeqCanvas extends JComponent implements ViewportListenerI
+@SuppressWarnings("serial")
+public class SeqCanvas extends JPanel implements ViewportListenerI
{
+ /**
+ * vertical gap in pixels between sequences and annotations when in wrapped mode
+ */
+ static final int SEQS_ANNOTATION_GAP = 3;
+
private static final String ZEROS = "0000000000";
final FeatureRenderer fr;
private final SequenceRenderer seqRdr;
- private boolean fastPaint = false;
+ boolean fastPaint = false;
private boolean fastpainting = false;
private int labelWidthWest; // label left width in pixels if shown
- private int wrappedSpaceAboveAlignment; // gap between widths
+ int wrappedSpaceAboveAlignment; // gap between widths
- private int wrappedRepeatHeightPx; // height in pixels of wrapped width
+ int wrappedRepeatHeightPx; // height in pixels of wrapped width
private int wrappedVisibleWidths; // number of wrapped widths displayed
- private Graphics2D gg;
+ // Don't do this! Graphics handles are supposed to be transient
+ //private Graphics2D gg;
/**
* Creates a new SeqCanvas object.
public SequenceRenderer getSequenceRenderer()
{
- return seqRdr;
+ return seqRdr;
}
public FeatureRenderer getFeatureRenderer()
int yPos = ypos + charHeight;
int startX = startx;
int endX = endx;
-
+
if (av.hasHiddenColumns())
{
HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns();
- startX = hiddenColumns.adjustForHiddenColumns(startx);
- endX = hiddenColumns.adjustForHiddenColumns(endx);
+ startX = hiddenColumns.visibleToAbsoluteColumn(startx);
+ endX = hiddenColumns.visibleToAbsoluteColumn(endx);
}
FontMetrics fm = getFontMetrics(av.getFont());
}
}
+
/*
* white fill the space for the scale
*/
g.drawString(valueAsString, xOffset, y);
}
}
+
}
/**
* <li>scrolling by trackpad, middle mouse button, or other device</li>
* <li>by moving the box in the Overview window</li>
* <li>programmatically to make a highlighted position visible</li>
+ * <li>pasting a block of sequences</li>
* </ul>
*
* @param horizontal
*/
public void fastPaint(int horizontal, int vertical)
{
- if (fastpainting || gg == null || img == null)
+
+ // effectively:
+ // if (horizontal != 0 && vertical != 0)
+ // throw new InvalidArgumentException();
+ if (fastpainting || img == null)
{
return;
}
fastpainting = true;
fastPaint = true;
-
try
{
int charHeight = av.getCharHeight();
int charWidth = av.getCharWidth();
-
+
ViewportRanges ranges = av.getRanges();
int startRes = ranges.getStartRes();
int endRes = ranges.getEndRes();
int transX = 0;
int transY = 0;
- gg.copyArea(horizontal * charWidth, vertical * charHeight,
- img.getWidth(), img.getHeight(), -horizontal * charWidth,
- -vertical * charHeight);
-
- if (horizontal > 0) // scrollbar pulled right, image to the left
- {
- transX = (endRes - startRes - horizontal) * charWidth;
- startRes = endRes - horizontal;
- }
- else if (horizontal < 0)
- {
- endRes = startRes - horizontal;
- }
- else if (vertical > 0) // scroll down
- {
- startSeq = endSeq - vertical;
-
- if (startSeq < ranges.getStartSeq())
- { // ie scrolling too fast, more than a page at a time
- startSeq = ranges.getStartSeq();
+ if (horizontal > 0) // scrollbar pulled right, image to the left
+ {
+ transX = (endRes - startRes - horizontal) * charWidth;
+ startRes = endRes - horizontal;
}
- else
+ else if (horizontal < 0)
{
- transY = img.getHeight() - ((vertical + 1) * charHeight);
+ endRes = startRes - horizontal;
}
- }
- else if (vertical < 0)
- {
- endSeq = startSeq - vertical;
- if (endSeq > ranges.getEndSeq())
+ if (vertical > 0) // scroll down
{
- endSeq = ranges.getEndSeq();
+ startSeq = endSeq - vertical;
+
+ if (startSeq < ranges.getStartSeq())
+ { // ie scrolling too fast, more than a page at a time
+ startSeq = ranges.getStartSeq();
+ }
+ else
+ {
+ transY = img.getHeight() - ((vertical + 1) * charHeight);
+ }
+ }
+ else if (vertical < 0)
+ {
+ endSeq = startSeq - vertical;
+
+ if (endSeq > ranges.getEndSeq())
+ {
+ endSeq = ranges.getEndSeq();
+ }
}
- }
- gg.translate(transX, transY);
- drawPanel(gg, startRes, endRes, startSeq, endSeq, 0);
- gg.translate(-transX, -transY);
- repaint();
+ // System.err.println(">>> FastPaint to " + transX + " " + transY + " "
+ // + horizontal + " " + vertical + " " + startRes + " " + endRes
+ // + " " + startSeq + " " + endSeq);
+
+ Graphics gg = img.getGraphics();
+ gg.copyArea(horizontal * charWidth, vertical * charHeight,
+ img.getWidth(), img.getHeight(), -horizontal * charWidth,
+ -vertical * charHeight);
+
+ /** @j2sNative xxi = this.img */
+
+ gg.translate(transX, transY);
+ drawPanel(gg, startRes, endRes, startSeq, endSeq, 0);
+ gg.translate(-transX, -transY);
+ gg.dispose();
+
+ // 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.
+ // System.out.println("SeqCanvas fastPaint() repaint() request...");
+ av.getAlignPanel().repaint();
} finally
{
fastpainting = false;
@Override
public void paintComponent(Graphics g)
{
- super.paintComponent(g);
-
+
int charHeight = av.getCharHeight();
int charWidth = av.getCharWidth();
- ViewportRanges ranges = av.getRanges();
-
int width = getWidth();
int height = getHeight();
width -= (width % charWidth);
height -= (height % charHeight);
- // selectImage is the selection group outline image
- BufferedImage selectImage = drawSelectionGroup(
- ranges.getStartRes(), ranges.getEndRes(),
- ranges.getStartSeq(), ranges.getEndSeq());
-
- BufferedImage cursorImage = drawCursor(ranges.getStartRes(),
- ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq());
+ // BH 2019 can't possibly fastPaint if either width or height is 0
- if ((img != null) && (fastPaint
- || (getVisibleRect().width != g.getClipBounds().width)
- || (getVisibleRect().height != g.getClipBounds().height)))
+ if (width == 0 || height == 0)
{
- BufferedImage lcimg = buildLocalImage(selectImage, cursorImage);
- g.drawImage(lcimg, 0, 0, this);
+ return;
+ }
+
+ ViewportRanges ranges = av.getRanges();
+ int startRes = ranges.getStartRes();
+ int startSeq = ranges.getStartSeq();
+ int endRes = ranges.getEndRes();
+ int endSeq = ranges.getEndSeq();
+
+ // [JAL-3226] problem that JavaScript (or Java) may consolidate multiple
+ // repaint() requests in unpredictable ways. In this case, the issue was
+ // that in response to a CTRL-C/CTRL-V paste request, in Java a fast
+ // repaint request preceded two full requests, thus resulting
+ // in a full request for paint. In constrast, in JavaScript, the three
+ // requests were bundled together into one, so the fastPaint flag was
+ // still present for the second and third request.
+ //
+ // This resulted in incomplete painting.
+ //
+ // The solution was to set seqCanvas.fastPaint and idCanvas.fastPaint false
+ // in PaintRefresher when the target to be painted is one of those two
+ // components.
+ //
+ // BH 2019.04.22
+ //
+ // An initial idea; can be removed once we determine this issue is closed:
+ // if (av.isFastPaintDisabled())
+ // {
+ // fastPaint = false;
+ // }
+
+ Rectangle vis, clip;
+ if (img != null
+ && (fastPaint
+ || (vis = getVisibleRect()).width != (clip = g
+ .getClipBounds()).width
+ || vis.height != clip.height))
+ {
+ g.drawImage(img, 0, 0, this);
+ drawSelectionGroup((Graphics2D) g, startRes, endRes, startSeq,
+ endSeq);
fastPaint = false;
}
- else if ((width > 0) && (height > 0))
+ else
{
- // img is a cached version of the last view we drew, if any
- // if we have no img or the size has changed, make a new one
+ // 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())
{
- img = setupImage();
- if (img == null)
- {
- return;
- }
- gg = (Graphics2D) img.getGraphics();
- gg.setFont(av.getFont());
+ img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
+ Graphics2D gg = (Graphics2D) img.getGraphics();
+ gg.setFont(av.getFont());
+
if (av.antiAlias)
{
gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
if (av.getWrapAlignment())
{
- drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes());
+ drawWrappedPanel(gg, width, height, ranges.getStartRes());
}
else
{
- drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(),
- ranges.getStartSeq(), ranges.getEndSeq(), 0);
+ drawPanel(gg, startRes, endRes, startSeq, endSeq, 0);
}
- // lcimg is a local *copy* of img which we'll draw selectImage on top of
- BufferedImage lcimg = buildLocalImage(selectImage, cursorImage);
- g.drawImage(lcimg, 0, 0, this);
+ drawSelectionGroup(gg, startRes, endRes, startSeq, endSeq);
+
+ g.drawImage(img, 0, 0, this);
+ gg.dispose();
+ }
+
+ if (av.cursorMode)
+ {
+ drawCursor(g, startRes, endRes, startSeq, endSeq);
}
}
{
drawPanel(g1, startRes, endRes, startSeq, endSeq, 0);
- BufferedImage selectImage = drawSelectionGroup(startRes, endRes,
+ drawSelectionGroup((Graphics2D) g1, startRes, endRes,
startSeq, endSeq);
- if (selectImage != null)
- {
- ((Graphics2D) g1).setComposite(AlphaComposite
- .getInstance(AlphaComposite.SRC_OVER));
- g1.drawImage(selectImage, 0, 0, this);
- }
}
/**
public void drawWrappedPanelForPrinting(Graphics g, int canvasWidth,
int canvasHeight, int startRes)
{
- SequenceGroup group = av.getSelectionGroup();
-
drawWrappedPanel(g, canvasWidth, canvasHeight, startRes);
+ SequenceGroup group = av.getSelectionGroup();
if (group != null)
{
- BufferedImage selectImage = null;
- try
- {
- selectImage = new BufferedImage(canvasWidth, canvasHeight,
- BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works
- } catch (OutOfMemoryError er)
- {
- System.gc();
- System.err.println("Print image OutOfMemory Error.\n" + er);
- new OOMWarning("Creating wrapped alignment image for printing", er);
- }
- if (selectImage != null)
- {
- Graphics2D g2 = selectImage.createGraphics();
- setupSelectionGroup(g2, selectImage);
- drawWrappedSelection(g2, group, canvasWidth, canvasHeight,
+ drawWrappedSelection((Graphics2D) g, group, canvasWidth, canvasHeight,
startRes);
-
- g2.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
- g.drawImage(selectImage, 0, 0, this);
- g2.dispose();
- }
- }
- }
-
- /*
- * Make a local image by combining the cached image img
- * with any selection
- */
- private BufferedImage buildLocalImage(BufferedImage selectImage,
- BufferedImage cursorImage)
- {
- // clone the cached image
- BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(),
- img.getType());
- Graphics2D g2d = lcimg.createGraphics();
- g2d.drawImage(img, 0, 0, null);
-
- // overlay selection group on lcimg
- if (selectImage != null)
- {
- g2d.setComposite(
- AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
- g2d.drawImage(selectImage, 0, 0, this);
}
- // overlay cursor on lcimg
- if (cursorImage != null)
- {
- g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
- g2d.drawImage(cursorImage, 0, 0, this);
- }
- g2d.dispose();
-
- return lcimg;
- }
-
- /*
- * Set up a buffered image of the correct height and size for the sequence canvas
- */
- private BufferedImage setupImage()
- {
- BufferedImage lcimg = null;
-
- int charWidth = av.getCharWidth();
- int charHeight = av.getCharHeight();
-
- int width = getWidth();
- int height = getHeight();
-
- width -= (width % charWidth);
- height -= (height % charHeight);
-
- if ((width < 1) || (height < 1))
- {
- return null;
- }
-
- try
- {
- lcimg = new BufferedImage(width, height,
- BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works
- } catch (OutOfMemoryError er)
- {
- System.gc();
- System.err.println(
- "Group image OutOfMemory Redraw Error.\n" + er);
- new OOMWarning("Creating alignment image for display", er);
-
- return null;
- }
-
- return lcimg;
}
/**
ViewportRanges ranges = av.getRanges();
ranges.setViewportStartAndWidth(startColumn, wrappedWidthInResidues);
+ // we need to call this again to make sure the startColumn +
+ // wrappedWidthInResidues values are used to calculate wrappedVisibleWidths
+ // correctly.
+ calculateWrappedGeometry(canvasWidth, canvasHeight);
+
/*
- * draw one width at a time (including any scales or annotation shown),
+ * draw one width at a time (excluding any scales shown),
* until we have run out of either alignment or vertical space available
*/
int ypos = wrappedSpaceAboveAlignment;
* (av.getScaleAboveWrapped() ? 2 : 1);
/*
- * height in pixels of the wrapped widths
+ * compute height in pixels of the wrapped widths
+ * - start with space above plus sequences
*/
wrappedRepeatHeightPx = wrappedSpaceAboveAlignment;
- // add sequences
- wrappedRepeatHeightPx += av.getRanges().getViewportHeight()
+ wrappedRepeatHeightPx += av.getAlignment().getHeight()
* charHeight;
- // add annotations panel height if shown
- wrappedRepeatHeightPx += getAnnotationHeight();
+
+ /*
+ * add annotations panel height if shown
+ * also gap between sequences and annotations
+ */
+ if (av.isShowAnnotation())
+ {
+ wrappedRepeatHeightPx += getAnnotationHeight();
+ wrappedRepeatHeightPx += SEQS_ANNOTATION_GAP; // 3px
+ }
/*
* number of visible widths (the last one may be part height),
* @param endColumn
* @param canvasHeight
*/
- protected void drawWrappedWidth(Graphics g, int ypos, int startColumn,
- int endColumn, int canvasHeight)
+ protected void drawWrappedWidth(Graphics g, final int ypos,
+ final int startColumn, final int endColumn,
+ final int canvasHeight)
{
ViewportRanges ranges = av.getRanges();
int viewportWidth = ranges.getViewportWidth();
int xOffset = labelWidthWest
+ ((startColumn - ranges.getStartRes()) % viewportWidth)
* charWidth;
- g.translate(xOffset, 0);
-
- // When printing we have an extra clipped region,
- // the Printable page which we need to account for here
- Shape clip = g.getClip();
- if (clip == null)
- {
- g.setClip(0, 0, viewportWidth * charWidth, canvasHeight);
- }
- else
- {
- g.setClip(0, (int) clip.getBounds().getY(),
- viewportWidth * charWidth, (int) clip.getBounds().getHeight());
- }
+ g.translate(xOffset, 0);
/*
* white fill the region to be drawn (so incremental fast paint doesn't
* scribble over an existing image)
*/
- gg.setColor(Color.white);
- gg.fillRect(0, ypos, (endx - startColumn + 1) * charWidth,
+ g.setColor(Color.white);
+ g.fillRect(0, ypos, (endx - startColumn + 1) * charWidth,
wrappedRepeatHeightPx);
drawPanel(g, startColumn, endx, 0, av.getAlignment().getHeight() - 1,
if (av.isShowAnnotation())
{
- g.translate(0, cHeight + ypos + 3);
+ final int yShift = cHeight + ypos + SEQS_ANNOTATION_GAP;
+ g.translate(0, yShift);
if (annotations == null)
{
annotations = new AnnotationPanel(av);
annotations.renderer.drawComponent(annotations, av, g, -1,
startColumn, endx + 1);
- g.translate(0, -cHeight - ypos - 3);
+ g.translate(0, -yShift);
}
- g.setClip(clip);
g.translate(-xOffset, 0);
}
int charWidth = av.getCharWidth();
g.setFont(av.getFont());
+
g.setColor(Color.black);
int ypos = wrappedSpaceAboveAlignment;
if (av.getScaleRightWrapped())
{
int x = labelWidthWest + viewportWidth * charWidth;
+
g.translate(x, 0);
drawVerticalScale(g, startCol, endColumn, ypos, false);
g.translate(-x, 0);
int charWidth = av.getCharWidth();
g.setColor(Color.blue);
+ int res;
HiddenColumns hidden = av.getAlignment().getHiddenColumns();
- List<Integer> positions = hidden.findHiddenRegionPositions();
- for (int pos : positions)
+
+ Iterator<Integer> it = hidden.getStartRegionIterator(startColumn,
+ endColumn);
+ while (it.hasNext())
{
- int res = pos - startColumn;
+ res = it.next() - startColumn;
if (res < 0 || res > endColumn - startColumn + 1)
{
int canvasWidth,
int canvasHeight, int startRes)
{
- int charHeight = av.getCharHeight();
- int charWidth = av.getCharWidth();
-
- // height gap above each panel
- int hgap = charHeight;
- if (av.getScaleAboveWrapped())
- {
- hgap += charHeight;
- }
+ // chop the wrapped alignment extent up into panel-sized blocks and treat
+ // each block as if it were a block from an unwrapped alignment
+ g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_ROUND, 3f, new float[]
+ { 5f, 3f }, 0f));
+ g.setColor(Color.RED);
+ int charWidth = av.getCharWidth();
int cWidth = (canvasWidth - labelWidthEast - labelWidthWest)
/ charWidth;
- int cHeight = av.getAlignment().getHeight() * charHeight;
-
int startx = startRes;
- int endx;
- int ypos = hgap; // vertical offset
- int maxwidth = av.getAlignment().getWidth();
-
- if (av.hasHiddenColumns())
- {
- maxwidth = av.getAlignment().getHiddenColumns()
- .findColumnPosition(maxwidth);
- }
+ int maxwidth = av.getAlignment().getVisibleWidth();
+ int ypos = wrappedSpaceAboveAlignment;
- // chop the wrapped alignment extent up into panel-sized blocks and treat
- // each block as if it were a block from an unwrapped alignment
while ((ypos <= canvasHeight) && (startx < maxwidth))
{
// set end value to be start + width, or maxwidth, whichever is smaller
- endx = startx + cWidth - 1;
+ int endx = startx + cWidth - 1;
if (endx > maxwidth)
{
}
g.translate(labelWidthWest, 0);
-
drawUnwrappedSelection(g, group, startx, endx, 0,
av.getAlignment().getHeight() - 1,
ypos);
-
g.translate(-labelWidthWest, 0);
- // update vertical offset
- ypos += cHeight + getAnnotationHeight() + hgap;
+ ypos += wrappedRepeatHeightPx;
- // update horizontal offset
startx += cWidth;
}
+ g.setStroke(new BasicStroke());
}
+ /**
+ * Answers zero if annotations are not shown, otherwise recalculates and answers
+ * the total height of all annotation rows in pixels
+ *
+ * @return
+ */
int getAnnotationHeight()
{
if (!av.isShowAnnotation())
else
{
int screenY = 0;
- final int screenYMax = endRes - startRes;
- int blockStart = startRes;
- int blockEnd = endRes;
+ int blockStart;
+ int blockEnd;
- for (int[] region : av.getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy())
- {
- int hideStart = region[0];
- int hideEnd = region[1];
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+ VisibleContigsIterator regions = hidden
+ .getVisContigsIterator(startRes, endRes + 1, true);
- if (hideStart <= blockStart)
- {
- blockStart += (hideEnd - hideStart) + 1;
- continue;
- }
+ while (regions.hasNext())
+ {
+ int[] region = regions.next();
+ blockEnd = region[1];
+ blockStart = region[0];
/*
* draw up to just before the next hidden region, or the end of
* the visible region, whichever comes first
*/
- blockEnd = Math.min(hideStart - 1, blockStart + screenYMax
- - screenY);
-
g1.translate(screenY * charWidth, 0);
draw(g1, blockStart, blockEnd, startSeq, endSeq, yOffset);
* draw the downline of the hidden column marker (ScalePanel draws the
* triangle on top) if we reached it
*/
- if (av.getShowHiddenMarkers() && blockEnd == hideStart - 1)
+ if (av.getShowHiddenMarkers()
+ && (regions.hasNext() || regions.endsAtHidden()))
{
g1.setColor(Color.blue);
g1.translate(-screenY * charWidth, 0);
screenY += blockEnd - blockStart + 1;
- blockStart = hideEnd + 1;
-
- if (screenY > screenYMax)
- {
- // already rendered last block
- return;
- }
- }
-
- if (screenY <= screenYMax)
- {
- // remaining visible region to render
- blockEnd = blockStart + screenYMax - screenY;
- g1.translate(screenY * charWidth, 0);
- draw(g1, blockStart, blockEnd, startSeq, endSeq, yOffset);
-
- g1.translate(-screenY * charWidth, 0);
}
}
if (av.hasSearchResults())
{
SearchResultsI searchResults = av.getSearchResults();
- int[] visibleResults = searchResults.getResults(nextSeq,
- startRes, endRes);
+ int[] visibleResults = searchResults.getResults(nextSeq, startRes,
+ endRes);
if (visibleResults != null)
{
for (int r = 0; r < visibleResults.length; r += 2)
{
seqRdr.drawHighlightedText(nextSeq, visibleResults[r],
- visibleResults[r + 1], (visibleResults[r] - startRes)
- * charWidth, offset
- + ((i - startSeq) * charHeight));
+ visibleResults[r + 1],
+ (visibleResults[r] - startRes) * charWidth,
+ offset + ((i - startSeq) * charHeight));
}
}
}
-
- /* if (av.cursorMode && cursorY == i && cursorX >= startRes
- && cursorX <= endRes)
- {
- seqRdr.drawCursor(nextSeq, cursorX, (cursorX - startRes) * charWidth,
- offset + ((i - startSeq) * charHeight));
- }*/
}
if (av.getSelectionGroup() != null
}
+ /**
+ * Draws the outlines of any groups defined on the alignment (excluding the
+ * current selection group, if any)
+ *
+ * @param g1
+ * @param startRes
+ * @param endRes
+ * @param startSeq
+ * @param endSeq
+ * @param offset
+ */
void drawGroupsBoundaries(Graphics g1, int startRes, int endRes,
int startSeq, int endSeq, int offset)
{
Graphics2D g = (Graphics2D) g1;
- //
- // ///////////////////////////////////
- // Now outline any areas if necessary
- // ///////////////////////////////////
SequenceGroup group = null;
int groupIndex = -1;
if (group != null)
{
- g.setStroke(new BasicStroke());
- g.setColor(group.getOutlineColour());
-
do
{
+ g.setColor(group.getOutlineColour());
drawPartialGroupOutline(g, group, startRes, endRes, startSeq,
endSeq, offset);
groupIndex++;
-
- g.setStroke(new BasicStroke());
-
if (groupIndex >= av.getAlignment().getGroups().size())
{
break;
}
-
group = av.getAlignment().getGroups().get(groupIndex);
-
} while (groupIndex < av.getAlignment().getGroups().size());
-
}
-
}
-
- /*
- * Draw the selection group as a separate image and overlay
+ /**
+ * Draws the outline of the current selection group (if any)
+ *
+ * @param g
+ * @param startRes
+ * @param endRes
+ * @param startSeq
+ * @param endSeq
*/
- private BufferedImage drawSelectionGroup(int startRes, int endRes,
+ private void drawSelectionGroup(Graphics2D g, int startRes, int endRes,
int startSeq, int endSeq)
{
- // get a new image of the correct size
- BufferedImage selectionImage = setupImage();
-
- if (selectionImage == null)
- {
- return null;
- }
-
SequenceGroup group = av.getSelectionGroup();
if (group == null)
{
- // nothing to draw
- return null;
+ return;
}
- // set up drawing colour
- Graphics2D g = (Graphics2D) selectionImage.getGraphics();
-
- setupSelectionGroup(g, selectionImage);
-
+ g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_ROUND, 3f, new float[]
+ { 5f, 3f }, 0f));
+ g.setColor(Color.RED);
if (!av.getWrapAlignment())
{
drawUnwrappedSelection(g, group, startRes, endRes, startSeq, endSeq,
drawWrappedSelection(g, group, getWidth(), getHeight(),
av.getRanges().getStartRes());
}
-
- g.dispose();
- return selectionImage;
+ g.setStroke(new BasicStroke());
}
/**
* @return a transparent image of the same size as the sequence canvas, with
* the cursor drawn on it, if any
*/
- private BufferedImage drawCursor(int startRes, int endRes, int startSeq,
+ private void drawCursor(Graphics g, int startRes, int endRes,
+ int startSeq,
int endSeq)
{
- // define our cursor image
- BufferedImage cursorImage = null;
-
// convert the cursorY into a position on the visible alignment
- int cursor_ypos = av.getAlignment().getHiddenColumns()
- .findColumnPosition(cursorY);
+ int cursor_ypos = cursorY;
// don't do work unless we have to
- if (av.cursorMode && cursor_ypos >= startSeq && cursor_ypos <= endSeq)
+ if (cursor_ypos >= startSeq && cursor_ypos <= endSeq)
{
int yoffset = 0;
int xoffset = 0;
// convert the cursorX into a position on the visible alignment
int cursor_xpos = av.getAlignment().getHiddenColumns()
- .findColumnPosition(cursorX);
+ .absoluteToVisibleColumn(cursorX);
- if (av.getWrapAlignment())
+ if (av.getAlignment().getHiddenColumns().isVisible(cursorX))
{
- // work out the correct offsets for the cursor
- int charHeight = av.getCharHeight();
- int charWidth = av.getCharWidth();
- int canvasWidth = getWidth();
- int canvasHeight = getHeight();
-
- // height gap above each panel
- int hgap = charHeight;
- if (av.getScaleAboveWrapped())
+
+ if (av.getWrapAlignment())
{
- hgap += charHeight;
- }
+ // work out the correct offsets for the cursor
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
+ int canvasWidth = getWidth();
+ int canvasHeight = getHeight();
+
+ // height gap above each panel
+ int hgap = charHeight;
+ if (av.getScaleAboveWrapped())
+ {
+ hgap += charHeight;
+ }
- int cWidth = (canvasWidth - labelWidthEast - labelWidthWest)
- / charWidth;
- int cHeight = av.getAlignment().getHeight() * charHeight;
+ int cWidth = (canvasWidth - labelWidthEast - labelWidthWest)
+ / charWidth;
+ int cHeight = av.getAlignment().getHeight() * charHeight;
- endx = startx + cWidth - 1;
- int ypos = hgap; // vertical offset
+ endx = startx + cWidth - 1;
+ int ypos = hgap; // vertical offset
- // iterate down the wrapped panels
- while ((ypos <= canvasHeight) && (endx < cursor_xpos))
- {
- // update vertical offset
- ypos += cHeight + getAnnotationHeight() + hgap;
+ // iterate down the wrapped panels
+ while ((ypos <= canvasHeight) && (endx < cursor_xpos))
+ {
+ // update vertical offset
+ ypos += cHeight + getAnnotationHeight() + hgap;
- // update horizontal offset
- startx += cWidth;
- endx = startx + cWidth - 1;
+ // update horizontal offset
+ startx += cWidth;
+ endx = startx + cWidth - 1;
+ }
+ yoffset = ypos;
+ xoffset = labelWidthWest;
}
- yoffset = ypos;
- xoffset = labelWidthWest;
- }
- // now check if cursor is within range for x values
- if (cursor_xpos >= startx && cursor_xpos <= endx)
- {
- // get a new image of the correct size
- cursorImage = setupImage();
- Graphics2D g = (Graphics2D) cursorImage.getGraphics();
-
- // get the character the cursor is drawn at
- SequenceI seq = av.getAlignment().getSequenceAt(cursorY);
- char s = seq.getCharAt(cursorX);
-
- seqRdr.drawCursor(g, s,
- xoffset + (cursor_xpos - startx) * av.getCharWidth(),
- yoffset + (cursor_ypos - startSeq) * av.getCharHeight());
- g.dispose();
+ // now check if cursor is within range for x values
+ if (cursor_xpos >= startx && cursor_xpos <= endx)
+ {
+ // get the character the cursor is drawn at
+ SequenceI seq = av.getAlignment().getSequenceAt(cursorY);
+ char s = seq.getCharAt(cursorX);
+
+ seqRdr.drawCursor(g, s,
+ xoffset + (cursor_xpos - startx) * av.getCharWidth(),
+ yoffset + (cursor_ypos - startSeq) * av.getCharHeight());
+ }
}
}
-
- return cursorImage;
}
- /*
- * Set up graphics for selection group
- */
- private void setupSelectionGroup(Graphics2D g,
- BufferedImage selectionImage)
- {
- // set background to transparent
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f));
- g.fillRect(0, 0, selectionImage.getWidth(), selectionImage.getHeight());
-
- // set up foreground to draw red dashed line
- g.setComposite(AlphaComposite.Src);
- g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
- BasicStroke.JOIN_ROUND, 3f, new float[]
- { 5f, 3f }, 0f));
- g.setColor(Color.RED);
- }
-
- /*
+ /**
* Draw a selection group over an unwrapped alignment
- * @param g graphics object to draw with
- * @param group selection group
- * @param startRes start residue of area to draw
- * @param endRes end residue of area to draw
- * @param startSeq start sequence of area to draw
- * @param endSeq end sequence of area to draw
- * @param offset vertical offset (used when called from wrapped alignment code)
+ *
+ * @param g
+ * graphics object to draw with
+ * @param group
+ * selection group
+ * @param startRes
+ * start residue of area to draw
+ * @param endRes
+ * end residue of area to draw
+ * @param startSeq
+ * start sequence of area to draw
+ * @param endSeq
+ * end sequence of area to draw
+ * @param offset
+ * vertical offset (used when called from wrapped alignment code)
*/
private void drawUnwrappedSelection(Graphics2D g, SequenceGroup group,
int startRes, int endRes, int startSeq, int endSeq, int offset)
{
- int charWidth = av.getCharWidth();
-
+ int charWidth = av.getCharWidth();
+
if (!av.hasHiddenColumns())
{
drawPartialGroupOutline(g, group, startRes, endRes, startSeq, endSeq,
{
// package into blocks of visible columns
int screenY = 0;
- int blockStart = startRes;
- int blockEnd = endRes;
+ int blockStart;
+ int blockEnd;
- for (int[] region : av.getAlignment().getHiddenColumns()
- .getHiddenColumnsCopy())
+ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
+ VisibleContigsIterator regions = hidden
+ .getVisContigsIterator(startRes, endRes + 1, true);
+ while (regions.hasNext())
{
- int hideStart = region[0];
- int hideEnd = region[1];
-
- if (hideStart <= blockStart)
- {
- blockStart += (hideEnd - hideStart) + 1;
- continue;
- }
-
- blockEnd = hideStart - 1;
+ int[] region = regions.next();
+ blockEnd = region[1];
+ blockStart = region[0];
g.translate(screenY * charWidth, 0);
drawPartialGroupOutline(g, group,
g.translate(-screenY * charWidth, 0);
screenY += blockEnd - blockStart + 1;
- blockStart = hideEnd + 1;
-
- if (screenY > (endRes - startRes))
- {
- // already rendered last block
- break;
- }
- }
-
- if (screenY <= (endRes - startRes))
- {
- // remaining visible region to render
- blockEnd = blockStart + (endRes - startRes) - screenY;
- g.translate(screenY * charWidth, 0);
- drawPartialGroupOutline(g, group,
- blockStart, blockEnd, startSeq, endSeq, offset);
-
- g.translate(-screenY * charWidth, 0);
}
}
}
- /*
- * Draw the selection group as a separate image and overlay
+ /**
+ * Draws part of a selection group outline
+ *
+ * @param g
+ * @param group
+ * @param startRes
+ * @param endRes
+ * @param startSeq
+ * @param endSeq
+ * @param verticalOffset
*/
private void drawPartialGroupOutline(Graphics2D g, SequenceGroup group,
int startRes, int endRes, int startSeq, int endSeq,
int verticalOffset)
{
- int charHeight = av.getCharHeight();
- int charWidth = av.getCharWidth();
-
+ int charHeight = av.getCharHeight();
+ int charWidth = av.getCharWidth();
int visWidth = (endRes - startRes + 1) * charWidth;
int oldY = -1;
boolean inGroup = false;
int top = -1;
int bottom = -1;
-
- int sx = -1;
int sy = -1;
- int xwidth = -1;
-
- for (i = startSeq; i <= endSeq; i++)
- {
- // position of start residue of group relative to startRes, in pixels
- sx = (group.getStartRes() - startRes) * charWidth;
- // width of group in pixels
- xwidth = (((group.getEndRes() + 1) - group.getStartRes()) * charWidth)
- - 1;
+ List<SequenceI> seqs = group.getSequences(null);
- sy = verticalOffset + (i - startSeq) * charHeight;
+ // position of start residue of group relative to startRes, in pixels
+ int sx = (group.getStartRes() - startRes) * charWidth;
- if (sx + xwidth < 0 || sx > visWidth)
- {
- continue;
- }
+ // width of group in pixels
+ int xwidth = (((group.getEndRes() + 1) - group.getStartRes())
+ * charWidth) - 1;
- if ((sx <= (endRes - startRes) * charWidth)
- && group.getSequences(null)
- .contains(av.getAlignment().getSequenceAt(i)))
+ if (!(sx + xwidth < 0 || sx > visWidth))
+ {
+ for (i = startSeq; i <= endSeq; i++)
{
- if ((bottom == -1) && !group.getSequences(null)
- .contains(av.getAlignment().getSequenceAt(i + 1)))
- {
- bottom = sy + charHeight;
- }
-
- if (!inGroup)
- {
- if (((top == -1) && (i == 0)) || !group.getSequences(null)
- .contains(av.getAlignment().getSequenceAt(i - 1)))
- {
- top = sy;
- }
+ sy = verticalOffset + (i - startSeq) * charHeight;
- oldY = sy;
- inGroup = true;
- }
- }
- else
- {
- if (inGroup)
+ if ((sx <= (endRes - startRes) * charWidth)
+ && seqs.contains(av.getAlignment().getSequenceAt(i)))
{
- // if start position is visible, draw vertical line to left of
- // group
- if (sx >= 0 && sx < visWidth)
+ if ((bottom == -1)
+ && !seqs.contains(av.getAlignment().getSequenceAt(i + 1)))
{
- g.drawLine(sx, oldY, sx, sy);
+ bottom = sy + charHeight;
}
- // if end position is visible, draw vertical line to right of
- // group
- if (sx + xwidth < visWidth)
+ if (!inGroup)
{
- g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
- }
-
- if (sx < 0)
- {
- xwidth += sx;
- sx = 0;
- }
-
- // don't let width extend beyond current block, or group extent
- // fixes JAL-2672
- if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
- {
- xwidth = (endRes - startRes + 1) * charWidth - sx;
- }
-
- // draw horizontal line at top of group
- if (top != -1)
- {
- g.drawLine(sx, top, sx + xwidth, top);
- top = -1;
- }
+ if (((top == -1) && (i == 0)) || !seqs
+ .contains(av.getAlignment().getSequenceAt(i - 1)))
+ {
+ top = sy;
+ }
- // draw horizontal line at bottom of group
- if (bottom != -1)
- {
- g.drawLine(sx, bottom, sx + xwidth, bottom);
- bottom = -1;
+ oldY = sy;
+ inGroup = true;
}
+ }
+ else if (inGroup)
+ {
+ drawVerticals(g, sx, xwidth, visWidth, oldY, sy);
+ drawHorizontals(g, sx, xwidth, visWidth, top, bottom);
+ // reset top and bottom
+ top = -1;
+ bottom = -1;
inGroup = false;
}
}
- }
-
- if (inGroup)
- {
- sy = verticalOffset + ((i - startSeq) * charHeight);
- if (sx >= 0 && sx < visWidth)
+ if (inGroup)
{
- g.drawLine(sx, oldY, sx, sy);
+ sy = verticalOffset + ((i - startSeq) * charHeight);
+ drawVerticals(g, sx, xwidth, visWidth, oldY, sy);
+ drawHorizontals(g, sx, xwidth, visWidth, top, bottom);
}
+ }
+ }
- if (sx + xwidth < visWidth)
- {
- g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
- }
+ /**
+ * Draw horizontal selection group boundaries at top and bottom positions
+ *
+ * @param g
+ * graphics object to draw on
+ * @param sx
+ * start x position
+ * @param xwidth
+ * width of gap
+ * @param visWidth
+ * visWidth maximum available width
+ * @param top
+ * position to draw top of group at
+ * @param bottom
+ * position to draw bottom of group at
+ */
+ private void drawHorizontals(Graphics2D g, int sx, int xwidth,
+ int visWidth, int top, int bottom)
+ {
+ int width = xwidth;
+ int startx = sx;
+ if (startx < 0)
+ {
+ width += startx;
+ startx = 0;
+ }
- if (sx < 0)
- {
- xwidth += sx;
- sx = 0;
- }
+ // don't let width extend beyond current block, or group extent
+ // fixes JAL-2672
+ if (startx + width >= visWidth)
+ {
+ width = visWidth - startx;
+ }
- if (sx + xwidth > visWidth)
- {
- xwidth = visWidth;
- }
- else if (sx + xwidth >= (endRes - startRes + 1) * charWidth)
- {
- xwidth = (endRes - startRes + 1) * charWidth;
- }
+ if (top != -1)
+ {
+ g.drawLine(startx, top, startx + width, top);
+ }
- if (top != -1)
- {
- g.drawLine(sx, top, sx + xwidth, top);
- top = -1;
- }
+ if (bottom != -1)
+ {
+ g.drawLine(startx, bottom - 1, startx + width, bottom - 1);
+ }
+ }
- if (bottom != -1)
- {
- g.drawLine(sx, bottom - 1, sx + xwidth, bottom - 1);
- bottom = -1;
- }
+ /**
+ * Draw vertical lines at sx and sx+xwidth providing they lie within
+ * [0,visWidth)
+ *
+ * @param g
+ * graphics object to draw on
+ * @param sx
+ * start x position
+ * @param xwidth
+ * width of gap
+ * @param visWidth
+ * visWidth maximum available width
+ * @param oldY
+ * top y value
+ * @param sy
+ * bottom y value
+ */
+ private void drawVerticals(Graphics2D g, int sx, int xwidth, int visWidth,
+ int oldY, int sy)
+ {
+ // if start position is visible, draw vertical line to left of
+ // group
+ if (sx >= 0 && sx < visWidth)
+ {
+ g.drawLine(sx, oldY, sx, sy);
+ }
- inGroup = false;
+ // if end position is visible, draw vertical line to right of
+ // group
+ if (sx + xwidth < visWidth)
+ {
+ g.drawLine(sx + xwidth, oldY, sx + xwidth, sy);
}
}
* Highlights search results in the visible region by rendering as white text
* on a black background. Any previous highlighting is removed. Answers true
* if any highlight was left on the visible alignment (so status bar should be
+ * set to match), else false. This method does _not_ set the 'fastPaint' flag,
+ * so allows the next repaint to update the whole display.
+ *
+ * @param results
+ * @return
+ */
+ public boolean highlightSearchResults(SearchResultsI results)
+ {
+ return highlightSearchResults(results, false);
+
+ }
+
+ /**
+ * Highlights search results in the visible region by rendering as white text
+ * on a black background. Any previous highlighting is removed. Answers true
+ * if any highlight was left on the visible alignment (so status bar should be
* set to match), else false.
* <p>
- * Currently fastPaint is not implemented for wrapped alignments. If a wrapped
- * alignment had to be scrolled to show the highlighted region, then it should
- * be fully redrawn, otherwise a fast paint can be performed. This argument
- * could be removed if fast paint of scrolled wrapped alignment is coded in
- * future (JAL-2609).
+ * Optionally, set the 'fastPaint' flag for a faster redraw if only the
+ * highlighted regions are modified. This speeds up highlighting across linked
+ * alignments.
+ * <p>
+ * Currently fastPaint is not implemented for scrolled wrapped alignments. If
+ * a wrapped alignment had to be scrolled to show the highlighted region, then
+ * it should be fully redrawn, otherwise a fast paint can be performed. This
+ * argument could be removed if fast paint of scrolled wrapped alignment is
+ * coded in future (JAL-2609).
*
* @param results
- * @param noFastPaint
+ * @param doFastPaint
+ * if true, sets a flag so the next repaint only redraws the modified
+ * image
* @return
*/
public boolean highlightSearchResults(SearchResultsI results,
- boolean noFastPaint)
+ boolean doFastPaint)
{
if (fastpainting)
{
boolean wrapped = av.getWrapAlignment();
try
{
- fastPaint = !noFastPaint;
+ fastPaint = doFastPaint;
fastpainting = fastPaint;
/*
*/
protected boolean drawMappedPositions(SearchResultsI results)
{
- if (results == null)
+ if ((results == null) || (img == null)) // JAL-2784 check gg is not null
{
return false;
}
if (av.hasHiddenColumns())
{
firstVisibleColumn = alignment.getHiddenColumns()
- .adjustForHiddenColumns(firstVisibleColumn);
+ .visibleToAbsoluteColumn(firstVisibleColumn);
lastVisibleColumn = alignment.getHiddenColumns()
- .adjustForHiddenColumns(lastVisibleColumn);
+ .visibleToAbsoluteColumn(lastVisibleColumn);
}
for (int seqNo = ranges.getStartSeq(); seqNo <= ranges
if (av.hasHiddenColumns())
{
firstCol = alignment.getHiddenColumns()
- .findColumnPosition(firstCol);
- lastCol = alignment.getHiddenColumns().findColumnPosition(lastCol);
+ .absoluteToVisibleColumn(firstCol);
+ lastCol = alignment.getHiddenColumns().absoluteToVisibleColumn(lastCol);
}
int transX = (firstCol - ranges.getStartRes()) * av.getCharWidth();
int transY = (firstSeq - ranges.getStartSeq()) * av.getCharHeight();
+ Graphics gg = img.getGraphics();
gg.translate(transX, transY);
drawPanel(gg, firstCol, lastCol, firstSeq, lastSeq, 0);
gg.translate(-transX, -transY);
+ gg.dispose();
}
return matchFound;
public void propertyChange(PropertyChangeEvent evt)
{
String eventName = evt.getPropertyName();
-
+ // System.err.println(">>SeqCanvas propertyChange " + eventName);
if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED))
{
fastPaint = true;
repaint();
return;
}
+ else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT))
+ {
+ fastPaint = false;
+ // System.err.println("!!!! fastPaint false from MOVE_VIEWPORT");
+ repaint();
+ return;
+ }
int scrollX = 0;
- if (eventName.equals(ViewportRanges.STARTRES))
+ if (eventName.equals(ViewportRanges.STARTRES)
+ || eventName.equals(ViewportRanges.STARTRESANDSEQ))
{
// Make sure we're not trying to draw a panel
// larger than the visible window
+ if (eventName.equals(ViewportRanges.STARTRES))
+ {
+ scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+ }
+ else
+ {
+ scrollX = ((int[]) evt.getNewValue())[0]
+ - ((int[]) evt.getOldValue())[0];
+ }
ViewportRanges vpRanges = av.getRanges();
- scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
- int range = vpRanges.getViewportWidth();
+
+ int range = vpRanges.getEndRes() - vpRanges.getStartRes() + 1;
if (scrollX > range)
{
scrollX = range;
scrollX = -range;
}
}
-
// 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.
-
- // scroll - startres and endres both change
if (eventName.equals(ViewportRanges.STARTRES))
{
if (av.getWrapAlignment())
// scroll
fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
}
+ else if (eventName.equals(ViewportRanges.STARTRESANDSEQ))
+ {
+ if (av.getWrapAlignment())
+ {
+ fastPaintWrapped(scrollX);
+ }
+ else
+ {
+ fastPaint(scrollX, 0);
+ }
+ }
+ else if (eventName.equals(ViewportRanges.STARTSEQ))
+ {
+ // scroll
+ fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
+ }
+ else if (eventName.equals(ViewportRanges.STARTRESANDSEQ))
+ {
+ if (av.getWrapAlignment())
+ {
+ fastPaintWrapped(scrollX);
+ }
+ }
}
/**
{
ViewportRanges ranges = av.getRanges();
- if (Math.abs(scrollX) > ranges.getViewportWidth())
+ if (Math.abs(scrollX) >= ranges.getViewportWidth())
{
/*
- * shift of more than one view width is
+ * shift of one view width or more is
* overcomplicated to handle in this method
*/
fastPaint = false;
return;
}
- if (fastpainting || gg == null)
+ if (fastpainting || img == null)
{
return;
}
try
{
+
+ Graphics gg = img.getGraphics();
+
calculateWrappedGeometry(getWidth(), getHeight());
/*
*/
drawWrappedDecorators(gg, ranges.getStartRes());
+ gg.dispose();
+
repaint();
} finally
{
return;
}
+ Graphics gg = img.getGraphics();
+
ViewportRanges ranges = av.getRanges();
int viewportWidth = ranges.getViewportWidth();
int charWidth = av.getCharWidth();
/*
* white fill first to erase annotations
*/
+
+
gg.translate(xOffset, 0);
gg.setColor(Color.white);
gg.fillRect(labelWidthWest, ypos,
gg.translate(-xOffset, 0);
drawWrappedWidth(gg, ypos, startRes, endRes, canvasHeight);
+
}
/*
gg.setColor(Color.white);
gg.fillRect(0, canvasHeight - heightBelow, getWidth(), heightBelow);
}
- }
+ gg.dispose();
+ }
/**
* Shifts the visible alignment by the specified number of columns - left if
{
return;
}
+
+ Graphics gg = img.getGraphics();
+
int charWidth = av.getCharWidth();
int canvasHeight = getHeight();
while (y >= 0)
{
+ /*
+ * shift 'widthToCopy' residues by 'positions' places to the right
+ */
gg.copyArea(copyFromLeftStart, y, widthToCopy, heightToCopy,
positions * charWidth, 0);
if (y > 0)
{
+ /*
+ * copy 'positions' residue from the row above (right hand end)
+ * to this row's left hand end
+ */
gg.copyArea(copyFromRightStart, y - wrappedRepeatHeightPx,
positions * charWidth, heightToCopy, -widthToCopy,
wrappedRepeatHeightPx);
* charWidth, heightToCopy, widthToCopy,
-wrappedRepeatHeightPx);
}
-
y += wrappedRepeatHeightPx;
xpos += viewportWidth;
}
}
+ gg.dispose();
}
*/
protected boolean drawMappedPositionsWrapped(SearchResultsI results)
{
- if (results == null)
+ if ((results == null) || (img == null)) // JAL-2784 check gg is not null
{
return false;
}
if (av.hasHiddenColumns())
{
firstVisibleColumn = alignment.getHiddenColumns()
- .adjustForHiddenColumns(firstVisibleColumn);
+ .visibleToAbsoluteColumn(firstVisibleColumn);
lastVisibleColumn = alignment.getHiddenColumns()
- .adjustForHiddenColumns(lastVisibleColumn);
+ .visibleToAbsoluteColumn(lastVisibleColumn);
}
int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
+
+ Graphics gg = img.getGraphics();
+
for (int seqNo = ranges.getStartSeq(); seqNo <= ranges
.getEndSeq(); seqNo++)
{
if (av.hasHiddenColumns())
{
displayColumn = alignment.getHiddenColumns()
- .findColumnPosition(displayColumn);
+ .absoluteToVisibleColumn(displayColumn);
}
/*
}
}
+ gg.dispose();
+
return matchFound;
}
{
return labelWidthWest;
}
+
}