import jalview.datamodel.SequenceI;
import jalview.renderer.ScaleRenderer;
import jalview.renderer.ScaleRenderer.ScaleMark;
++import jalview.util.Comparison;
import jalview.viewmodel.ViewportListenerI;
import jalview.viewmodel.ViewportRanges;
boolean fastPaint = false;
++ boolean fastpainting = false;
++
int labelWidthWest;
int labelWidthEast;
}
/**
-- * DOCUMENT ME!
++ * Draw the scale to the left or right of a wrapped alignment
*
* @param g
-- * DOCUMENT ME!
* @param startx
-- * DOCUMENT ME!
++ * first column of wrapped width (0.. excluding any hidden columns)
* @param endx
-- * DOCUMENT ME!
++ * last column of wrapped width (0.. excluding any hidden columns)
* @param ypos
-- * DOCUMENT ME!
++ * vertical offset at which to begin the scale
++ * @param left
++ * if true, scale is left of residues, if false, scale is right
*/
-- void drawWestScale(Graphics g, int startx, int endx, int ypos)
++ void drawVerticalScale(Graphics g, int startx, int endx, int ypos,
++ boolean left)
{
-- FontMetrics fm = getFontMetrics(av.getFont());
ypos += charHeight;
if (av.hasHiddenColumns())
{
-- startx = av.getAlignment().getHiddenColumns()
-- .adjustForHiddenColumns(startx);
-- endx = av.getAlignment().getHiddenColumns()
-- .adjustForHiddenColumns(endx);
-- }
--
-- int maxwidth = av.getAlignment().getWidth();
-- if (av.hasHiddenColumns())
-- {
-- maxwidth = av.getAlignment().getHiddenColumns()
-- .findColumnPosition(maxwidth) - 1;
++ HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns();
++ startx = hiddenColumns.adjustForHiddenColumns(startx);
++ endx = hiddenColumns.adjustForHiddenColumns(endx);
}
++ FontMetrics fm = getFontMetrics(av.getFont());
for (int i = 0; i < av.getAlignment().getHeight(); i++)
{
SequenceI seq = av.getAlignment().getSequenceAt(i);
-- int index = startx;
-- int value = -1;
-- while (index < endx)
++ /*
++ * find sequence position of first non-gapped position -
++ * to the right if scale left, to the left if scale right
++ */
++ int index = left ? startx : endx;
++ int value = -1;
++ while (index >= startx && index <= endx)
{
-- if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
++ if (!Comparison.isGap(seq.getCharAt(index)))
++ {
++ value = seq.findPosition(index);
++ break;
++ }
++ if (left)
{
index++;
--
-- continue;
}
--
-- value = av.getAlignment().getSequenceAt(i).findPosition(index);
--
-- break;
-- }
--
-- if (value != -1)
-- {
-- int x = labelWidthWest - fm.stringWidth(String.valueOf(value))
-- - charWidth / 2;
-- g.drawString(value + "", x, (ypos + (i * charHeight))
-- - (charHeight / 5));
-- }
-- }
-- }
--
-- /**
-- * DOCUMENT ME!
-- *
-- * @param g
-- * DOCUMENT ME!
-- * @param startx
-- * DOCUMENT ME!
-- * @param endx
-- * DOCUMENT ME!
-- * @param ypos
-- * DOCUMENT ME!
-- */
-- void drawEastScale(Graphics g, int startx, int endx, int ypos)
-- {
-- ypos += charHeight;
--
-- if (av.hasHiddenColumns())
-- {
-- endx = av.getAlignment().getHiddenColumns()
-- .adjustForHiddenColumns(endx);
-- }
--
-- SequenceI seq;
-- // EAST SCALE
-- for (int i = 0; i < av.getAlignment().getHeight(); i++)
-- {
-- seq = av.getAlignment().getSequenceAt(i);
-- int index = endx;
-- int value = -1;
--
-- while (index > startx)
-- {
-- if (jalview.util.Comparison.isGap(seq.getCharAt(index)))
++ else
{
index--;
--
-- continue;
}
--
-- value = seq.findPosition(index);
--
-- break;
}
if (value != -1)
{
-- g.drawString(String.valueOf(value), 0, (ypos + (i * charHeight))
++ /*
++ * draw scale value, justified, with half a character width
++ * separation from the sequence data
++ */
++ int justify = fm.stringWidth(String.valueOf(value)) + charWidth;
++ int xpos = left ? labelWidthWest - justify + charWidth / 2
++ : getWidth() - justify - charWidth / 2;
++
++ g.drawString(String.valueOf(value), xpos, (ypos + (i * charHeight))
- (charHeight / 5));
}
}
}
-- boolean fastpainting = false;
--
/**
* need to make this thread safe move alignment rendering in response to
* slider adjustment
int canvasHeight, int startRes)
{
updateViewport();
-- AlignmentI al = av.getAlignment();
--
int labelWidth = 0;
if (av.getScaleRightWrapped() || av.getScaleLeftWrapped())
{
}
int cWidth = (canvasWidth - labelWidthEast - labelWidthWest) / charWidth;
-- int cHeight = av.getAlignment().getHeight() * charHeight;
av.setWrappedWidth(cWidth);
av.getRanges().setViewportStartAndWidth(startRes, cWidth);
-- int endx;
int ypos = hgap;
int maxwidth = av.getAlignment().getWidth();
}
int annotationHeight = getAnnotationHeight();
++ int sequencesHeight = av.getAlignment().getHeight() * charHeight;
while ((ypos <= canvasHeight) && (startRes < maxwidth))
{
-- endx = startRes + cWidth - 1;
++ drawWrappedWidth(g, startRes, canvasHeight, cWidth, maxwidth, ypos);
-- if (endx > maxwidth)
-- {
-- endx = maxwidth;
-- }
++ ypos += sequencesHeight + annotationHeight + hgap;
-- g.setFont(av.getFont());
-- g.setColor(Color.black);
++ startRes += cWidth;
++ }
++ }
-- if (av.getScaleLeftWrapped())
-- {
-- drawWestScale(g, startRes, endx, ypos);
-- }
++ /**
++ * @param g
++ * @param startRes
++ * @param canvasHeight
++ * @param canvasWidth
++ * @param maxWidth
++ * @param ypos
++ */
++ protected void drawWrappedWidth(Graphics g, int startRes,
++ int canvasHeight, int canvasWidth, int maxWidth, int ypos)
++ {
++ int endx;
++ endx = startRes + canvasWidth - 1;
-- if (av.getScaleRightWrapped())
-- {
-- g.translate(canvasWidth - labelWidthEast, 0);
-- drawEastScale(g, startRes, endx, ypos);
-- g.translate(-(canvasWidth - labelWidthEast), 0);
-- }
++ if (endx > maxWidth)
++ {
++ endx = maxWidth;
++ }
-- g.translate(labelWidthWest, 0);
++ g.setFont(av.getFont());
++ g.setColor(Color.black);
-- if (av.getScaleAboveWrapped())
-- {
-- drawNorthScale(g, startRes, endx, ypos);
-- }
++ if (av.getScaleLeftWrapped())
++ {
++ drawVerticalScale(g, startRes, endx, ypos, true);
++ }
-- if (av.hasHiddenColumns() && av.getShowHiddenMarkers())
-- {
-- g.setColor(Color.blue);
-- int res;
-- HiddenColumns hidden = av.getAlignment().getHiddenColumns();
-- List<Integer> positions = hidden.findHiddenRegionPositions();
-- for (int pos : positions)
-- {
-- res = pos - startRes;
++ if (av.getScaleRightWrapped())
++ {
++ drawVerticalScale(g, startRes, endx, ypos, false);
++ }
-- if (res < 0 || res > endx - startRes)
-- {
-- continue;
-- }
++ g.translate(labelWidthWest, 0);
-- gg.fillPolygon(
-- new int[] { res * charWidth - charHeight / 4,
-- res * charWidth + charHeight / 4, res * charWidth },
-- new int[] { ypos - (charHeight / 2),
-- ypos - (charHeight / 2), ypos - (charHeight / 2) + 8 },
-- 3);
++ if (av.getScaleAboveWrapped())
++ {
++ drawNorthScale(g, startRes, endx, ypos);
++ }
++ if (av.hasHiddenColumns() && av.getShowHiddenMarkers())
++ {
++ g.setColor(Color.blue);
++ HiddenColumns hidden = av.getAlignment().getHiddenColumns();
++ List<Integer> positions = hidden.findHiddenRegionPositions();
++ for (int pos : positions)
++ {
++ int res = pos - startRes;
++
++ if (res < 0 || res > endx - startRes)
++ {
++ continue;
}
-- }
-- // When printing we have an extra clipped region,
-- // the Printable page which we need to account for here
-- Shape clip = g.getClip();
++ gg.fillPolygon(new int[] { res * charWidth - charHeight / 4,
++ res * charWidth + charHeight / 4, res * charWidth }, new int[] {
++ ypos - (charHeight / 2), ypos - (charHeight / 2),
++ ypos - (charHeight / 2) + 8 }, 3);
-- if (clip == null)
-- {
-- g.setClip(0, 0, cWidth * charWidth, canvasHeight);
-- }
-- else
-- {
-- g.setClip(0, (int) clip.getBounds().getY(), cWidth * charWidth,
-- (int) clip.getBounds().getHeight());
}
++ }
-- drawPanel(g, startRes, endx, 0, al.getHeight() - 1, ypos);
++ // When printing we have an extra clipped region,
++ // the Printable page which we need to account for here
++ Shape clip = g.getClip();
-- if (av.isShowAnnotation())
-- {
-- g.translate(0, cHeight + ypos + 3);
-- if (annotations == null)
-- {
-- annotations = new AnnotationPanel(av);
-- }
++ if (clip == null)
++ {
++ g.setClip(0, 0, canvasWidth * charWidth, canvasHeight);
++ }
++ else
++ {
++ g.setClip(0, (int) clip.getBounds().getY(), canvasWidth * charWidth,
++ (int) clip.getBounds().getHeight());
++ }
-- annotations.renderer.drawComponent(annotations, av, g, -1,
-- startRes, endx + 1);
-- g.translate(0, -cHeight - ypos - 3);
-- }
-- g.setClip(clip);
-- g.translate(-labelWidthWest, 0);
++ drawPanel(g, startRes, endx, 0, av.getAlignment().getHeight() - 1, ypos);
-- ypos += cHeight + annotationHeight + hgap;
++ int cHeight = av.getAlignment().getHeight() * charHeight;
-- startRes += cWidth;
++ if (av.isShowAnnotation())
++ {
++ g.translate(0, cHeight + ypos + 3);
++ if (annotations == null)
++ {
++ annotations = new AnnotationPanel(av);
++ }
++
++ annotations.renderer.drawComponent(annotations, av, g, -1, startRes,
++ endx + 1);
++ g.translate(0, -cHeight - ypos - 3);
}
++ g.setClip(clip);
++ g.translate(-labelWidthWest, 0);
}
AnnotationPanel annotations;
{
String eventName = evt.getPropertyName();
-- if (av.getWrapAlignment())
-- {
-- if (eventName.equals(ViewportRanges.STARTRES))
-- {
-- repaint();
-- }
-- }
-- else
++ if (true/*!av.getWrapAlignment()*/)
{
int scrollX = 0;
if (eventName.equals(ViewportRanges.STARTRES))
if (eventName.equals(ViewportRanges.STARTRES))
{
// scroll - startres and endres both change
-- fastPaint(scrollX, 0);
++ if (av.getWrapAlignment())
++ {
++ fastPaintWrapped(scrollX);
++ }
++ else
++ {
++ fastPaint(scrollX, 0);
++ }
}
else if (eventName.equals(ViewportRanges.STARTSEQ))
{
}
/**
++ * Does a minimal update of the image for a scroll movement. This method
++ * handles scroll movements of up to one width of the wrapped alignment (one
++ * click in the vertical scrollbar). Larger movements (for example after a
++ * scroll to highlight a mapped position) trigger a full redraw instead.
++ *
++ * @param scrollX
++ * number of positions scrolled (right if positive, left if negative)
++ */
++ protected void fastPaintWrapped(int scrollX)
++ {
++ if (Math.abs(scrollX) > 0 /*av.getRanges().getViewportWidth()*/)
++ {
++ /*
++ * shift of more than one view width is too much
++ * to handle in this method
++ */
++ fastPaint = false;
++ repaint();
++ return;
++ }
++
++ fastPaint = true;
++ shiftWrappedAlignment(-scrollX);
++
++ // add new columns (scale above, sequence, annotation)
++ // at top left if scrollX < 0 or bottom right if scrollX > 0
++
++ repaint();
++ }
++
++ /**
++ * Shifts the visible alignment by the specified number of columns - left if
++ * negative, right if positive. Includes scale above, left or right and
++ * annotations (if shown). Does not draw newly visible columns.
++ *
++ * @param positions
++ */
++ protected void shiftWrappedAlignment(int positions)
++ {
++ if (positions == 0)
++ {
++ return;
++ }
++
++ int repeatHeight = getRepeatHeightWrapped();
++ ViewportRanges ranges = av.getRanges();
++ int widthToCopy = (ranges.getViewportWidth() - Math.abs(positions))
++ * charWidth;
++ int visibleWidths = getHeight() / repeatHeight;
++ if (getHeight() % repeatHeight > 0)
++ {
++ visibleWidths++;
++ }
++ int viewportWidth = ranges.getViewportWidth();
++
++ if (positions > 0)
++ {
++ /*
++ * shift right (after scroll left)
++ * for each wrapped width (starting with the last), copy (width-positions)
++ * columns from the left margin to the right margin, and copy positions
++ * columns from the right margin of the row above (if any) to the
++ * left margin of the current row
++ */
++ int xpos = ranges.getStartRes() + (visibleWidths - 1) * viewportWidth;
++
++ /*
++ * get y-offset of last wrapped width
++ */
++ int y = getHeight() / repeatHeight * repeatHeight;
++ int copyFromLeftStart = labelWidthWest;
++ int copyFromRightStart = copyFromLeftStart + widthToCopy;
++
++ while (y >= 0)
++ {
++ // todo limit repeatHeight for a last part height width
++ gg.copyArea(copyFromLeftStart, y, widthToCopy, repeatHeight,
++ positions * charWidth, 0);
++ if (y > 0)
++ {
++ gg.copyArea(copyFromRightStart, y - repeatHeight, positions
++ * charWidth, repeatHeight, -widthToCopy, repeatHeight);
++ }
++
++ if (av.getScaleLeftWrapped())
++ {
++ // drawVerticalScale(gg, xpos, xpos + viewportWidth, y, true);
++ }
++ if (av.getScaleRightWrapped())
++ {
++ // drawVerticalScale(gg, xpos, xpos + viewportWidth, y, false);
++ }
++
++ y -= repeatHeight;
++ xpos -= viewportWidth;
++ }
++ }
++ else
++ {
++ /*
++ * shift left (after scroll right)
++ * for each wrapped width (starting with the first), copy (width-positions)
++ * columns from the right margin to the left margin, and copy positions
++ * columns from the left margin of the row below (if any) to the
++ * right margin of the current row
++ */
++ int xpos = ranges.getStartRes();
++ int y = 0;
++ int copyFromRightStart = labelWidthWest - positions * charWidth;
++
++ while (y < getHeight())
++ {
++ // todo limit repeatHeight for a last part height width
++ gg.copyArea(copyFromRightStart, y, widthToCopy, repeatHeight,
++ positions * charWidth, 0);
++ if (y + repeatHeight < getHeight())
++ {
++ gg.copyArea(labelWidthWest, y + repeatHeight, -positions
++ * charWidth, repeatHeight, widthToCopy, -repeatHeight);
++ }
++
++ if (av.getScaleLeftWrapped())
++ {
++ // drawVerticalScale(gg, xpos, xpos + viewportWidth, y, true);
++ }
++ if (av.getScaleRightWrapped())
++ {
++ // drawVerticalScale(gg, xpos, xpos + viewportWidth, y, false);
++ }
++
++ y += repeatHeight;
++ xpos += ranges.getViewportWidth();
++ }
++ }
++ }
++
++ /**
* 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