From 682503a8ef93a72d63431a2818bd550623cd2918 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Mon, 3 Jul 2017 15:25:48 +0100 Subject: [PATCH] JAL-147 ViewportRanges calculate wrapped vertical scroll position --- src/jalview/appletgui/AlignmentPanel.java | 74 +++----- src/jalview/gui/AlignmentPanel.java | 239 ++++++++++++------------ src/jalview/viewmodel/ViewportRanges.java | 31 +++ test/jalview/viewmodel/ViewportRangesTest.java | 33 ++++ 4 files changed, 212 insertions(+), 165 deletions(-) diff --git a/src/jalview/appletgui/AlignmentPanel.java b/src/jalview/appletgui/AlignmentPanel.java index 6826c4c..edf6ad4 100644 --- a/src/jalview/appletgui/AlignmentPanel.java +++ b/src/jalview/appletgui/AlignmentPanel.java @@ -802,46 +802,45 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, sendViewPosition(); } - private void adjustVertical(int offy) + private void adjustVertical(int newY) { - int oldX = vpRanges.getStartRes(); - int oldwidth = vpRanges.getViewportWidth(); - int oldY = vpRanges.getStartSeq(); - int oldheight = vpRanges.getViewportHeight(); - if (av.getWrapAlignment()) { - int rowSize = seqPanel.seqCanvas - .getWrappedCanvasWidth(seqPanel.seqCanvas.getWidth()); - - // if we're scrolling to the position we're already at, stop - // this prevents infinite recursion of events when the scroll/viewport - // ranges values are the same - int newX = offy * rowSize; - newX += oldX % rowSize; // horizontal scroll offset if any - if ((newX == oldX) && (oldwidth == rowSize)) + /* + * if we're scrolling to the position we're already at, stop + * this prevents infinite recursion of events when the scroll/viewport + * ranges values are the same + */ + int oldX = vpRanges.getStartRes(); + int oldY = vpRanges.getWrappedScrollPosition(oldX); + if (oldY == newY) { return; } - else if (offy > -1) + else if (newY > -1) { - // limit page up/down to one width's worth of positions - newX = newX > oldX ? oldX + rowSize : oldX - rowSize; + /* + * limit page up/down to one width's worth of positions + */ + int rowSize = vpRanges.getViewportWidth(); + int newX = newY > oldY ? oldX + rowSize : oldX - rowSize; vpRanges.setViewportStartAndWidth(newX, rowSize); } } else { int height = seqPanel.seqCanvas.getHeight() / av.getCharHeight(); + int oldY = vpRanges.getStartSeq(); + int oldheight = vpRanges.getViewportHeight(); // if we're scrolling to the position we're already at, stop // this prevents infinite recursion of events when the scroll/viewport // ranges values are the same - if ((offy == oldY) && (height == oldheight)) + if ((newY == oldY) && (height == oldheight)) { return; } - vpRanges.setViewportStartAndHeight(offy, height); + vpRanges.setViewportStartAndHeight(newY, height); } if (av.getWrapAlignment() || !fastPaint) { @@ -986,35 +985,20 @@ public class AlignmentPanel extends Panel implements AdjustmentListener, } - /* + /** * Set vertical scroll bar parameters for wrapped panel - * @param res - * the residue to scroll to + * + * @param topLeftColumn + * the column position at top left (0..) */ - private void setScrollingForWrappedPanel(int res) + private void setScrollingForWrappedPanel(int topLeftColumn) { - // get the width of the alignment in residues - int maxwidth = av.getAlignment().getWidth(); - if (av.hasHiddenColumns()) - { - maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; - } + int scrollPosition = vpRanges.getWrappedScrollPosition(topLeftColumn); + int maxScroll = vpRanges.getWrappedScrollPosition(vpRanges + .getVisibleAlignmentWidth() - 1); - // get the width of the canvas in residues - int canvasWidth = seqPanel.seqCanvas - .getWrappedCanvasWidth(seqPanel.seqCanvas.getSize().width); - if (canvasWidth > 0) - { - // position we want to scroll to is number of canvasWidth's to get there - int current = res / canvasWidth; - - // max scroll position: add one because extent is 1 and scrollbar value - // can only be set to at most max - extent - int max = maxwidth / canvasWidth + 1; - vscroll.setUnitIncrement(1); - vscroll.setValues(current, 1, 0, max); - } + vscroll.setUnitIncrement(1); + vscroll.setValues(scrollPosition, 1, 0, maxScroll); } protected Panel sequenceHolderPanel = new Panel(); diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 437e678..9d21a6c 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -629,21 +629,24 @@ public class AlignmentPanel extends GAlignmentPanel implements annotationSpaceFillerHolder.setVisible(true); } - if (wrap) - { - int widthInRes = getSeqPanel().seqCanvas - .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - vpRanges.setViewportWidth(widthInRes); - } - else - { - int widthInRes = (getSeqPanel().seqCanvas.getWidth() / av - .getCharWidth()) - 1; - int heightInSeq = (getSeqPanel().seqCanvas.getHeight() / av - .getCharHeight()) - 1; + int canvasWidth = getSeqPanel().seqCanvas.getWidth(); + if (canvasWidth > 0) + { // may not yet be laid out + if (wrap) + { + int widthInRes = getSeqPanel().seqCanvas + .getWrappedCanvasWidth(canvasWidth); + vpRanges.setViewportWidth(widthInRes); + } + else + { + int widthInRes = (canvasWidth / av.getCharWidth()) - 1; + int heightInSeq = (getSeqPanel().seqCanvas.getHeight() / av + .getCharHeight()) - 1; - vpRanges.setViewportWidth(widthInRes); - vpRanges.setViewportHeight(heightInSeq); + vpRanges.setViewportWidth(widthInRes); + vpRanges.setViewportHeight(heightInSeq); + } } idSpaceFillerPanel1.setVisible(!wrap); @@ -735,101 +738,111 @@ public class AlignmentPanel extends GAlignmentPanel implements @Override public void adjustmentValueChanged(AdjustmentEvent evt) { - int oldX = vpRanges.getStartRes(); - int oldwidth = vpRanges.getViewportWidth(); - int oldY = vpRanges.getStartSeq(); - int oldheight = vpRanges.getViewportHeight(); - if (av.getWrapAlignment()) { - if (evt.getSource() == hscroll) - { - return; // no horizontal scroll when wrapped - } - else if (evt.getSource() == vscroll) + adjustScrollingWrapped(evt); + return; + } + + if (evt.getSource() == hscroll) + { + int oldX = vpRanges.getStartRes(); + int oldwidth = vpRanges.getViewportWidth(); + int x = hscroll.getValue(); + int width = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); + + // if we're scrolling to the position we're already at, stop + // this prevents infinite recursion of events when the scroll/viewport + // ranges values are the same + if ((x == oldX) && (width == oldwidth)) { - int offy = vscroll.getValue(); - int rowSize = getSeqPanel().seqCanvas - .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - - // if we're scrolling to the position we're already at, stop - // this prevents infinite recursion of events when the scroll/viewport - // ranges values are the same - int newX = offy * rowSize; - newX += oldX % rowSize; // horizontal scroll offset if any - if ((newX == oldX) && (oldwidth == rowSize)) - { - return; - } - else if (offy > -1) - { - // limit page up/down to one width's worth of positions - newX = newX > oldX ? oldX + rowSize : oldX - rowSize; - vpRanges.setViewportStartAndWidth(newX, rowSize); - } + return; } - else + vpRanges.setViewportStartAndWidth(x, width); + } + else if (evt.getSource() == vscroll) + { + int oldY = vpRanges.getStartSeq(); + int oldheight = vpRanges.getViewportHeight(); + int y = vscroll.getValue(); + int height = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight(); + + // if we're scrolling to the position we're already at, stop + // this prevents infinite recursion of events when the scroll/viewport + // ranges values are the same + if ((y == oldY) && (height == oldheight)) { - // This is only called if file loaded is a jar file that - // was wrapped when saved and user has wrap alignment true - // as preference setting - SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() - { - // When updating scrolling to use ViewportChange events, this code - // could not be validated and it is not clear if it is now being - // called. Log warning here in case it is called and unforeseen - // problems occur - Cache.log - .warn("Unexpected path through code: Wrapped jar file opened with wrap alignment set in preferences"); - - // scroll to start of panel - vpRanges.setStartRes(0); - vpRanges.setStartSeq(0); - } - }); + return; } + vpRanges.setViewportStartAndHeight(y, height); + } + if (!fastPaint) + { repaint(); } - else + } + + /** + * Responds to a scroll change by setting the start position of the viewport. + * Does + * + * @param evt + */ + protected void adjustScrollingWrapped(AdjustmentEvent evt) + { + if (evt.getSource() == hscroll) { - // horizontal scroll - if (evt.getSource() == hscroll) - { - int x = hscroll.getValue(); - int width = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); + return; // no horizontal scroll when wrapped + } + if (evt.getSource() == vscroll) + { + int newY = vscroll.getValue(); - // if we're scrolling to the position we're already at, stop - // this prevents infinite recursion of events when the scroll/viewport - // ranges values are the same - if ((x == oldX) && (width == oldwidth)) - { - return; - } - vpRanges.setViewportStartAndWidth(x, width); - } - else if (evt.getSource() == vscroll) + /* + * if we're scrolling to the position we're already at, stop + * this prevents infinite recursion of events when the scroll/viewport + * ranges values are the same + */ + int oldX = vpRanges.getStartRes(); + int oldY = vpRanges.getWrappedScrollPosition(oldX); + if (oldY == newY) { - int y = vscroll.getValue(); - int height = getSeqPanel().seqCanvas.getHeight() - / av.getCharHeight(); - - // if we're scrolling to the position we're already at, stop - // this prevents infinite recursion of events when the scroll/viewport - // ranges values are the same - if ((y == oldY) && (height == oldheight)) - { - return; - } - vpRanges.setViewportStartAndHeight(y, height); + return; } - if (!fastPaint) + else if (newY > -1) { - repaint(); + /* + * limit page up/down to one width's worth of positions + */ + int rowSize = vpRanges.getViewportWidth(); + int newX = newY > oldY ? oldX + rowSize : oldX - rowSize; + vpRanges.setViewportStartAndWidth(newX, rowSize); } } + else + { + // This is only called if file loaded is a jar file that + // was wrapped when saved and user has wrap alignment true + // as preference setting + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + // When updating scrolling to use ViewportChange events, this code + // could not be validated and it is not clear if it is now being + // called. Log warning here in case it is called and unforeseen + // problems occur + Cache.log + .warn("Unexpected path through code: Wrapped jar file opened with wrap alignment set in preferences"); + + // scroll to start of panel + vpRanges.setStartRes(0); + vpRanges.setStartSeq(0); + } + }); + } + repaint(); } /** @@ -879,35 +892,21 @@ public class AlignmentPanel extends GAlignmentPanel implements setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq()); } - /* - * Set vertical scroll bar parameters for wrapped panel - * @param res - * the residue to scroll to + /** + * Set vertical scroll bar position, and number of increments, for wrapped + * panel + * + * @param topLeftColumn + * the column position at top left (0..) */ - private void setScrollingForWrappedPanel(int res) + private void setScrollingForWrappedPanel(int topLeftColumn) { - // get the width of the alignment in residues - int maxwidth = av.getAlignment().getWidth(); - if (av.hasHiddenColumns()) - { - maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; - } + int scrollPosition = vpRanges.getWrappedScrollPosition(topLeftColumn); + int maxScroll = vpRanges.getWrappedScrollPosition(vpRanges + .getVisibleAlignmentWidth() - 1); - // get the width of the canvas in residues - int canvasWidth = getSeqPanel().seqCanvas - .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - if (canvasWidth > 0) - { - // position we want to scroll to is number of canvasWidth's to get there - int current = res / canvasWidth; - - // max scroll position: add one because extent is 1 and scrollbar value - // can only be set to at most max - extent - int max = maxwidth / canvasWidth + 1; - vscroll.setUnitIncrement(1); - vscroll.setValues(current, 1, 0, max); - } + vscroll.setUnitIncrement(1); + vscroll.setValues(scrollPosition, 1, 0, maxScroll); } /** diff --git a/src/jalview/viewmodel/ViewportRanges.java b/src/jalview/viewmodel/ViewportRanges.java index f290ae7..36e598f 100644 --- a/src/jalview/viewmodel/ViewportRanges.java +++ b/src/jalview/viewmodel/ViewportRanges.java @@ -577,4 +577,35 @@ public class ViewportRanges extends ViewportProperties { wrappedMode = wrapped; } + + /** + * Answers the vertical scroll position (0..) to set, given the visible column + * that is at top left. Note that if called with the total visible width of + * the alignment, this gives the maximum cursor scroll value. + * + *
+   * Example:
+   *    viewport width 40 columns (0-39, 40-79, 80-119...)
+   *    column 0 returns scroll position 0
+   *    columns 0-40 return scroll position 1
+   *    columns 41-80 return scroll position 2
+   *    etc
+   * 
+ * + * @param topLeftColumn + * (0..) + * @return + */ + public int getWrappedScrollPosition(final int topLeftColumn) + { + int w = getViewportWidth(); + + /* + * visible whole widths + */ + int scroll = topLeftColumn / w; + scroll += topLeftColumn % w > 0 ? 1 : 0; + + return scroll; + } } diff --git a/test/jalview/viewmodel/ViewportRangesTest.java b/test/jalview/viewmodel/ViewportRangesTest.java index 636f8dd..4c93d71 100644 --- a/test/jalview/viewmodel/ViewportRangesTest.java +++ b/test/jalview/viewmodel/ViewportRangesTest.java @@ -523,6 +523,39 @@ public class ViewportRangesTest { assertTrue(l.verify(1, Arrays.asList("startres"))); l.reset(); } + + @Test(groups = { "Functional" }) + public void testGetWrappedScrollPosition() + { + AlignmentI al2 = gen.generate(157, 15, 1, 5, 5); + ViewportRanges vr = new ViewportRanges(al2); + vr.setStartEndRes(0, 39); + int width = vr.getViewportWidth(); // 40 + + /* + * scroll is 0 at column 0 (only) + */ + assertEquals(vr.getWrappedScrollPosition(0), 0); + + /* + * scroll is 1 at columns 1-40 + */ + int i = 1; + int j = width; + for (; i <= j; i++) + { + assertEquals(1, vr.getWrappedScrollPosition(i)); + } + + /* + * scroll is 2 at columns 41-80, etc + */ + j += width; + for (; i <= j; i++) + { + assertEquals(2, vr.getWrappedScrollPosition(i), "For " + i); + } + } } // mock listener for property change events -- 1.7.10.2