grid: refactor, move common functionality to base class

This commit is contained in:
Vadim Lopatin 2014-06-05 14:36:29 +04:00
parent 52824b85b5
commit bafb0d2710
1 changed files with 238 additions and 207 deletions

View File

@ -84,22 +84,6 @@ class StringGridAdapter : GridAdapter {
Widget colHeader(int col) { return null; } Widget colHeader(int col) { return null; }
} }
class GridWidgetBase : WidgetGroup {
@property abstract int cols();
@property abstract GridWidgetBase cols(int c);
@property abstract int rows();
@property abstract GridWidgetBase rows(int r);
/// flag to enable column headers
@property abstract bool showColHeaders();
@property abstract GridWidgetBase showColHeaders(bool show);
/// flag to enable row headers
@property abstract bool showRowHeaders();
@property abstract GridWidgetBase showRowHeaders(bool show);
this(string ID = null) {
super(ID);
}
}
/// grid control action codes /// grid control action codes
enum GridActions : int { enum GridActions : int {
/// no action /// no action
@ -165,18 +149,14 @@ enum GridActions : int {
SelectDocumentEnd, SelectDocumentEnd,
} }
/** class GridWidgetBase : WidgetGroup, OnScrollHandler {
* Grid view with string data shown. All rows are of the same height. /// column count (including header columns and fixed columns)
*/
class StringGridWidget : GridWidgetBase, OnScrollHandler {
protected ScrollBar _vscrollbar;
protected ScrollBar _hscrollbar;
protected int _cols; protected int _cols;
/// row count (including header rows and fixed rows)
protected int _rows; protected int _rows;
protected dstring[][] _data; /// column widths
protected dstring[] _rowTitles;
protected dstring[] _colTitles;
protected int[] _colWidths; protected int[] _colWidths;
/// row heights
protected int[] _rowHeights; protected int[] _rowHeights;
/// number of header rows (e.g. like col name A, B, C... in excel; 0 for no header row) /// number of header rows (e.g. like col name A, B, C... in excel; 0 for no header row)
protected int _headerRows; protected int _headerRows;
@ -194,124 +174,60 @@ class StringGridWidget : GridWidgetBase, OnScrollHandler {
protected int _col; protected int _col;
/// selected cell row /// selected cell row
protected int _row; protected int _row;
/// vertical scrollbar control
protected ScrollBar _vscrollbar;
/// horizontal scrollbar control
protected ScrollBar _hscrollbar;
this(string ID = null) { /// selected column
super(ID); @property int col() { return _col; }
_vscrollbar = new ScrollBar("vscrollbar", Orientation.Vertical); /// selected row
_hscrollbar = new ScrollBar("hscrollbar", Orientation.Horizontal); @property int row() { return _row; }
_hscrollbar.onScrollEventListener = this; /// column count
_vscrollbar.onScrollEventListener = this; @property int cols() { return _cols; }
addChild(_vscrollbar); /// set column count
addChild(_hscrollbar); @property GridWidgetBase cols(int c) { resize(c, _rows); return this; }
styleId = "EDIT_BOX"; /// row count
// create sample grid content @property int rows() { return _rows; }
_headerCols = 1; /// set row count
_headerRows = 1; @property GridWidgetBase rows(int r) { resize(_cols, r); return this; }
_fixedCols = 2;
_fixedRows = 2;
resize(20, 30);
_col = 3;
_row = 4;
for (int y = 1; y < _rows; y++) {
for (int x = 1; x < _cols; x++) {
_data[y][x] = "cell("d ~ to!dstring(x) ~ ","d ~ to!dstring(y) ~ ")"d;
}
}
acceleratorMap.add( [
new Action(GridActions.Up, KeyCode.UP, 0),
new Action(GridActions.Down, KeyCode.DOWN, 0),
new Action(GridActions.Left, KeyCode.LEFT, 0),
new Action(GridActions.Right, KeyCode.RIGHT, 0),
new Action(GridActions.LineBegin, KeyCode.HOME, 0),
new Action(GridActions.LineEnd, KeyCode.END, 0),
new Action(GridActions.PageUp, KeyCode.PAGEUP, 0),
new Action(GridActions.PageDown, KeyCode.PAGEDOWN, 0),
new Action(GridActions.PageBegin, KeyCode.PAGEUP, KeyFlag.Control),
new Action(GridActions.PageEnd, KeyCode.PAGEDOWN, KeyFlag.Control),
new Action(GridActions.DocumentBegin, KeyCode.HOME, KeyFlag.Control),
new Action(GridActions.DocumentEnd, KeyCode.END, KeyFlag.Control),
]);
focusable = true;
}
@property override int cols() {
return _cols;
}
@property override GridWidgetBase cols(int c) {
resize(c, _rows);
return this;
}
@property override int rows() {
return _rows;
}
@property override GridWidgetBase rows(int r) {
resize(_cols, r);
return this;
}
/// flag to enable column headers
@property override bool showColHeaders() {
return _headerRows > 0;
}
@property override GridWidgetBase showColHeaders(bool show) {
_headerRows = show ? 1 : 0;
return this;
}
/// flag to enable row headers
@property override bool showRowHeaders() {
return _headerCols > 0;
}
@property override GridWidgetBase showRowHeaders(bool show) {
_headerCols = show ? 1 : 0;
return this;
}
/// get cell text
dstring cellText(int col, int row) {
return _data[row][col];
}
/// set cell text
GridWidgetBase setCellText(int col, int row, dstring text) {
_data[row][col] = text;
return this;
}
/// zero based index generation of column header - like in Excel - for testing
dstring genColHeader(int col) {
dstring res;
int n1 = col / 26;
int n2 = col % 26;
if (n1)
res ~= n1 + 'A';
res ~= n2 + 'A';
return res;
}
/// set new size /// set new size
void resize(int cols, int rows) { void resize(int cols, int rows) {
if (cols == _cols && rows == _rows) if (cols == _cols && rows == _rows)
return; return;
_data.length = rows;
for (int y = 0; y < rows; y++)
_data[y].length = cols;
_colTitles.length = cols;
for (int i = _cols; i < cols; i++)
_colTitles[i] = i > 0 ? ("col "d ~ to!dstring(i)) : ""d;
_rowTitles.length = rows;
_colWidths.length = cols; _colWidths.length = cols;
for (int i = _cols; i < cols; i++) { for (int i = _cols; i < cols; i++) {
if (i >= _headerCols)
_data[0][i] = genColHeader(i - _headerCols);
_colWidths[i] = i == 0 ? 20 : 100; _colWidths[i] = i == 0 ? 20 : 100;
} }
_rowHeights.length = rows; _rowHeights.length = rows;
int fontHeight = font.height; int fontHeight = font.height;
for (int i = _rows; i < rows; i++) { for (int i = _rows; i < rows; i++) {
if (i >= _headerRows)
_data[i][0] = to!dstring(i - _headerRows + 1);
_rowHeights[i] = fontHeight + 2; _rowHeights[i] = fontHeight + 2;
} }
_cols = cols; _cols = cols;
_rows = rows; _rows = rows;
} }
/// flag to enable column headers
@property bool showColHeaders() {
return _headerRows > 0;
}
@property GridWidgetBase showColHeaders(bool show) {
_headerRows = show ? 1 : 0;
invalidate();
return this;
}
/// flag to enable row headers
@property bool showRowHeaders() {
return _headerCols > 0;
}
@property GridWidgetBase showRowHeaders(bool show) {
_headerCols = show ? 1 : 0;
invalidate();
return this;
}
/// returns column width (index includes col/row headers, if any); returns 0 for columns hidden by scroll at the left /// returns column width (index includes col/row headers, if any); returns 0 for columns hidden by scroll at the left
int colWidth(int x) { int colWidth(int x) {
if (x >= _headerCols + _fixedCols && x < _headerCols + _fixedCols + _scrollCol) if (x >= _headerCols + _fixedCols && x < _headerCols + _fixedCols + _scrollCol)
@ -404,6 +320,7 @@ class StringGridWidget : GridWidgetBase, OnScrollHandler {
} }
} }
/// column by X, ignoring scroll position
protected int colByAbsoluteX(int x) { protected int colByAbsoluteX(int x) {
int xx = 0; int xx = 0;
for (int i = 0; i < _cols; i++) { for (int i = 0; i < _cols; i++) {
@ -415,6 +332,7 @@ class StringGridWidget : GridWidgetBase, OnScrollHandler {
return 0; return 0;
} }
/// row by Y, ignoring scroll position
protected int rowByAbsoluteY(int y) { protected int rowByAbsoluteY(int y) {
int yy = 0; int yy = 0;
for (int i = 0; i < _rows; i++) { for (int i = 0; i < _rows; i++) {
@ -740,39 +658,6 @@ class StringGridWidget : GridWidgetBase, OnScrollHandler {
} }
} }
/// returns row header title
dstring rowTitle(int row) {
return _rowTitles[row];
}
/// set row header title
GridWidgetBase setRowTitle(int row, dstring title) {
_rowTitles[row] = title;
return this;
}
/// returns row header title
dstring colTitle(int col) {
return _colTitles[col];
}
/// set col header title
GridWidgetBase setColTitle(int col, dstring title) {
_colTitles[col] = title;
return this;
}
/// draw column header
void drawColHeader(DrawBuf buf, Rect rc, int index) {
//FontRef fnt = font;
//buf.fillRect(rc, 0xE0E0E0);
//buf.drawFrame(rc, 0x808080, Rect(1,1,1,1));
//fnt.drawText(buf, rc.left, rc.top, "col"d, 0x000000);
}
/// draw row header
void drawRowHeader(DrawBuf buf, Rect rc, int index) {
//FontRef fnt = font;
//buf.fillRect(rc, 0xE0E0E0);
//buf.drawFrame(rc, 0x808080, Rect(1,1,1,1));
//fnt.drawText(buf, rc.left, rc.top, "row"d, 0x000000);
}
Point fullContentSize() { Point fullContentSize() {
Point sz; Point sz;
for (int i = 0; i < _cols; i++) for (int i = 0; i < _cols; i++)
@ -839,53 +724,7 @@ class StringGridWidget : GridWidgetBase, OnScrollHandler {
updateScrollBars(); updateScrollBars();
} }
/// draw cell content protected void drawClient(DrawBuf buf) {
void drawCell(DrawBuf buf, Rect rc, int col, int row) {
rc.shrink(2, 1);
FontRef fnt = font;
dstring txt = cellText(col, row);
Point sz = fnt.textSize(txt);
Align ha = Align.Left;
if (col < _headerCols)
ha = Align.Right;
if (row < _headerRows)
ha = Align.HCenter;
applyAlign(rc, sz, ha, Align.VCenter);
fnt.drawText(buf, rc.left + 1, rc.top + 1, txt, 0x000000);
}
/// draw cell background
void drawCellBackground(DrawBuf buf, Rect rc, int col, int row) {
Rect vborder = rc;
Rect hborder = rc;
vborder.left = vborder.right - 1;
hborder.top = hborder.bottom - 1;
hborder.right--;
bool selectedCol = _col == col;
bool selectedRow = _row == row;
bool selectedCell = selectedCol && selectedRow;
if (col < _headerCols || row < _headerRows) {
// draw header cell background
uint cl = 0x80909090;
if (selectedCol || selectedRow)
cl = 0x80FFC040;
buf.fillRect(rc, cl);
buf.fillRect(vborder, 0x80202020);
buf.fillRect(hborder, 0x80202020);
} else {
// normal cell background
if (col < _headerCols + _fixedCols || row < _headerRows + _fixedRows) {
// fixed cell background
buf.fillRect(rc, 0x80E0E0E0);
}
buf.fillRect(vborder, 0x80C0C0C0);
buf.fillRect(hborder, 0x80C0C0C0);
if (selectedCell)
buf.drawFrame(rc, 0x404040FF, Rect(1,1,1,1), 0xC0FFFF00);
}
}
void drawClient(DrawBuf buf) {
auto saver = ClipRectSaver(buf, _clientRect, 0); auto saver = ClipRectSaver(buf, _clientRect, 0);
//buf.fillRect(_clientRect, 0x80A08080); //buf.fillRect(_clientRect, 0x80A08080);
Rect rc; Rect rc;
@ -939,6 +778,198 @@ class StringGridWidget : GridWidgetBase, OnScrollHandler {
drawClient(buf); drawClient(buf);
_needDraw = false; _needDraw = false;
} }
/// draw cell content
protected void drawCell(DrawBuf buf, Rect rc, int col, int row) {
// override it
}
/// draw cell background
protected void drawCellBackground(DrawBuf buf, Rect rc, int col, int row) {
// override it
}
this(string ID = null) {
super(ID);
_vscrollbar = new ScrollBar("vscrollbar", Orientation.Vertical);
_hscrollbar = new ScrollBar("hscrollbar", Orientation.Horizontal);
_hscrollbar.onScrollEventListener = this;
_vscrollbar.onScrollEventListener = this;
addChild(_vscrollbar);
addChild(_hscrollbar);
acceleratorMap.add( [
new Action(GridActions.Up, KeyCode.UP, 0),
new Action(GridActions.Down, KeyCode.DOWN, 0),
new Action(GridActions.Left, KeyCode.LEFT, 0),
new Action(GridActions.Right, KeyCode.RIGHT, 0),
new Action(GridActions.LineBegin, KeyCode.HOME, 0),
new Action(GridActions.LineEnd, KeyCode.END, 0),
new Action(GridActions.PageUp, KeyCode.PAGEUP, 0),
new Action(GridActions.PageDown, KeyCode.PAGEDOWN, 0),
new Action(GridActions.PageBegin, KeyCode.PAGEUP, KeyFlag.Control),
new Action(GridActions.PageEnd, KeyCode.PAGEDOWN, KeyFlag.Control),
new Action(GridActions.DocumentBegin, KeyCode.HOME, KeyFlag.Control),
new Action(GridActions.DocumentEnd, KeyCode.END, KeyFlag.Control),
]);
focusable = true;
}
}
/**
* Grid view with string data shown. All rows are of the same height.
*/
class StringGridWidget : GridWidgetBase {
protected dstring[][] _data;
protected dstring[] _rowTitles;
protected dstring[] _colTitles;
this(string ID = null) {
super(ID);
styleId = "EDIT_BOX";
// create sample grid content
_headerCols = 1;
_headerRows = 1;
_fixedCols = 2;
_fixedRows = 2;
resize(20, 30);
_col = 3;
_row = 4;
for (int y = 1; y < _rows; y++) {
for (int x = 1; x < _cols; x++) {
_data[y][x] = "cell("d ~ to!dstring(x) ~ ","d ~ to!dstring(y) ~ ")"d;
}
}
}
/// get cell text
dstring cellText(int col, int row) {
return _data[row][col];
}
/// set cell text
GridWidgetBase setCellText(int col, int row, dstring text) {
_data[row][col] = text;
return this;
}
/// zero based index generation of column header - like in Excel - for testing
dstring genColHeader(int col) {
dstring res;
int n1 = col / 26;
int n2 = col % 26;
if (n1)
res ~= n1 + 'A';
res ~= n2 + 'A';
return res;
}
/// set new size
override void resize(int cols, int rows) {
if (cols == _cols && rows == _rows)
return;
int oldcols = _cols;
int oldrows = _rows;
super.resize(cols, rows);
_data.length = rows;
for (int y = 0; y < rows; y++)
_data[y].length = cols;
_colTitles.length = cols;
for (int i = oldcols; i < cols; i++)
_colTitles[i] = i > 0 ? ("col "d ~ to!dstring(i)) : ""d;
_rowTitles.length = rows;
for (int i = oldcols; i < cols; i++) {
if (i >= _headerCols)
_data[0][i] = genColHeader(i - _headerCols);
_colWidths[i] = i == 0 ? 20 : 100;
}
_rowHeights.length = rows;
int fontHeight = font.height;
for (int i = oldrows; i < rows; i++) {
if (i >= _headerRows)
_data[i][0] = to!dstring(i - _headerRows + 1);
_rowHeights[i] = fontHeight + 2;
}
}
/// returns row header title
dstring rowTitle(int row) {
return _rowTitles[row];
}
/// set row header title
GridWidgetBase setRowTitle(int row, dstring title) {
_rowTitles[row] = title;
return this;
}
/// returns row header title
dstring colTitle(int col) {
return _colTitles[col];
}
/// set col header title
GridWidgetBase setColTitle(int col, dstring title) {
_colTitles[col] = title;
return this;
}
/// draw column header
void drawColHeader(DrawBuf buf, Rect rc, int index) {
//FontRef fnt = font;
//buf.fillRect(rc, 0xE0E0E0);
//buf.drawFrame(rc, 0x808080, Rect(1,1,1,1));
//fnt.drawText(buf, rc.left, rc.top, "col"d, 0x000000);
}
/// draw row header
void drawRowHeader(DrawBuf buf, Rect rc, int index) {
//FontRef fnt = font;
//buf.fillRect(rc, 0xE0E0E0);
//buf.drawFrame(rc, 0x808080, Rect(1,1,1,1));
//fnt.drawText(buf, rc.left, rc.top, "row"d, 0x000000);
}
/// draw cell content
protected override void drawCell(DrawBuf buf, Rect rc, int col, int row) {
rc.shrink(2, 1);
FontRef fnt = font;
dstring txt = cellText(col, row);
Point sz = fnt.textSize(txt);
Align ha = Align.Left;
if (col < _headerCols)
ha = Align.Right;
if (row < _headerRows)
ha = Align.HCenter;
applyAlign(rc, sz, ha, Align.VCenter);
fnt.drawText(buf, rc.left + 1, rc.top + 1, txt, 0x000000);
}
/// draw cell background
protected override void drawCellBackground(DrawBuf buf, Rect rc, int col, int row) {
Rect vborder = rc;
Rect hborder = rc;
vborder.left = vborder.right - 1;
hborder.top = hborder.bottom - 1;
hborder.right--;
bool selectedCol = _col == col;
bool selectedRow = _row == row;
bool selectedCell = selectedCol && selectedRow;
if (col < _headerCols || row < _headerRows) {
// draw header cell background
uint cl = 0x80909090;
if (selectedCol || selectedRow)
cl = 0x80FFC040;
buf.fillRect(rc, cl);
buf.fillRect(vborder, 0x80202020);
buf.fillRect(hborder, 0x80202020);
} else {
// normal cell background
if (col < _headerCols + _fixedCols || row < _headerRows + _fixedRows) {
// fixed cell background
buf.fillRect(rc, 0x80E0E0E0);
}
buf.fillRect(vborder, 0x80C0C0C0);
buf.fillRect(hborder, 0x80C0C0C0);
if (selectedCell)
buf.drawFrame(rc, 0x404040FF, Rect(1,1,1,1), 0xC0FFFF00);
}
}
} }
/** /**