grid: improved scroll support

This commit is contained in:
Vadim Lopatin 2014-06-09 11:30:16 +04:00
parent a283ebd307
commit 0103bb8a3d
1 changed files with 66 additions and 39 deletions

View File

@ -320,7 +320,7 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
/// update scrollbar positions /// update scrollbar positions
protected void updateScrollBars() { protected void updateScrollBars() {
calcScrollableAreaPos(_fullyVisibleCells, _fullyVisibleCellsRect, _fullScrollableArea, _visibleScrollableArea); calcScrollableAreaPos();
if (_hscrollbar) { if (_hscrollbar) {
_hscrollbar.setRange(0, _fullScrollableArea.width); _hscrollbar.setRange(0, _fullScrollableArea.width);
_hscrollbar.pageSize(_visibleScrollableArea.width); _hscrollbar.pageSize(_visibleScrollableArea.width);
@ -357,15 +357,25 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
return 0; return 0;
} }
/// move scroll position horizontally by dx, and vertically by dy /// move scroll position horizontally by dx, and vertically by dy; returns true if scrolled
void scrollBy(int dx, int dy) { bool scrollBy(int dx, int dy) {
scrollTo(_headerCols + _fixedCols + _scrollCol + dx, _headerRows + _fixedRows + _scrollRow + dy); return scrollTo(_headerCols + _fixedCols + _scrollCol + dx, _headerRows + _fixedRows + _scrollRow + dy);
} }
/// set scroll position to show specified cell as top left in scrollable area /// set scroll position to show specified cell as top left in scrollable area
void scrollTo(int col, int row) { bool scrollTo(int col, int row) {
int oldx = _scrollCol;
int oldy = _scrollRow;
int newScrollCol = col - _headerCols - _fixedCols; int newScrollCol = col - _headerCols - _fixedCols;
int newScrollRow = row - _headerRows - _fixedRows; int newScrollRow = row - _headerRows - _fixedRows;
if (newScrollCol > _maxScrollCol)
newScrollCol = _maxScrollCol;
if (newScrollCol < 0)
newScrollCol = 0;
if (newScrollRow > _maxScrollRow)
newScrollRow = _maxScrollRow;
if (newScrollRow < 0)
newScrollRow = 0;
//bool changed = false; //bool changed = false;
if (newScrollCol >= 0 && newScrollCol + _headerCols + _fixedCols < _cols) { if (newScrollCol >= 0 && newScrollCol + _headerCols + _fixedCols < _cols) {
if (_scrollCol != newScrollCol) { if (_scrollCol != newScrollCol) {
@ -381,6 +391,7 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
} }
//if (changed) //if (changed)
updateScrollBars(); updateScrollBars();
return oldx != _scrollCol || oldy != _scrollRow;
} }
/// handle scroll event /// handle scroll event
@ -458,7 +469,7 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
_col = col; _col = col;
_row = row; _row = row;
invalidate(); invalidate();
calcScrollableAreaPos(_fullyVisibleCells, _fullyVisibleCellsRect, _fullScrollableArea, _visibleScrollableArea); calcScrollableAreaPos();
if (makeVisible) if (makeVisible)
makeCellVisible(_col, _row); makeCellVisible(_col, _row);
return true; return true;
@ -497,37 +508,39 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
return super.onMouseEvent(event); return super.onMouseEvent(event);
} }
/// calculate scrollable area info /// calculate scrollable area info
protected void calcScrollableAreaPos(ref Rect fullyVisibleCells, ref Rect fullyVisibleCellsRect, ref Rect fullScrollableArea, ref Rect visibleScrollableArea) { protected void calcScrollableAreaPos() {
fullyVisibleCells.left = _headerCols + _fixedCols + _scrollCol; _maxScrollCol = _maxScrollRow = 0;
fullyVisibleCells.top = _headerRows + _fixedRows + _scrollRow; _fullyVisibleCells.left = _headerCols + _fixedCols + _scrollCol;
_fullyVisibleCells.top = _headerRows + _fixedRows + _scrollRow;
Rect rc; Rect rc;
int xx = 0; int xx = 0;
for (int i = 0; i < _cols && xx < _clientRect.width; i++) { for (int i = 0; i < _cols && xx < _clientRect.width; i++) {
if (i == fullyVisibleCells.left) { if (i == _fullyVisibleCells.left) {
fullyVisibleCellsRect.left = fullyVisibleCellsRect.right = xx; _fullyVisibleCellsRect.left = _fullyVisibleCellsRect.right = xx;
} }
int w = colWidth(i); int w = colWidth(i);
if (i >= fullyVisibleCells.left && xx + w <= _clientRect.width) { if (i >= _fullyVisibleCells.left && xx + w <= _clientRect.width) {
fullyVisibleCellsRect.right = xx + w; _fullyVisibleCellsRect.right = xx + w;
fullyVisibleCells.right = i; _fullyVisibleCells.right = i;
} }
xx += w; xx += w;
} }
int yy = 0; int yy = 0;
for (int i = 0; i < _rows && yy < _clientRect.height; i++) { for (int i = 0; i < _rows && yy < _clientRect.height; i++) {
if (i == fullyVisibleCells.top) if (i == _fullyVisibleCells.top)
fullyVisibleCellsRect.top = fullyVisibleCellsRect.bottom = yy; _fullyVisibleCellsRect.top = _fullyVisibleCellsRect.bottom = yy;
int w = rowHeight(i); int w = rowHeight(i);
if (i >= fullyVisibleCells.top && yy + w <= _clientRect.height) { if (i >= _fullyVisibleCells.top && yy + w <= _clientRect.height) {
fullyVisibleCellsRect.bottom = yy + w; _fullyVisibleCellsRect.bottom = yy + w;
fullyVisibleCells.bottom = i; _fullyVisibleCells.bottom = i;
} }
yy += w; yy += w;
} }
int maxVisibleScrollWidth = _clientRect.width - fullyVisibleCellsRect.left; int maxVisibleScrollWidth = _clientRect.width - _fullyVisibleCellsRect.left;
int maxVisibleScrollHeight = _clientRect.height - fullyVisibleCellsRect.top; int maxVisibleScrollHeight = _clientRect.height - _fullyVisibleCellsRect.top;
if (maxVisibleScrollWidth < 0) if (maxVisibleScrollWidth < 0)
maxVisibleScrollWidth = 0; maxVisibleScrollWidth = 0;
if (maxVisibleScrollHeight < 0) if (maxVisibleScrollHeight < 0)
@ -538,69 +551,73 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
xx = 0; xx = 0;
for (int i = 0; i < _cols; i++) { for (int i = 0; i < _cols; i++) {
if (i == _headerCols + _fixedCols) { if (i == _headerCols + _fixedCols) {
fullScrollableArea.left = xx; _fullScrollableArea.left = xx;
} }
if (i == fullyVisibleCells.left) { if (i == _fullyVisibleCells.left) {
visibleScrollableArea.left = xx; _visibleScrollableArea.left = xx;
} }
int w = _colWidths[i]; int w = _colWidths[i];
xx += w; xx += w;
if (i >= _headerCols + _fixedCols) { if (i >= _headerCols + _fixedCols) {
fullScrollableArea.right = xx; _fullScrollableArea.right = xx;
} }
if (i >= fullyVisibleCells.left) { if (i >= _fullyVisibleCells.left) {
visibleScrollableArea.right = xx; _visibleScrollableArea.right = xx;
} }
} }
xx = 0; xx = 0;
for (int i = _cols - 1; i >= _headerCols + _fixedCols; i--) { for (int i = _cols - 1; i >= _headerCols + _fixedCols; i--) {
int w = _colWidths[i]; int w = _colWidths[i];
if (xx + w > maxVisibleScrollWidth) { if (xx + w > maxVisibleScrollWidth) {
fullScrollableArea.right += maxVisibleScrollWidth - xx; _fullScrollableArea.right += maxVisibleScrollWidth - xx;
break; break;
} }
_maxScrollCol = i - _headerCols - _fixedCols;
xx += w; xx += w;
} }
yy = 0; yy = 0;
for (int i = 0; i < _rows; i++) { for (int i = 0; i < _rows; i++) {
if (i == _headerRows + _fixedRows) { if (i == _headerRows + _fixedRows) {
fullScrollableArea.top = yy; _fullScrollableArea.top = yy;
} }
if (i == fullyVisibleCells.top) { if (i == _fullyVisibleCells.top) {
visibleScrollableArea.top = yy; _visibleScrollableArea.top = yy;
} }
int w = _rowHeights[i]; int w = _rowHeights[i];
yy += w; yy += w;
if (i >= _headerRows + _fixedRows) { if (i >= _headerRows + _fixedRows) {
fullScrollableArea.bottom = yy; _fullScrollableArea.bottom = yy;
} }
if (i >= fullyVisibleCells.top) { if (i >= _fullyVisibleCells.top) {
visibleScrollableArea.bottom = yy; _visibleScrollableArea.bottom = yy;
} }
} }
yy = 0; yy = 0;
for (int i = _rows - 1; i >= _headerRows + _fixedRows; i--) { for (int i = _rows - 1; i >= _headerRows + _fixedRows; i--) {
int w = _rowHeights[i]; int w = _rowHeights[i];
if (yy + w > maxVisibleScrollHeight) { if (yy + w > maxVisibleScrollHeight) {
fullScrollableArea.bottom += maxVisibleScrollHeight - yy; _fullScrollableArea.bottom += maxVisibleScrollHeight - yy;
break; break;
} }
_maxScrollRow = i - _headerRows - _fixedRows;
yy += w; yy += w;
} }
// crop scroll area by client rect // crop scroll area by client rect
//if (visibleScrollableArea.width > maxVisibleScrollWidth) //if (visibleScrollableArea.width > maxVisibleScrollWidth)
visibleScrollableArea.right = visibleScrollableArea.left + maxVisibleScrollWidth; _visibleScrollableArea.right = _visibleScrollableArea.left + maxVisibleScrollWidth;
//if (visibleScrollableArea.height > maxVisibleScrollHeight) //if (visibleScrollableArea.height > maxVisibleScrollHeight)
visibleScrollableArea.bottom = visibleScrollableArea.top + maxVisibleScrollHeight; _visibleScrollableArea.bottom = _visibleScrollableArea.top + maxVisibleScrollHeight;
} }
protected int _maxScrollCol;
protected int _maxScrollRow;
protected Rect _fullyVisibleCells; protected Rect _fullyVisibleCells;
protected Rect _fullyVisibleCellsRect; protected Rect _fullyVisibleCellsRect;
protected Rect _fullScrollableArea; protected Rect _fullScrollableArea;
protected Rect _visibleScrollableArea; protected Rect _visibleScrollableArea;
override protected bool handleAction(const Action a) { override protected bool handleAction(const Action a) {
calcScrollableAreaPos(_fullyVisibleCells, _fullyVisibleCellsRect, _fullScrollableArea, _visibleScrollableArea); calcScrollableAreaPos();
switch (a.id) { switch (a.id) {
case GridActions.ScrollLeft: case GridActions.ScrollLeft:
if (_scrollCol > 0) if (_scrollCol > 0)
@ -640,6 +657,11 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
} }
return true; return true;
case GridActions.ScrollPageRight: case GridActions.ScrollPageRight:
int prevCol = _fullyVisibleCells.right;
while (_headerCols + _fixedCols + _scrollCol < prevCol) {
if (!scrollBy(1, 0))
break;
}
return true; return true;
case GridActions.ScrollPageUp: case GridActions.ScrollPageUp:
// scroll up line by line // scroll up line by line
@ -651,6 +673,11 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
} }
return true; return true;
case GridActions.ScrollPageDown: case GridActions.ScrollPageDown:
int prevRow = _fullyVisibleCells.bottom;
while (_headerRows + _fixedRows + _scrollRow < prevRow) {
if (!scrollBy(0, 1))
break;
}
return true; return true;
case GridActions.LineBegin: case GridActions.LineBegin:
if (_scrollCol > 0 && _col > _headerCols + _fixedCols + _scrollCol) if (_scrollCol > 0 && _col > _headerCols + _fixedCols + _scrollCol)
@ -726,7 +753,7 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
int prevRow = _row; int prevRow = _row;
for (int i = prevRow + 1; i < _rows; i++) { for (int i = prevRow + 1; i < _rows; i++) {
selectCell(_col, i); selectCell(_col, i);
calcScrollableAreaPos(_fullyVisibleCells, _fullyVisibleCellsRect, _fullScrollableArea, _visibleScrollableArea); calcScrollableAreaPos();
if (_fullyVisibleCells.top >= prevRow) if (_fullyVisibleCells.top >= prevRow)
break; break;
} }