X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=inline;f=src%2Fjalview%2Fviewmodel%2FViewportRanges.java;h=6f817bb0cdd8c8a82a93a7b5c43da29686cfcc62;hb=ead40d75a04715c80c61e34e277bb995cb2bef90;hp=f14b10e411ba09c26797c29254eb666413a59533;hpb=f789d3fe25fd4785dcba27d5d39275959109eb5f;p=jalview.git diff --git a/src/jalview/viewmodel/ViewportRanges.java b/src/jalview/viewmodel/ViewportRanges.java index f14b10e..6f817bb 100644 --- a/src/jalview/viewmodel/ViewportRanges.java +++ b/src/jalview/viewmodel/ViewportRanges.java @@ -24,11 +24,10 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.HiddenColumns; /** - * Slightly less embryonic class which: Supplies and updates viewport properties - * relating to position such as: start and end residues and sequences; ideally - * will serve hidden columns/rows too. Intention also to support calculations - * for positioning, scrolling etc. such as finding the middle of the viewport, - * checking for scrolls off screen + * Supplies and updates viewport properties relating to position such as: start + * and end residues and sequences; ideally will serve hidden columns/rows too. + * Intention also to support calculations for positioning, scrolling etc. such + * as finding the middle of the viewport, checking for scrolls off screen */ public class ViewportRanges extends ViewportProperties { @@ -40,6 +39,12 @@ public class ViewportRanges extends ViewportProperties public static final String ENDSEQ = "endseq"; + public static final String STARTRESANDSEQ = "startresandseq"; + + public static final String MOVE_VIEWPORT = "move_viewport"; + + private boolean wrappedMode = false; + // start residue of viewport private int startRes; @@ -92,7 +97,7 @@ public class ViewportRanges extends ViewportProperties */ public int getVisibleAlignmentWidth() { - return al.getWidth() - al.getHiddenColumns().getSize(); + return al.getVisibleWidth(); } /** @@ -128,10 +133,40 @@ public class ViewportRanges extends ViewportProperties */ public void setStartEndRes(int start, int end) { + int[] oldvalues = updateStartEndRes(start, end); + int oldstartres = oldvalues[0]; + int oldendres = oldvalues[1]; + + changeSupport.firePropertyChange(STARTRES, oldstartres, startRes); + if (oldstartres == startRes) + { + // event won't be fired if start positions are same + // fire an event for the end positions in case they changed + changeSupport.firePropertyChange(ENDRES, oldendres, endRes); + } + } + + /** + * Update start and end residue values, adjusting for width constraints if + * necessary + * + * @param start + * start residue + * @param end + * end residue + * @return array containing old start and end residue values + */ + private int[] updateStartEndRes(int start, int end) + { int oldstartres = this.startRes; - if (start > getVisibleAlignmentWidth() - 1) + + /* + * if not wrapped, don't leave white space at the right margin + */ + int lastColumn = getVisibleAlignmentWidth() - 1; + if (!wrappedMode && (start > lastColumn)) { - startRes = Math.max(getVisibleAlignmentWidth() - 1, 0); + startRes = Math.max(lastColumn, 0); } else if (start < 0) { @@ -147,39 +182,15 @@ public class ViewportRanges extends ViewportProperties { endRes = 0; } - else if (end > getVisibleAlignmentWidth() - 1) + else if (!wrappedMode && (end > lastColumn)) { - endRes = Math.max(getVisibleAlignmentWidth() - 1, 0); + endRes = Math.max(lastColumn, 0); } else { endRes = end; } - - changeSupport.firePropertyChange(STARTRES, oldstartres, startRes); - if (oldstartres == startRes) - { - // event won't be fired if start positions are same - // fire an event for the end positions in case they changed - changeSupport.firePropertyChange(ENDRES, oldendres, endRes); - } - } - - /** - * Set last residue visible in the viewport. Fires a property change event. - * - * @param res - * residue position - */ - public void setEndRes(int res) - { - int startres = res; - int width = getViewportWidth(); - if (startres + width - 1 > getVisibleAlignmentWidth() - 1) - { - startres = getVisibleAlignmentWidth() - width; - } - setStartEndRes(startres - width + 1, startres); + return new int[] { oldstartres, oldendres }; } /** @@ -213,10 +224,36 @@ public class ViewportRanges extends ViewportProperties */ public void setStartEndSeq(int start, int end) { + int[] oldvalues = updateStartEndSeq(start, end); + int oldstartseq = oldvalues[0]; + int oldendseq = oldvalues[1]; + + changeSupport.firePropertyChange(STARTSEQ, oldstartseq, startSeq); + if (oldstartseq == startSeq) + { + // event won't be fired if start positions are the same + // fire in case the end positions changed + changeSupport.firePropertyChange(ENDSEQ, oldendseq, endSeq); + } + } + + /** + * Update start and end sequence values, adjusting for height constraints if + * necessary + * + * @param start + * start sequence + * @param end + * end sequence + * @return array containing old start and end sequence values + */ + private int[] updateStartEndSeq(int start, int end) + { int oldstartseq = this.startSeq; - if (start > getVisibleAlignmentHeight() - 1) + int visibleHeight = getVisibleAlignmentHeight(); + if (start > visibleHeight - 1) { - startSeq = Math.max(getVisibleAlignmentHeight() - 1, 0); + startSeq = Math.max(visibleHeight - 1, 0); } else if (start < 0) { @@ -228,9 +265,9 @@ public class ViewportRanges extends ViewportProperties } int oldendseq = this.endSeq; - if (end >= getVisibleAlignmentHeight()) + if (end >= visibleHeight) { - endSeq = Math.max(getVisibleAlignmentHeight() - 1, 0); + endSeq = Math.max(visibleHeight - 1, 0); } else if (end < 0) { @@ -240,14 +277,7 @@ public class ViewportRanges extends ViewportProperties { endSeq = end; } - - changeSupport.firePropertyChange(STARTSEQ, oldstartseq, startSeq); - if (oldstartseq == startSeq) - { - // event won't be fired if start positions are the same - // fire in case the end positions changed - changeSupport.firePropertyChange(ENDSEQ, oldendseq, endSeq); - } + return new int[] { oldstartseq, oldendseq }; } /** @@ -264,6 +294,34 @@ public class ViewportRanges extends ViewportProperties } /** + * Set start residue and start sequence together (fires single event). The + * event supplies a pair of old values and a pair of new values: [old start + * residue, old start sequence] and [new start residue, new start sequence] + * + * @param res + * the start residue + * @param seq + * the start sequence + */ + public void setStartResAndSeq(int res, int seq) + { + int width = getViewportWidth(); + int[] oldresvalues = updateStartEndRes(res, res + width - 1); + + int startseq = seq; + int height = getViewportHeight(); + if (startseq + height - 1 > getVisibleAlignmentHeight() - 1) + { + startseq = getVisibleAlignmentHeight() - height; + } + int[] oldseqvalues = updateStartEndSeq(startseq, startseq + height - 1); + + int[] old = new int[] { oldresvalues[0], oldseqvalues[0] }; + int[] newresseq = new int[] { startRes, startSeq }; + changeSupport.firePropertyChange(STARTRESANDSEQ, old, newresseq); + } + + /** * Get start residue of viewport */ public int getStartRes() @@ -338,12 +396,18 @@ public class ViewportRanges extends ViewportProperties { vpstart = 0; } - else if ((w <= getVisibleAlignmentWidth()) - && (vpstart + w - 1 > getVisibleAlignmentWidth() - 1)) - // viewport width is less than the full alignment and we are running off the - // RHS edge + + /* + * if not wrapped, don't leave white space at the right margin + */ + if (!wrappedMode) { - vpstart = getVisibleAlignmentWidth() - w; + if ((w <= getVisibleAlignmentWidth()) + && (vpstart + w - 1 > getVisibleAlignmentWidth() - 1)) + { + vpstart = getVisibleAlignmentWidth() - w; + } + } setStartEndRes(vpstart, vpstart + w - 1); } @@ -405,23 +469,39 @@ public class ViewportRanges extends ViewportProperties */ public boolean scrollUp(boolean up) { + /* + * if in unwrapped mode, scroll up or down one sequence row; + * if in wrapped mode, scroll by one visible width of columns + */ if (up) { - if (startSeq < 1) + if (wrappedMode) { - return false; + pageUp(); + } + else + { + if (startSeq < 1) + { + return false; + } + setStartSeq(startSeq - 1); } - - setStartSeq(startSeq - 1); } else { - if (endSeq >= getVisibleAlignmentHeight() - 1) + if (wrappedMode) { - return false; + pageDown(); + } + else + { + if (endSeq >= getVisibleAlignmentHeight() - 1) + { + return false; + } + setStartSeq(startSeq + 1); } - - setStartSeq(startSeq + 1); } return true; } @@ -464,18 +544,33 @@ public class ViewportRanges extends ViewportProperties * the startRes changed, else false. * * @param res - * residue position to scroll to + * residue position to scroll to NB visible position not absolute + * alignment position * @return */ public boolean scrollToWrappedVisible(int res) { - int oldStartRes = startRes; - int width = getViewportWidth(); - - if (res >= oldStartRes && res < oldStartRes + width) + int newStartRes = calcWrappedStartResidue(res); + if (newStartRes == startRes) { return false; } + setStartRes(newStartRes); + + return true; + } + + /** + * Calculate wrapped start residue from visible start residue + * + * @param res + * visible start residue + * @return left column of panel res will be located in + */ + private int calcWrappedStartResidue(int res) + { + int oldStartRes = startRes; + int width = getViewportWidth(); boolean up = res < oldStartRes; int widthsToScroll = Math.abs((res - oldStartRes) / width); @@ -491,19 +586,16 @@ public class ViewportRanges extends ViewportProperties { newStartRes = 0; } - - setStartRes(newStartRes); - - return true; + return newStartRes; } /** * Scroll so that (x,y) is visible. Fires a property change event. * * @param x - * x position in alignment + * x position in alignment (absolute position) * @param y - * y position in alignment + * y position in alignment (absolute position) */ public void scrollToVisible(int x, int y) { @@ -515,16 +607,16 @@ public class ViewportRanges extends ViewportProperties { scrollUp(false); } - + HiddenColumns hidden = al.getHiddenColumns(); - while (x < hidden.adjustForHiddenColumns(startRes)) + while (x < hidden.visibleToAbsoluteColumn(startRes)) { if (!scrollRight(false)) { break; } } - while (x > hidden.adjustForHiddenColumns(endRes)) + while (x > hidden.visibleToAbsoluteColumn(endRes)) { if (!scrollRight(true)) { @@ -532,20 +624,172 @@ public class ViewportRanges extends ViewportProperties } } } - + + /** + * Set the viewport location so that a position is visible + * + * @param x + * column to be visible: absolute position in alignment + * @param y + * row to be visible: absolute position in alignment + */ + public boolean setViewportLocation(int x, int y) + { + boolean changedLocation = false; + + // convert the x,y location to visible coordinates + int visX = al.getHiddenColumns().absoluteToVisibleColumn(x); + int visY = al.getHiddenSequences().findIndexWithoutHiddenSeqs(y); + + // if (vis_x,vis_y) is already visible don't do anything + if (startRes > visX || visX > endRes + || startSeq > visY && visY > endSeq) + { + int[] old = new int[] { startRes, startSeq }; + int[] newresseq; + if (wrappedMode) + { + int newstartres = calcWrappedStartResidue(visX); + setStartRes(newstartres); + newresseq = new int[] { startRes, startSeq }; + } + else + { + // set the viewport x location to contain vis_x + int newstartres = visX; + int width = getViewportWidth(); + if (newstartres + width - 1 > getVisibleAlignmentWidth() - 1) + { + newstartres = getVisibleAlignmentWidth() - width; + } + updateStartEndRes(newstartres, newstartres + width - 1); + + // set the viewport y location to contain vis_y + int newstartseq = visY; + int height = getViewportHeight(); + if (newstartseq + height - 1 > getVisibleAlignmentHeight() - 1) + { + newstartseq = getVisibleAlignmentHeight() - height; + } + updateStartEndSeq(newstartseq, newstartseq + height - 1); + + newresseq = new int[] { startRes, startSeq }; + } + changedLocation = true; + changeSupport.firePropertyChange(MOVE_VIEWPORT, old, newresseq); + } + return changedLocation; + } + /** * Adjust sequence position for page up. Fires a property change event. */ public void pageUp() { - setViewportStartAndHeight(2 * startSeq - endSeq, getViewportHeight()); + if (wrappedMode) + { + setStartRes(Math.max(0, getStartRes() - getViewportWidth())); + } + else + { + setViewportStartAndHeight(startSeq - (endSeq - startSeq), + getViewportHeight()); + } } - + /** * Adjust sequence position for page down. Fires a property change event. */ public void pageDown() { - setViewportStartAndHeight(endSeq, getViewportHeight()); + if (wrappedMode) + { + /* + * if height is more than width (i.e. not all sequences fit on screen), + * increase page down to height + */ + int newStart = getStartRes() + + Math.max(getViewportHeight(), getViewportWidth()); + + /* + * don't page down beyond end of alignment, or if not all + * sequences fit in the visible height + */ + if (newStart < getVisibleAlignmentWidth()) + { + setStartRes(newStart); + } + } + else + { + setViewportStartAndHeight(endSeq, getViewportHeight()); + } + } + + public void setWrappedMode(boolean wrapped) + { + wrappedMode = wrapped; + } + + public boolean isWrappedMode() + { + return wrappedMode; + } + + /** + * Answers the vertical scroll position (0..) to set, given the visible column + * that is at top left. + * + *
+ * Example: + * viewport width 40 columns (0-39, 40-79, 80-119...) + * column 0 returns scroll position 0 + * columns 1-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; + + /* + * add 1 for a part width if there is one + */ + scroll += topLeftColumn % w > 0 ? 1 : 0; + + return scroll; + } + + /** + * Answers the maximum wrapped vertical scroll value, given the column + * position (0..) to show at top left of the visible region. + * + * @param topLeftColumn + * @return + */ + public int getWrappedMaxScroll(int topLeftColumn) + { + int scrollPosition = getWrappedScrollPosition(topLeftColumn); + + /* + * how many more widths could be drawn after this one? + */ + int columnsRemaining = getVisibleAlignmentWidth() - topLeftColumn; + int width = getViewportWidth(); + int widthsRemaining = columnsRemaining / width + + (columnsRemaining % width > 0 ? 1 : 0) - 1; + int maxScroll = scrollPosition + widthsRemaining; + + return maxScroll; } }