{
g.drawString(mstring, mpos * charWidth, ypos - (charHeight / 2));
}
- g.drawLine((mpos * charWidth) + (charWidth / 2), (ypos + 2)
- - (charHeight / 2), (mpos * charWidth) + (charWidth / 2),
- ypos - 2);
+ g.drawLine((mpos * charWidth) + (charWidth / 2),
+ (ypos + 2) - (charHeight / 2),
+ (mpos * charWidth) + (charWidth / 2), ypos - 2);
}
}
}
{
int x = labelWidthWest - fm.stringWidth(String.valueOf(value))
- charWidth / 2;
- g.drawString(value + "", x, (ypos + (i * charHeight))
- - (charHeight / 5));
+ g.drawString(value + "", x,
+ (ypos + (i * charHeight)) - (charHeight / 5));
}
}
}
if (value != -1)
{
- g.drawString(String.valueOf(value), 0, (ypos + (i * charHeight))
- - (charHeight / 5));
+ g.drawString(String.valueOf(value), 0,
+ (ypos + (i * charHeight)) - (charHeight / 5));
}
}
}
fastpainting = true;
fastPaint = true;
updateViewport();
- gg.copyArea(horizontal * charWidth, vertical * charHeight, imgWidth,
- imgHeight, -horizontal * charWidth, -vertical * charHeight);
ViewportRanges ranges = av.getRanges();
int startRes = ranges.getStartRes();
int transX = 0;
int transY = 0;
+ gg.copyArea(horizontal * charWidth, vertical * charHeight, imgWidth,
+ imgHeight, -horizontal * charWidth, -vertical * charHeight);
+
if (horizontal > 0) // scrollbar pulled right, image to the left
{
transX = (endRes - startRes - horizontal) * charWidth;
// img and call later.
super.paintComponent(g);
- if (lcimg != null
- && (fastPaint
- || (getVisibleRect().width != g.getClipBounds().width) || (getVisibleRect().height != g
- .getClipBounds().height)))
+ if (lcimg != null && (fastPaint
+ || (getVisibleRect().width != g.getClipBounds().width)
+ || (getVisibleRect().height != g.getClipBounds().height)))
{
g.drawImage(lcimg, 0, 0, this);
fastPaint = false;
}
/**
- * DOCUMENT ME!
+ * Returns the visible width of the canvas in residues, after allowing for
+ * East or West scales (if shown)
*
- * @param cwidth
- * DOCUMENT ME!
+ * @param canvasWidth
+ * the width in pixels (possibly including scales)
*
- * @return DOCUMENT ME!
+ * @return
*/
- public int getWrappedCanvasWidth(int cwidth)
+ public int getWrappedCanvasWidth(int canvasWidth)
{
FontMetrics fm = getFontMetrics(av.getFont());
if (av.getScaleLeftWrapped())
{
- labelWidthWest = getLabelWidth(fm);
+ labelWidthWest = labelWidthEast > 0 ? labelWidthEast
+ : getLabelWidth(fm);
}
- return (cwidth - labelWidthEast - labelWidthWest) / charWidth;
+ return (canvasWidth - labelWidthEast - labelWidthWest) / charWidth;
}
/**
*/
protected int getLabelWidth(FontMetrics fm)
{
+ /*
+ * find the biggest sequence end position we need to show
+ * (note this is not necessarily the sequence length)
+ */
int maxWidth = 0;
- for (int i = 0; i < av.getAlignment().getHeight(); i++)
+ AlignmentI alignment = av.getAlignment();
+ for (int i = 0; i < alignment.getHeight(); i++)
{
- maxWidth = Math.max(maxWidth, av.getAlignment().getSequenceAt(i)
- .getEnd());
+ maxWidth = Math.max(maxWidth, alignment.getSequenceAt(i).getEnd());
}
int length = 2;
av.setWrappedWidth(cWidth);
- av.getRanges().setEndRes(av.getRanges().getStartRes() + cWidth - 1);
+ av.getRanges().setViewportStartAndWidth(startRes, cWidth);
int endx;
int ypos = hgap;
- int maxwidth = av.getAlignment().getWidth() - 1;
+ int maxwidth = av.getAlignment().getWidth();
if (av.hasHiddenColumns())
{
maxwidth = av.getAlignment().getHiddenColumns()
- .findColumnPosition(maxwidth) - 1;
+ .findColumnPosition(maxwidth);
}
int annotationHeight = getAnnotationHeight();
g.setColor(Color.blue);
int res;
HiddenColumns hidden = av.getAlignment().getHiddenColumns();
- for (int i = 0; i < hidden.getHiddenRegions().size(); i++)
+ List<Integer> positions = hidden.findHiddenRegionPositions();
+ for (int pos : positions)
{
- res = hidden.findHiddenRegionPosition(i) - startRes;
+ res = pos - startRes;
if (res < 0 || res > endx - startRes)
{
}
gg.fillPolygon(
- new int[] { res * charWidth - charHeight / 4,
+ new int[]
+ { res * charWidth - charHeight / 4,
res * charWidth + charHeight / 4, res * charWidth },
- new int[] { ypos - (charHeight / 2),
- ypos - (charHeight / 2), ypos - (charHeight / 2) + 8 },
+ new int[]
+ { ypos - (charHeight / 2), ypos - (charHeight / 2),
+ ypos - (charHeight / 2) + 8 },
3);
}
annotations = new AnnotationPanel(av);
}
- annotations.renderer.drawComponent(annotations, av, g, -1,
- startRes, endx + 1);
+ annotations.renderer.drawComponent(annotations, av, g, -1, startRes,
+ endx + 1);
g.translate(0, -cHeight - ypos - 3);
}
g.setClip(clip);
}
else
{
- List<int[]> regions = av.getAlignment().getHiddenColumns()
- .getHiddenRegions();
-
int screenY = 0;
final int screenYMax = endRes - startRes;
int blockStart = startRes;
int blockEnd = endRes;
- for (int[] region : regions)
+ for (int[] region : av.getAlignment().getHiddenColumns()
+ .getHiddenColumnsCopy())
{
int hideStart = region[0];
int hideEnd = region[1];
if (av.isShowSequenceFeatures())
{
- fr.drawSequence(g, nextSeq, startRes, endRes, offset
- + ((i - startSeq) * charHeight), false);
+ fr.drawSequence(g, nextSeq, startRes, endRes,
+ offset + ((i - startSeq) * charHeight), false);
}
/*
for (int r = 0; r < visibleResults.length; r += 2)
{
sr.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));
}
}
}
{
sx = (group.getStartRes() - startRes) * charWidth;
sy = offset + ((i - startSeq) * charHeight);
- ex = (((group.getEndRes() + 1) - group.getStartRes()) * charWidth) - 1;
+ ex = (((group.getEndRes() + 1) - group.getStartRes()) * charWidth)
+ - 1;
if (sx + ex < 0 || sx > visWidth)
{
}
if ((sx <= (endRes - startRes) * charWidth)
- && group.getSequences(null).contains(
- av.getAlignment().getSequenceAt(i)))
+ && group.getSequences(null)
+ .contains(av.getAlignment().getSequenceAt(i)))
{
- if ((bottom == -1)
- && !group.getSequences(null).contains(
- av.getAlignment().getSequenceAt(i + 1)))
+ 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)))
+ if (((top == -1) && (i == 0)) || !group.getSequences(null)
+ .contains(av.getAlignment().getSequenceAt(i - 1)))
{
top = sy;
}
if (group == av.getSelectionGroup())
{
g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT,
- BasicStroke.JOIN_ROUND, 3f, new float[] { 5f, 3f },
- 0f));
+ BasicStroke.JOIN_ROUND, 3f, new float[]
+ { 5f, 3f }, 0f));
g.setColor(Color.RED);
}
else
* on a black background. Any previous highlighting is removed. Answers true
* if any highlight was left on the visible alignment (so status bar should be
* set to match), else false.
+ * <p>
+ * Currently fastPaint is not implemented for wrapped alignments. If a wrapped
+ * alignment had to be scrolled to show the highlighted region, then it should
+ * be fully redrawn, otherwise a fast paint can be performed. This argument
+ * could be removed if fast paint of scrolled wrapped alignment is coded in
+ * future (JAL-2609).
*
* @param results
+ * @param noFastPaint
* @return
*/
- public boolean highlightSearchResults(SearchResultsI results)
+ public boolean highlightSearchResults(SearchResultsI results,
+ boolean noFastPaint)
{
- updateViewport();
-
- /*
- * for now, don't attempt fastpaint if wrapped format
- */
- boolean wrapped = av.getWrapAlignment();
- if (wrapped)
+ if (fastpainting)
{
- // drawWrappedMappedPositions(results);
- // img = null;
- // av.setSearchResults(results);
- // repaint();
- // return;
+ return false;
}
-
- fastpainting = true;
- fastPaint = true;
+ boolean wrapped = av.getWrapAlignment();
try
{
+ fastPaint = !noFastPaint;
+ fastpainting = fastPaint;
+
+ updateViewport();
+
/*
* to avoid redrawing the whole visible region, we instead
* redraw just the minimal regions to remove previous highlights
boolean drawn = false;
if (wrapped)
{
- redrawn = drawWrappedMappedPositions(previous);
- drawn = drawWrappedMappedPositions(results);
+ redrawn = drawMappedPositionsWrapped(previous);
+ drawn = drawMappedPositionsWrapped(results);
redrawn |= drawn;
}
else
{
fastpainting = false;
}
-
}
/**
@Override
public void propertyChange(PropertyChangeEvent evt)
{
- if (!av.getWrapAlignment())
+ String eventName = evt.getPropertyName();
+
+ if (av.getWrapAlignment())
{
- if (evt.getPropertyName().equals("startres")
- || evt.getPropertyName().equals("endres"))
+ if (eventName.equals(ViewportRanges.STARTRES))
+ {
+ repaint();
+ }
+ }
+ else
+ {
+ int scrollX = 0;
+ if (eventName.equals(ViewportRanges.STARTRES))
{
// Make sure we're not trying to draw a panel
// larger than the visible window
ViewportRanges vpRanges = av.getRanges();
- int scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
- if (scrollX > vpRanges.getEndRes() - vpRanges.getStartRes())
+ scrollX = (int) evt.getNewValue() - (int) evt.getOldValue();
+ int range = vpRanges.getEndRes() - vpRanges.getStartRes();
+ if (scrollX > range)
{
- scrollX = vpRanges.getEndRes() - vpRanges.getStartRes();
+ scrollX = range;
}
- else if (scrollX < vpRanges.getStartRes() - vpRanges.getEndRes())
+ else if (scrollX < -range)
{
- scrollX = vpRanges.getStartRes() - vpRanges.getEndRes();
+ 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.
+ if (eventName.equals(ViewportRanges.STARTRES))
+ {
+ // scroll - startres and endres both change
fastPaint(scrollX, 0);
}
- else if (evt.getPropertyName().equals("startseq")
- || evt.getPropertyName().equals("endseq"))
+ else if (eventName.equals(ViewportRanges.STARTSEQ))
{
+ // scroll
fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue());
}
}
}
/**
- * Redraws any positions in the search results in the visible region. Any
- * highlights are drawn depending on the search results set on the Viewport,
- * not the results parameter. This allows this method to be called to either
- * clear highlighting (passing the previous search results), or set new
- * highlighting.
+ * Redraws any positions in the search results in the visible region of a
+ * wrapped alignment. Any highlights are drawn depending on the search results
+ * set on the Viewport, not the <code>results</code> argument. This allows
+ * this method to be called either to clear highlights (passing the previous
+ * search results), or to draw new highlights.
*
* @param results
* @return
*/
- protected boolean drawWrappedMappedPositions(SearchResultsI results)
+ protected boolean drawMappedPositionsWrapped(SearchResultsI results)
{
if (results == null)
{
}
boolean matchFound = false;
-
- /*
- * Viewport ranges are set for the 'row' of the wrapped alignment
- * the cursor is in, not the whole visible region; really we want
- * the latter; +-6 a temporary fudge for codons wrapping across lines
- */
+
+ int wrappedWidth = av.getWrappedWidth();
+ int wrappedHeight = getRepeatHeightWrapped();
+
ViewportRanges ranges = av.getRanges();
- int firstVisibleColumn = ranges.getStartRes() - 6;
- int lastVisibleColumn = ranges.getEndRes() + 6;
+ int canvasHeight = getHeight();
+ int repeats = canvasHeight / wrappedHeight;
+ if (canvasHeight / wrappedHeight > 0)
+ {
+ repeats++;
+ }
+
+ int firstVisibleColumn = ranges.getStartRes();
+ int lastVisibleColumn = ranges.getStartRes() + repeats
+ * ranges.getViewportWidth() - 1;
+
AlignmentI alignment = av.getAlignment();
if (av.hasHiddenColumns())
{
lastVisibleColumn = alignment.getHiddenColumns()
.adjustForHiddenColumns(lastVisibleColumn);
}
-
- /*
- * find width of alignment in residues, and height of alignment,
- * so we can calculate where to render each matched position
- */
- int wrappedWidth = av.getWrappedWidth();
- int wrappedHeight = av.getAlignment().getHeight() * av.getCharHeight();
- int gapHeight = av.getCharHeight()
- * (av.getScaleAboveWrapped() ? 2 : 1);
- wrappedHeight += gapHeight;
- wrappedHeight += getAnnotationHeight();
+
+ int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
for (int seqNo = ranges.getStartSeq(); seqNo <= ranges
.getEndSeq(); seqNo++)
* transY: offset from top edge of canvas to residue position
*/
int transY = gapHeight;
- transY += (displayColumn / wrappedWidth) * wrappedHeight;
+ transY += (displayColumn - ranges.getStartRes())
+ / wrappedWidth * wrappedHeight;
transY += (seqNo - ranges.getStartSeq()) * av.getCharHeight();
/*
return matchFound;
}
+
+ /**
+ * Answers the height in pixels of a repeating section of the wrapped
+ * alignment, including space above, scale above if shown, sequences, and
+ * annotation panel if shown
+ *
+ * @return
+ */
+ protected int getRepeatHeightWrapped()
+ {
+ // gap (and maybe scale) above
+ int repeatHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1);
+
+ // add sequences
+ repeatHeight += av.getRanges().getViewportHeight() * charHeight;
+
+ // add annotations panel height if shown
+ repeatHeight += getAnnotationHeight();
+
+ return repeatHeight;
+ }
}