From: gmungoc Date: Fri, 28 Jul 2017 13:12:39 +0000 (+0200) Subject: JAL-2609 first try X-Git-Tag: Release_2_10_3b1~91^2~6^2~31 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=15e102bc28463efa98d7d68e3a93f4f09c62248f;p=jalview.git JAL-2609 first try --- 15e102bc28463efa98d7d68e3a93f4f09c62248f diff --cc src/jalview/gui/SeqCanvas.java index 0e31246,0e31246..3b0d717 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@@ -27,6 -27,6 +27,7 @@@ import jalview.datamodel.SequenceGroup 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; @@@ -70,6 -70,6 +71,8 @@@ public class SeqCanvas extends JCompone boolean fastPaint = false; ++ boolean fastpainting = false; ++ int labelWidthWest; int labelWidthEast; @@@ -154,122 -154,122 +157,74 @@@ } /** -- * 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 @@@ -489,8 -489,8 +444,6 @@@ int canvasHeight, int startRes) { updateViewport(); -- AlignmentI al = av.getAlignment(); -- int labelWidth = 0; if (av.getScaleRightWrapped() || av.getScaleLeftWrapped()) { @@@ -508,13 -508,13 +461,11 @@@ } 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(); @@@ -525,98 -525,98 +476,111 @@@ } 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 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 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; @@@ -1166,14 -1166,14 +1130,7 @@@ { 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)) @@@ -1201,7 -1201,7 +1158,14 @@@ 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)) { @@@ -1212,6 -1212,6 +1176,143 @@@ } /** ++ * 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 results argument. This allows diff --cc src/jalview/gui/SeqPanel.java index e12c397,e12c397..eedad59 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@@ -215,7 -215,7 +215,7 @@@ public class SeqPanel extends JPanel im + hgap + seqCanvas.getAnnotationHeight(); int y = evt.getY(); -- y -= hgap; ++ y = Math.max(0, y - hgap); x = Math.max(0, x - seqCanvas.labelWidthWest); int cwidth = seqCanvas.getWrappedCanvasWidth(this.getWidth()); @@@ -228,8 -228,8 +228,8 @@@ wrappedBlock += startRes / cwidth; // allow for wrapped view scrolled right (possible from Overview) int startOffset = startRes % cwidth; -- res = wrappedBlock * cwidth -- + Math.min(cwidth - 1, startOffset + x / av.getCharWidth()); ++ res = wrappedBlock * cwidth + startOffset ++ + +Math.min(cwidth - 1, x / av.getCharWidth()); } else {