Skip to content

Commit

Permalink
Spacers affect Escalator's scrollbars (#16644)
Browse files Browse the repository at this point in the history
Change-Id: I73a7a6db4d25c09d4a3eb04c4aea18f06428d320
  • Loading branch information
Henrik Paul committed Feb 24, 2015
1 parent 2b88463 commit d270613
Showing 1 changed file with 115 additions and 30 deletions.
145 changes: 115 additions & 30 deletions client/src/com/vaadin/client/widgets/Escalator.java
Expand Up @@ -1144,6 +1144,9 @@ public void scrollToColumn(final int columnIndex,

public void scrollToRow(final int rowIndex,
final ScrollDestination destination, final double padding) {

getLogger().warning("[[spacers]] scrollToRow");

final double targetStartPx = body.getDefaultRowHeight() * rowIndex;
final double targetEndPx = targetStartPx
+ body.getDefaultRowHeight();
Expand Down Expand Up @@ -2317,7 +2320,7 @@ private void setTopRowLogicalIndex(int topRowLogicalIndex) {
this.topRowLogicalIndex = topRowLogicalIndex;
}

private int getTopRowLogicalIndex() {
public int getTopRowLogicalIndex() {
return topRowLogicalIndex;
}

Expand Down Expand Up @@ -2610,7 +2613,7 @@ protected void paintInsertRows(final int index, final int numberOfRows) {
*/

final double yDelta = numberOfRows * getDefaultRowHeight();
adjustScrollPosIgnoreEvents(yDelta);
moveViewportAndContent(yDelta);
updateTopRowLogicalIndex(numberOfRows);
}

Expand Down Expand Up @@ -2768,30 +2771,53 @@ private void moveAndUpdateEscalatorRows(final Range visualSourceRange,
}

/**
* Adjust the scroll position without having the scroll handler have any
* side-effects.
* Adjust the scroll position and move the contained rows.
* <p>
* <em>Note:</em> This method does not account for spacers.
* <p>
* <em>Note:</em> {@link Scroller#onScroll()} <em>will</em> be
* triggered, but it will not do anything, with the help of
* {@link Escalator#internalScrollEventCalls}.
* The difference between using this method and simply scrolling is that
* this method "takes the rows with it" and renders them appropriately.
* The viewport may be scrolled any arbitrary amount, and the rows are
* moved appropriately, but always snapped into a plausible place.
* <p>
* <dl>
* <dt>Example 1</dt>
* <dd>An Escalator with default row height 20px. Adjusting the scroll
* position with 7.5px will move the viewport 7.5px down, but leave the
* row where it is.</dd>
* <dt>Example 2</dt>
* <dd>An Escalator with default row height 20px. Adjusting the scroll
* position with 27.5px will move the viewport 27.5px down, and place
* the row at 20px.</dd>
* </dl>
*
* @param yDelta
* the delta of pixels to scrolls. A positive value moves the
* viewport downwards, while a negative value moves the
* viewport upwards
* the delta of pixels by which to move the viewport and
* content. A positive value moves everything downwards,
* while a negative value moves everything upwards
*/
public void adjustScrollPosIgnoreEvents(final double yDelta) {
public void moveViewportAndContent(final double yDelta) {

/*
* TODO: When adding and removing rows starts supporting spacers,
* this method should also take spacers into account. Remember to
* adjust the javadoc as well.
*/

if (yDelta == 0) {
return;
}

verticalScrollbar.setScrollPosByDelta(yDelta);
double newTop = tBodyScrollTop + yDelta;
final double rowTopPos = body.getRowTop(getLogicalRowIndex(newTop));

verticalScrollbar.setScrollPos(newTop);

final double rowTopPos = yDelta - (yDelta % getDefaultRowHeight());
for (final TableRowElement tr : visualRowOrder) {
setRowPosition(tr, 0, getRowTop(tr) + rowTopPos);
for (int i = 0; i < visualRowOrder.size(); i++) {
final TableRowElement tr = visualRowOrder.get(i);
setRowPosition(tr, 0, rowTopPos + getDefaultRowHeight() * i);
}
setBodyScrollPosition(tBodyScrollLeft, tBodyScrollTop + yDelta);
setBodyScrollPosition(tBodyScrollLeft, newTop);
}

/**
Expand Down Expand Up @@ -2915,7 +2941,7 @@ protected void paintRemoveRows(final int index, final int numberOfRows) {
* to do is to adjust the scroll position to account for the
* removed rows
*/
adjustScrollPosIgnoreEvents(-yDelta);
moveViewportAndContent(-yDelta);
} else if (removalScrollsToShowFirstLogicalRow) {
/*
* It seems like we've removed all rows from above, and also
Expand All @@ -2924,8 +2950,7 @@ protected void paintRemoveRows(final int index, final int numberOfRows) {
* current negative scrolltop, presto!), so that it isn't
* aligned funnily
*/
adjustScrollPosIgnoreEvents(-verticalScrollbar
.getScrollPos());
moveViewportAndContent(-verticalScrollbar.getScrollPos());
}
}

Expand Down Expand Up @@ -3730,13 +3755,6 @@ public void shiftRowPositions(int row, double diff) {
for (TableRowElement tr : getVisibleRowsAfter(row)) {
setRowPosition(tr, 0, getRowTop(tr) + diff);
}

if (row > getTopRowLogicalIndex()) {
// TODO
getLogger().warning(
"[[spacers]] scrollbar compensation not yet "
+ "implemented");
}
}

private List<TableRowElement> getVisibleRowsAfter(int logicalRow) {
Expand Down Expand Up @@ -4302,13 +4320,80 @@ public void setHeight(double height) {
assert height >= 0 : "Height must be more >= 0 (was " + height
+ ")";

double diff = height - Math.max(0, this.height);
final double heightDiff = height - Math.max(0, this.height);
final double oldHeight = this.height;

this.height = height;
root.getStyle().setHeight(height, Unit.PX);

shiftSpacerPositions(getRow(), diff);
body.shiftRowPositions(getRow(), diff);
body.verifyEscalatorCount();
// move the visible spacers getRow row onwards.
shiftSpacerPositions(getRow(), heightDiff);

/*
* If we're growing, we'll adjust the scroll size first, then
* adjust scrolling. If we're shrinking, we do it after the
* second if-clause.
*/
boolean spacerIsGrowing = heightDiff > 0;
if (spacerIsGrowing) {
verticalScrollbar.setScrollSize(verticalScrollbar
.getScrollSize() + heightDiff);
}

boolean viewportNeedsScrolling = getRow() < body
.getTopRowLogicalIndex();
if (viewportNeedsScrolling) {

/*
* We can't use adjustScrollPos here, probably because of a
* bookkeeping-related race condition.
*
* This particular situation is easier, however, since we
* know exactly how many pixels we need to move (heightDiff)
* and all elements below the spacer always need to move
* that pixel amount.
*/

for (TableRowElement row : body.visualRowOrder) {
body.setRowPosition(row, 0, body.getRowTop(row)
+ heightDiff);
}

double top = getTop();
double bottom = top + oldHeight;
double scrollTop = verticalScrollbar.getScrollPos();

boolean viewportTopIsAtMidSpacer = top < scrollTop
&& scrollTop < bottom;

final double moveDiff;
if (viewportTopIsAtMidSpacer && !spacerIsGrowing) {

/*
* If the scroll top is in the middle of the modified
* spacer, we want to scroll the viewport up as usual,
* but we don't want to scroll past the top of it.
*
* Math.max ensures this (remember: the result is going
* to be negative).
*/

moveDiff = Math.max(heightDiff, top - scrollTop);
} else {
moveDiff = heightDiff;
}
body.setBodyScrollPosition(tBodyScrollLeft, tBodyScrollTop
+ moveDiff);
verticalScrollbar.setScrollPosByDelta(moveDiff);

} else {
body.shiftRowPositions(getRow(), heightDiff);
}

if (!spacerIsGrowing) {
verticalScrollbar.setScrollSize(verticalScrollbar
.getScrollSize() + heightDiff);
}
}

@Override
Expand Down

0 comments on commit d270613

Please sign in to comment.