grids: row select support

This commit is contained in:
Vadim Lopatin 2014-06-09 13:26:19 +04:00
parent 0103bb8a3d
commit e7b40dc6e0
2 changed files with 135 additions and 31 deletions

View File

@ -520,6 +520,7 @@ extern (C) int UIAppMain(string[] args) {
grid.resize(30, 50);
grid.fixedCols = 3;
grid.fixedRows = 2;
grid.rowSelect = true;
grid.selectCell(4, 6, false);
// create sample grid content
for (int y = 1; y < grid.rows; y++) {

View File

@ -158,6 +158,10 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
protected int[] _colWidths;
/// row heights
protected int[] _rowHeights;
/// when true, shows col headers row
protected bool _showColHeaders;
/// when true, shows row headers column
protected bool _showRowHeaders;
/// number of header rows (e.g. like col name A, B, C... in excel; 0 for no header row)
protected int _headerRows;
/// number of header columns (e.g. like row number in excel; 0 for no header column)
@ -180,7 +184,8 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
protected ScrollBar _hscrollbar;
/// inner area, excluding additional controls like scrollbars
protected Rect _clientRect;
/// when true, allows to select only whole row
protected bool _rowSelect;
// properties
@ -196,6 +201,7 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
@property int rows() { return _rows; }
/// set row count
@property GridWidgetBase rows(int r) { resize(_cols, r); return this; }
/// fixed (non-scrollable) data column count
@property int fixedCols() { return _fixedCols; }
@property GridWidgetBase fixedCols(int c) { _fixedCols = c; invalidate(); return this; }
@ -203,23 +209,58 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
@property int fixedRows() { return _fixedRows; }
@property GridWidgetBase fixedRows(int r) { _fixedRows = r; invalidate(); return this; }
/// row header column count
@property int headerCols() { return _headerCols; }
@property GridWidgetBase headerCols(int c) {
_headerCols = c;
invalidate();
return this;
}
/// col header row count
@property int headerRows() { return _headerRows; }
@property GridWidgetBase headerRows(int r) {
_headerRows = r;
invalidate();
return this;
}
/// flag to enable column headers
@property bool showColHeaders() {
return _headerRows > 0;
/// when true, allows only select the whole row
@property bool rowSelect() {
return _rowSelect;
}
@property GridWidgetBase showColHeaders(bool show) {
_headerRows = show ? 1 : 0;
@property GridWidgetBase rowSelect(bool flg) {
_rowSelect = flg;
invalidate();
return this;
}
/// flag to enable column headers
@property bool showColHeaders() {
return _showColHeaders;
}
@property GridWidgetBase showColHeaders(bool show) {
if (_showColHeaders != show) {
_showColHeaders = show;
for (int i = 0; i < _headerRows; i++)
autoFitRowHeight(i);
invalidate();
}
return this;
}
/// flag to enable row headers
@property bool showRowHeaders() {
return _headerCols > 0;
return _showRowHeaders;
}
@property GridWidgetBase showRowHeaders(bool show) {
_headerCols = show ? 1 : 0;
invalidate();
if (_showRowHeaders != show) {
_showRowHeaders = show;
for (int i = 0; i < _headerCols; i++)
autoFitColumnWidth(i);
invalidate();
}
return this;
}
@ -391,6 +432,7 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
}
//if (changed)
updateScrollBars();
invalidate();
return oldx != _scrollCol || oldy != _scrollRow;
}
@ -505,6 +547,13 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
}
return true;
}
if (event.action == MouseAction.Wheel) {
if (event.flags & MouseFlag.Shift)
scrollBy(-event.wheelDelta, 0);
else
scrollBy(0, -event.wheelDelta);
return true;
}
return super.onMouseEvent(event);
}
@ -618,24 +667,41 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
override protected bool handleAction(const Action a) {
calcScrollableAreaPos();
switch (a.id) {
int actionId = a.id;
if (_rowSelect) {
switch(actionId) {
case GridActions.Left:
actionId = GridActions.ScrollLeft;
break;
case GridActions.Right:
actionId = GridActions.ScrollRight;
break;
//case GridActions.LineBegin:
// actionId = GridActions.ScrollPageLeft;
// break;
//case GridActions.LineEnd:
// actionId = GridActions.ScrollPageRight;
// break;
default:
break;
}
}
switch (actionId) {
case GridActions.ScrollLeft:
if (_scrollCol > 0)
scrollBy(-1, 0);
scrollBy(-1, 0);
return true;
case GridActions.Left:
selectCell(_col - 1, _row);
return true;
case GridActions.ScrollRight:
if (_fullyVisibleCells.right < _cols - 1)
scrollBy(1, 0);
scrollBy(1, 0);
return true;
case GridActions.Right:
selectCell(_col + 1, _row);
return true;
case GridActions.ScrollUp:
if (_scrollRow > 0)
scrollBy(0, -1);
scrollBy(0, -1);
return true;
case GridActions.Up:
selectCell(_col, _row - 1);
@ -680,7 +746,7 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
}
return true;
case GridActions.LineBegin:
if (_scrollCol > 0 && _col > _headerCols + _fixedCols + _scrollCol)
if (_scrollCol > 0 && _col > _headerCols + _fixedCols + _scrollCol && !_rowSelect)
selectCell(_headerCols + _fixedCols + _scrollCol, _row);
else {
if (_scrollCol > 0) {
@ -791,7 +857,6 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
}
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
override void layout(Rect rc) {
if (visibility == Visibility.Gone) {
@ -924,14 +989,22 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
return m;
}
void autoFitColumnWidth(int i) {
_colWidths[i] = (i < _headerCols && !_showRowHeaders) ? 0 : measureColWidth(i) + 5;
}
void autoFitColumnWidths() {
for (int i = 0; i < _cols; i++)
_colWidths[i] = measureColWidth(i) + 5;
autoFitColumnWidth(i);
}
void autoFitRowHeight(int i) {
_rowHeights[i] = (i < _headerRows && !_showColHeaders) ? 0 : measureRowHeight(i) + 2;
}
void autoFitRowHeights() {
for (int i = 0; i < _rows; i++)
_rowHeights[i] = measureRowHeight(i) + 2;
autoFitRowHeight(i);
}
void autoFit() {
@ -947,6 +1020,10 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
_vscrollbar.onScrollEventListener = this;
addChild(_vscrollbar);
addChild(_hscrollbar);
_headerCols = 1;
_headerRows = 1;
_showColHeaders = true;
_showRowHeaders = true;
acceleratorMap.add( [
new Action(GridActions.Up, KeyCode.UP, 0),
new Action(GridActions.Down, KeyCode.DOWN, 0),
@ -965,11 +1042,29 @@ class GridWidgetBase : WidgetGroup, OnScrollHandler {
}
}
class StringGridWidgetBase : GridWidgetBase {
this(string ID = null) {
super(ID);
}
/// get cell text
abstract dstring cellText(int col, int row);
/// set cell text
abstract StringGridWidgetBase setCellText(int col, int row, dstring text);
/// returns row header title
abstract dstring rowTitle(int row);
/// set row header title
abstract StringGridWidgetBase setRowTitle(int row, dstring title);
/// returns row header title
abstract dstring colTitle(int col);
/// set col header title
abstract StringGridWidgetBase setColTitle(int col, dstring title);
}
/**
* Grid view with string data shown. All rows are of the same height.
*/
class StringGridWidget : GridWidgetBase {
class StringGridWidget : StringGridWidgetBase {
protected dstring[][] _data;
protected dstring[] _rowTitles;
@ -980,11 +1075,11 @@ class StringGridWidget : GridWidgetBase {
styleId = "EDIT_BOX";
}
/// get cell text
dstring cellText(int col, int row) {
override dstring cellText(int col, int row) {
return _data[row][col];
}
/// set cell text
GridWidgetBase setCellText(int col, int row, dstring text) {
override StringGridWidgetBase setCellText(int col, int row, dstring text) {
_data[row][col] = text;
return this;
}
@ -1038,22 +1133,22 @@ class StringGridWidget : GridWidgetBase {
}
/// returns row header title
dstring rowTitle(int row) {
override dstring rowTitle(int row) {
return _rowTitles[row];
}
/// set row header title
GridWidgetBase setRowTitle(int row, dstring title) {
override StringGridWidgetBase setRowTitle(int row, dstring title) {
_rowTitles[row] = title;
return this;
}
/// returns row header title
dstring colTitle(int col) {
override dstring colTitle(int col) {
return _colTitles[col];
}
/// set col header title
GridWidgetBase setColTitle(int col, dstring title) {
override StringGridWidgetBase setColTitle(int col, dstring title) {
_colTitles[col] = title;
return this;
}
@ -1093,11 +1188,15 @@ class StringGridWidget : GridWidgetBase {
bool selectedCol = _col == col;
bool selectedRow = _row == row;
bool selectedCell = selectedCol && selectedRow;
if (_rowSelect && selectedRow)
selectedCell = true;
if (col < _headerCols || row < _headerRows) {
// draw header cell background
uint cl = 0x80909090;
if (selectedCol || selectedRow)
cl = 0x80FFC040;
if (!_rowSelect || col < _headerCols) {
if (selectedCol || selectedRow)
cl = 0x80FFC040;
}
buf.fillRect(rc, cl);
buf.fillRect(vborder, 0x80202020);
buf.fillRect(hborder, 0x80202020);
@ -1109,8 +1208,12 @@ class StringGridWidget : GridWidgetBase {
}
buf.fillRect(vborder, 0x80C0C0C0);
buf.fillRect(hborder, 0x80C0C0C0);
if (selectedCell)
buf.drawFrame(rc, 0x404040FF, Rect(1,1,1,1), 0xC0FFFF00);
if (selectedCell) {
if (_rowSelect)
buf.drawFrame(rc, 0x80A0B0FF, Rect(0,1,0,1), 0xC0FFFF00);
else
buf.drawFrame(rc, 0x404040FF, Rect(1,1,1,1), 0xC0FFFF00);
}
}
}