Merge pull request #339 from igor84/multiSelect

Added multi selection to string grid and filedlg, issue #23
This commit is contained in:
Vadim Lopatin 2017-04-25 10:16:24 +03:00 committed by GitHub
commit e4d156cfae
4 changed files with 288 additions and 23 deletions

View File

@ -384,6 +384,7 @@ extern (C) int UIAppMain(string[] args) {
UIString caption; UIString caption;
caption = "Open Text File"d; caption = "Open Text File"d;
FileDialog dlg = new FileDialog(caption, window, null); FileDialog dlg = new FileDialog(caption, window, null);
dlg.allowMultipleFiles = true;
dlg.addFilter(FileFilterEntry(UIString("FILTER_ALL_FILES", "All files (*)"d), "*")); dlg.addFilter(FileFilterEntry(UIString("FILTER_ALL_FILES", "All files (*)"d), "*"));
dlg.addFilter(FileFilterEntry(UIString("FILTER_TEXT_FILES", "Text files (*.txt)"d), "*.txt")); dlg.addFilter(FileFilterEntry(UIString("FILTER_TEXT_FILES", "Text files (*.txt)"d), "*.txt"));
dlg.addFilter(FileFilterEntry(UIString("FILTER_SOURCE_FILES", "Source files"d), "*.d;*.dd;*.c;*.cc;*.cpp;*.h;*.hpp")); dlg.addFilter(FileFilterEntry(UIString("FILTER_SOURCE_FILES", "Source files"d), "*.d;*.dd;*.c;*.cc;*.cpp;*.h;*.hpp"));
@ -391,29 +392,31 @@ extern (C) int UIAppMain(string[] args) {
//dlg.filterIndex = 2; //dlg.filterIndex = 2;
dlg.dialogResult = delegate(Dialog dlg, const Action result) { dlg.dialogResult = delegate(Dialog dlg, const Action result) {
if (result.id == ACTION_OPEN.id) { if (result.id == ACTION_OPEN.id) {
string filename = result.stringParam; string[] filenames = (cast(FileDialog)dlg).filenames;
if (filename.endsWith(".d") || filename.endsWith(".txt") || filename.endsWith(".cpp") || filename.endsWith(".h") || filename.endsWith(".c") foreach (filename; filenames) {
|| filename.endsWith(".json") || filename.endsWith(".dd") || filename.endsWith(".ddoc") || filename.endsWith(".xml") || filename.endsWith(".html") if (filename.endsWith(".d") || filename.endsWith(".txt") || filename.endsWith(".cpp") || filename.endsWith(".h") || filename.endsWith(".c")
|| filename.endsWith(".html") || filename.endsWith(".css") || filename.endsWith(".log") || filename.endsWith(".hpp")) { || filename.endsWith(".json") || filename.endsWith(".dd") || filename.endsWith(".ddoc") || filename.endsWith(".xml") || filename.endsWith(".html")
// open source file in tab || filename.endsWith(".html") || filename.endsWith(".css") || filename.endsWith(".log") || filename.endsWith(".hpp")) {
int index = tabs.tabIndex(filename); // open source file in tab
if (index >= 0) { int index = tabs.tabIndex(filename);
// file is already opened in tab if (index >= 0) {
tabs.selectTab(index, true); // file is already opened in tab
} else { tabs.selectTab(index, true);
SourceEdit editor = new SourceEdit(filename);
if (editor.load(filename)) {
tabs.addTab(editor, toUTF32(baseName(filename)), null, true);
tabs.selectTab(filename);
} else { } else {
destroy(editor); SourceEdit editor = new SourceEdit(filename);
window.showMessageBox(UIString("File open error"d), UIString("Cannot open file "d ~ toUTF32(filename))); if (editor.load(filename)) {
tabs.addTab(editor, toUTF32(baseName(filename)), null, true);
tabs.selectTab(filename);
} else {
destroy(editor);
window.showMessageBox(UIString("File open error"d), UIString("Cannot open file "d ~ toUTF32(filename)));
}
} }
} else {
Log.d("FileDialog.onDialogResult: ", result, " param=", result.stringParam);
window.showMessageBox(UIString("FileOpen result"d), UIString("Filename: "d ~ toUTF32(filename)));
} }
} else { }
Log.d("FileDialog.onDialogResult: ", result, " param=", result.stringParam);
window.showMessageBox(UIString("FileOpen result"d), UIString("Filename: "d ~ toUTF32(filename)));
}
} }
}; };
@ -950,6 +953,7 @@ void main()
grid.fixedCols = 3; grid.fixedCols = 3;
grid.fixedRows = 2; grid.fixedRows = 2;
//grid.rowSelect = true; // testing full row selection //grid.rowSelect = true; // testing full row selection
grid.multiSelect = true;
grid.selectCell(4, 6, false); grid.selectCell(4, 6, false);
// create sample grid content // create sample grid content
for (int y = 0; y < grid.rows; y++) { for (int y = 0; y < grid.rows; y++) {

View File

@ -56,6 +56,10 @@ struct Point {
Point opBinary(string op)(Point v) if (op == "-") { Point opBinary(string op)(Point v) if (op == "-") {
return Point(x - v.x, y - v.y); return Point(x - v.x, y - v.y);
} }
int opCmp(ref const Point b) const {
if (x == b.x) return y - b.y;
return x - b.x;
}
} }
/// 2D rectangle /// 2D rectangle

View File

@ -120,6 +120,7 @@ class FileDialog : Dialog, CustomGridCellAdapter {
protected bool _isOpenDialog; protected bool _isOpenDialog;
protected bool _showHiddenFiles; protected bool _showHiddenFiles;
protected bool _allowMultipleFiles;
protected string[string] _filetypeIcons; protected string[string] _filetypeIcons;
@ -183,6 +184,18 @@ class FileDialog : Dialog, CustomGridCellAdapter {
_filename = s; _filename = s;
} }
/// all the selected filenames
@property string[] filenames() {
string[] res;
res.reserve(_fileList.selection.length);
int i = 0;
foreach (val; _fileList.selection) {
res ~= _entries[val.y];
++i;
}
return res;
}
@property bool showHiddenFiles() { @property bool showHiddenFiles() {
return _showHiddenFiles; return _showHiddenFiles;
} }
@ -191,6 +204,14 @@ class FileDialog : Dialog, CustomGridCellAdapter {
_showHiddenFiles = b; _showHiddenFiles = b;
} }
@property bool allowMultipleFiles() {
return _allowMultipleFiles;
}
@property void allowMultipleFiles(bool b) {
_allowMultipleFiles = b;
}
/// return currently selected filter value - array of patterns like ["*.txt", "*.rtf"] /// return currently selected filter value - array of patterns like ["*.txt", "*.rtf"]
@property string[] selectedFilter() { @property string[] selectedFilter() {
if (_filterIndex >= 0 && _filterIndex < _filters.length) if (_filterIndex >= 0 && _filterIndex < _filters.length)
@ -575,6 +596,7 @@ class FileDialog : Dialog, CustomGridCellAdapter {
_fileList.setColTitle(3, "Modified"d); _fileList.setColTitle(3, "Modified"d);
_fileList.showRowHeaders = false; _fileList.showRowHeaders = false;
_fileList.rowSelect = true; _fileList.rowSelect = true;
_fileList.multiSelect = _allowMultipleFiles;
_fileList.cellPopupMenu = &getCellPopupMenu; _fileList.cellPopupMenu = &getCellPopupMenu;
_fileList.menuItemAction = &handleAction; _fileList.menuItemAction = &handleAction;

View File

@ -58,6 +58,7 @@ import dlangui.widgets.controls;
import dlangui.widgets.scroll; import dlangui.widgets.scroll;
import dlangui.widgets.menu; import dlangui.widgets.menu;
import std.conv; import std.conv;
import std.container.rbtree;
import std.algorithm : equal; import std.algorithm : equal;
/// cellPopupMenu signal handler interface /// cellPopupMenu signal handler interface
@ -151,12 +152,20 @@ enum GridActions : int {
None = 0, None = 0,
/// move selection up /// move selection up
Up = 2000, Up = 2000,
/// expend selection up
SelectUp,
/// move selection down /// move selection down
Down, Down,
/// expend selection down
SelectDown,
/// move selection left /// move selection left
Left, Left,
/// expend selection left
SelectLeft,
/// move selection right /// move selection right
Right, Right,
/// expend selection right
SelectRight,
/// scroll up, w/o changing selection /// scroll up, w/o changing selection
ScrollUp, ScrollUp,
@ -208,6 +217,8 @@ enum GridActions : int {
DocumentEnd, DocumentEnd,
/// move cursor to the end of document with selection /// move cursor to the end of document with selection
SelectDocumentEnd, SelectDocumentEnd,
/// select all entries without moving the cursor
SelectAll,
/// Enter key pressed on cell /// Enter key pressed on cell
ActivateCell, ActivateCell,
} }
@ -324,10 +335,15 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
/// scroll Y offset in pixels /// scroll Y offset in pixels
protected int _scrollY; protected int _scrollY;
/// selected cells when multiselect is enabled
protected RedBlackTree!Point _selection;
/// selected cell column /// selected cell column
protected int _col; protected int _col;
/// selected cell row /// selected cell row
protected int _row; protected int _row;
/// when true, allows multi cell selection
protected bool _multiSelect;
private Point _lastSelectedCell;
/// when true, allows to select only whole row /// when true, allows to select only whole row
protected bool _rowSelect; protected bool _rowSelect;
/// default column width - for newly added columns /// default column width - for newly added columns
@ -337,6 +353,8 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
// properties // properties
/// selected cells when multiselect is enabled
@property RedBlackTree!Point selection() { return _selection; }
/// selected column /// selected column
@property int col() { return _col - _headerCols; } @property int col() { return _col - _headerCols; }
/// selected row /// selected row
@ -422,12 +440,29 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
return this; return this;
} }
/// when true, allows multi cell selection
@property bool multiSelect() {
return _multiSelect;
}
@property GridWidgetBase multiSelect(bool flg) {
_multiSelect = flg;
if (!_multiSelect) {
_selection.clear();
_selection.insert(Point(_col - _headerCols, _row - _headerRows));
}
return this;
}
/// when true, allows only select the whole row /// when true, allows only select the whole row
@property bool rowSelect() { @property bool rowSelect() {
return _rowSelect; return _rowSelect;
} }
@property GridWidgetBase rowSelect(bool flg) { @property GridWidgetBase rowSelect(bool flg) {
_rowSelect = flg; _rowSelect = flg;
if (_rowSelect) {
_selection.clear();
_selection.insert(Point(_col - _headerCols, _row - _headerRows));
}
invalidate(); invalidate();
return this; return this;
} }
@ -872,10 +907,51 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
} }
} }
bool multiSelectCell(int col, int row, bool expandExisting = false) {
if (_col == col && _row == row && !expandExisting)
return false; // same position
if (col < _headerCols || row < _headerRows || col >= _cols || row >= _rows)
return false; // out of range
if (_changedSize) updateCumulativeSizes();
_lastSelectedCell.x = col;
_lastSelectedCell.y = row;
if (_rowSelect) col = _headerCols;
if (expandExisting) {
_selection.clear();
int startX = _col - _headerCols;
int startY = _row - headerRows;
int endX = col - _headerCols;
int endY = row - headerRows;
if (_rowSelect) startX = 0;
if (startX > endX) {
startX = endX;
endX = _col - _headerCols;
}
if (startY > endY) {
startY = endY;
endY = _row - _headerRows;
}
for (int x = startX; x <= endX; ++x) {
for (int y = startY; y <= endY; ++y) {
_selection.insert(Point(x, y));
}
}
} else {
_selection.insert(Point(col - _headerCols, row - _headerRows));
_col = col;
_row = row;
}
invalidate();
calcScrollableAreaPos();
makeCellVisible(_lastSelectedCell.x, _lastSelectedCell.y);
return true;
}
/// move selection to specified cell /// move selection to specified cell
bool selectCell(int col, int row, bool makeVisible = true, GridWidgetBase source = null, bool needNotification = true) { bool selectCell(int col, int row, bool makeVisible = true, GridWidgetBase source = null, bool needNotification = true) {
if (source is null) if (source is null)
source = this; source = this;
_selection.clear();
if (_col == col && _row == row) if (_col == col && _row == row)
return false; // same position return false; // same position
if (col < _headerCols || row < _headerRows || col >= _cols || row >= _rows) if (col < _headerCols || row < _headerRows || col >= _cols || row >= _rows)
@ -883,6 +959,12 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
if (_changedSize) updateCumulativeSizes(); if (_changedSize) updateCumulativeSizes();
_col = col; _col = col;
_row = row; _row = row;
_lastSelectedCell = Point(col, row);
if (_rowSelect) {
_selection.insert(Point(0, row - _headerRows));
} else {
_selection.insert(Point(col - _headerCols, row - _headerRows));
}
invalidate(); invalidate();
calcScrollableAreaPos(); calcScrollableAreaPos();
if (makeVisible) if (makeVisible)
@ -1063,6 +1145,8 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
if (cellFound && normalCell) { if (cellFound && normalCell) {
if (c == _col && r == _row && event.doubleClick) { if (c == _col && r == _row && event.doubleClick) {
activateCell(c, r); activateCell(c, r);
} else if (_multiSelect && (event.flags & (MouseFlag.Shift | MouseFlag.Control)) != 0) {
multiSelectCell(c, r, (event.flags & MouseFlag.Shift) != 0);
} else { } else {
selectCell(c, r); selectCell(c, r);
} }
@ -1072,7 +1156,11 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
if (event.action == MouseAction.Move && (event.flags & MouseFlag.LButton)) { if (event.action == MouseAction.Move && (event.flags & MouseFlag.LButton)) {
// TODO: selection // TODO: selection
if (cellFound && normalCell) { if (cellFound && normalCell) {
selectCell(c, r); if (_multiSelect) {
multiSelectCell(c, r, true);
} else {
selectCell(c, r);
}
} }
return true; return true;
} }
@ -1175,18 +1263,39 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
case Left: case Left:
selectCell(_col - 1, _row); selectCell(_col - 1, _row);
return true; return true;
case SelectLeft:
if (_multiSelect) {
multiSelectCell(_lastSelectedCell.x - 1, _lastSelectedCell.y, true);
} else {
selectCell(_col - 1, _row);
}
return true;
case ScrollRight: case ScrollRight:
scrollBy(1, 0); scrollBy(1, 0);
return true; return true;
case Right: case Right:
selectCell(_col + 1, _row); selectCell(_col + 1, _row);
return true; return true;
case SelectRight:
if (_multiSelect) {
multiSelectCell(_lastSelectedCell.x + 1, _lastSelectedCell.y, true);
} else {
selectCell(_col + 1, _row);
}
return true;
case ScrollUp: case ScrollUp:
scrollBy(0, -1); scrollBy(0, -1);
return true; return true;
case Up: case Up:
selectCell(_col, _row - 1); selectCell(_col, _row - 1);
return true; return true;
case SelectUp:
if (_multiSelect) {
multiSelectCell(_lastSelectedCell.x, _lastSelectedCell.y - 1, true);
} else {
selectCell(_col, _row - 1);
}
return true;
case ScrollDown: case ScrollDown:
if (lastScrollRow < _rows - 1) if (lastScrollRow < _rows - 1)
scrollBy(0, 1); scrollBy(0, 1);
@ -1194,6 +1303,13 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
case Down: case Down:
selectCell(_col, _row + 1); selectCell(_col, _row + 1);
return true; return true;
case SelectDown:
if (_multiSelect) {
multiSelectCell(_lastSelectedCell.x, _lastSelectedCell.y + 1, true);
} else {
selectCell(_col, _row + 1);
}
return true;
case ScrollPageLeft: case ScrollPageLeft:
// scroll left cell by cell // scroll left cell by cell
while (scrollCol > nonScrollCols) { while (scrollCol > nonScrollCols) {
@ -1224,8 +1340,23 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
break; break;
} }
return true; return true;
case SelectLineBegin:
if (!_multiSelect) goto case LineBegin;
if (_rowSelect) goto case SelectDocumentBegin;
if (sc > nonScrollCols && _col > sc) {
multiSelectCell(sc, _lastSelectedCell.y, true);
} else {
if (sc > nonScrollCols) {
_scrollX = 0;
updateScrollBars();
invalidate();
}
multiSelectCell(_headerCols, _lastSelectedCell.y, true);
}
return true;
case LineBegin: case LineBegin:
if (sc > nonScrollCols && _col > sc && !_rowSelect) { if (_rowSelect) goto case DocumentBegin;
if (sc > nonScrollCols && _col > sc) {
// move selection and don's scroll // move selection and don's scroll
selectCell(sc, _row); selectCell(sc, _row);
} else { } else {
@ -1238,14 +1369,34 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
selectCell(_headerCols, _row); selectCell(_headerCols, _row);
} }
return true; return true;
case SelectLineEnd:
if (!_multiSelect) goto case LineEnd;
if (_rowSelect) goto case SelectDocumentEnd;
if (_col < lastScrollCol) {
// move selection and don's scroll
multiSelectCell(lastScrollCol, _lastSelectedCell.y, true);
} else {
multiSelectCell(_cols - 1, _lastSelectedCell.y, true);
}
return true;
case LineEnd: case LineEnd:
if (_col < lastScrollCol && !_rowSelect) { if (_rowSelect) goto case DocumentEnd;
if (_col < lastScrollCol) {
// move selection and don's scroll // move selection and don's scroll
selectCell(lastScrollCol, _row); selectCell(lastScrollCol, _row);
} else { } else {
selectCell(_cols - 1, _row); selectCell(_cols - 1, _row);
} }
return true; return true;
case SelectDocumentBegin:
if (!_multiSelect) goto case DocumentBegin;
if (_scrollY > 0) {
_scrollY = 0;
updateScrollBars();
invalidate();
}
multiSelectCell(_lastSelectedCell.x, _headerRows, true);
return true;
case DocumentBegin: case DocumentBegin:
if (_scrollY > 0) { if (_scrollY > 0) {
_scrollY = 0; _scrollY = 0;
@ -1254,18 +1405,64 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
} }
selectCell(_col, _headerRows); selectCell(_col, _headerRows);
return true; return true;
case SelectDocumentEnd:
if (!_multiSelect) goto case DocumentEnd;
multiSelectCell(_lastSelectedCell.x, _rows - 1, true);
return true;
case DocumentEnd: case DocumentEnd:
selectCell(_col, _rows - 1); selectCell(_col, _rows - 1);
return true; return true;
case SelectAll:
if (!_multiSelect) return true;
int endX = row;
if (_rowSelect) endX = 0;
for (int x = 0; x <= endX; ++x) {
for (int y = 0; y < rows; ++y) {
_selection.insert(Point(x, y));
}
}
invalidate();
return true;
case SelectPageBegin:
if (!_multiSelect) goto case PageBegin;
if (scrollRow > nonScrollRows)
multiSelectCell(_lastSelectedCell.x, scrollRow, true);
else
multiSelectCell(_lastSelectedCell.x, _headerRows, true);
return true;
case PageBegin: case PageBegin:
if (scrollRow > nonScrollRows) if (scrollRow > nonScrollRows)
selectCell(_col, scrollRow); selectCell(_col, scrollRow);
else else
selectCell(_col, _headerRows); selectCell(_col, _headerRows);
return true; return true;
case SelectPageEnd:
if (!_multiSelect) goto case PageEnd;
multiSelectCell(_lastSelectedCell.x, lastScrollRow, true);
return true;
case PageEnd: case PageEnd:
selectCell(_col, lastScrollRow); selectCell(_col, lastScrollRow);
return true; return true;
case SelectPageUp:
if (_row > sr) {
// not at top scrollable cell
multiSelectCell(_lastSelectedCell.x, sr, true);
} else {
// at top of scrollable area
if (scrollRow > nonScrollRows) {
// scroll up line by line
int prevRow = _row;
for (int i = prevRow - 1; i >= _headerRows; i--) {
multiSelectCell(_lastSelectedCell.x, i, true);
if (lastScrollRow <= prevRow)
break;
}
} else {
// scrolled to top - move upper cell
multiSelectCell(_lastSelectedCell.x, _headerRows, true);
}
}
return true;
case PageUp: case PageUp:
if (_row > sr) { if (_row > sr) {
// not at top scrollable cell // not at top scrollable cell
@ -1286,6 +1483,24 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
} }
} }
return true; return true;
case SelectPageDown:
if (_row < _rows - 1) {
int lr = lastScrollRow;
if (_row < lr) {
// not at bottom scrollable cell
multiSelectCell(_lastSelectedCell.x, lr, true);
} else {
// scroll down
int prevRow = _row;
for (int i = prevRow + 1; i < _rows; i++) {
multiSelectCell(_lastSelectedCell.x, i, true);
calcScrollableAreaPos();
if (scrollRow >= prevRow)
break;
}
}
}
return true;
case PageDown: case PageDown:
if (_row < _rows - 1) { if (_row < _rows - 1) {
int lr = lastScrollRow; int lr = lastScrollRow;
@ -1470,6 +1685,7 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
super(ID, hscrollbarMode, vscrollbarMode); super(ID, hscrollbarMode, vscrollbarMode);
_headerCols = 1; _headerCols = 1;
_headerRows = 1; _headerRows = 1;
_selection = new RedBlackTree!Point();
_defRowHeight = BACKEND_CONSOLE ? 1 : pointsToPixels(16); _defRowHeight = BACKEND_CONSOLE ? 1 : pointsToPixels(16);
_defColumnWidth = BACKEND_CONSOLE ? 7 : 100; _defColumnWidth = BACKEND_CONSOLE ? 7 : 100;
@ -1488,6 +1704,19 @@ class GridWidgetBase : ScrollWidgetBase, GridModelAdapter, MenuItemActionHandler
new Action(GridActions.PageEnd, KeyCode.PAGEDOWN, KeyFlag.Control), new Action(GridActions.PageEnd, KeyCode.PAGEDOWN, KeyFlag.Control),
new Action(GridActions.DocumentBegin, KeyCode.HOME, KeyFlag.Control), new Action(GridActions.DocumentBegin, KeyCode.HOME, KeyFlag.Control),
new Action(GridActions.DocumentEnd, KeyCode.END, KeyFlag.Control), new Action(GridActions.DocumentEnd, KeyCode.END, KeyFlag.Control),
new Action(GridActions.SelectUp, KeyCode.UP, KeyFlag.Shift),
new Action(GridActions.SelectDown, KeyCode.DOWN, KeyFlag.Shift),
new Action(GridActions.SelectLeft, KeyCode.LEFT, KeyFlag.Shift),
new Action(GridActions.SelectRight, KeyCode.RIGHT, KeyFlag.Shift),
new Action(GridActions.SelectLineBegin, KeyCode.HOME, KeyFlag.Shift),
new Action(GridActions.SelectLineEnd, KeyCode.END, KeyFlag.Shift),
new Action(GridActions.SelectPageUp, KeyCode.PAGEUP, KeyFlag.Shift),
new Action(GridActions.SelectPageDown, KeyCode.PAGEDOWN, KeyFlag.Shift),
new Action(GridActions.SelectPageBegin, KeyCode.PAGEUP, KeyFlag.Control | KeyFlag.Shift),
new Action(GridActions.SelectPageEnd, KeyCode.PAGEDOWN, KeyFlag.Control | KeyFlag.Shift),
new Action(GridActions.SelectDocumentBegin, KeyCode.HOME, KeyFlag.Control | KeyFlag.Shift),
new Action(GridActions.SelectDocumentEnd, KeyCode.END, KeyFlag.Control | KeyFlag.Shift),
new Action(GridActions.SelectAll, KeyCode.KEY_A, KeyFlag.Control),
new Action(GridActions.ActivateCell, KeyCode.RETURN, 0), new Action(GridActions.ActivateCell, KeyCode.RETURN, 0),
]); ]);
focusable = true; focusable = true;
@ -1673,6 +1902,9 @@ class StringGridWidget : StringGridWidgetBase {
bool selectedCell = selectedCol && selectedRow; bool selectedCell = selectedCol && selectedRow;
if (_rowSelect && selectedRow) if (_rowSelect && selectedRow)
selectedCell = true; selectedCell = true;
if (!selectedCell && _multiSelect) {
selectedCell = Point(c, r) in _selection || (_rowSelect && Point(0, r) in _selection);
}
// draw header cell background // draw header cell background
DrawableRef dw = c < 0 ? _cellRowHeaderBackgroundDrawable : _cellHeaderBackgroundDrawable; DrawableRef dw = c < 0 ? _cellRowHeaderBackgroundDrawable : _cellHeaderBackgroundDrawable;
uint cl = _cellHeaderBackgroundColor; uint cl = _cellHeaderBackgroundColor;
@ -1703,6 +1935,9 @@ class StringGridWidget : StringGridWidgetBase {
bool selectedCell = selectedCol && selectedRow; bool selectedCell = selectedCol && selectedRow;
if (_rowSelect && selectedRow) if (_rowSelect && selectedRow)
selectedCell = true; selectedCell = true;
if (!selectedCell && _multiSelect) {
selectedCell = Point(c, r) in _selection || (_rowSelect && Point(0, r) in _selection);
}
uint borderColor = _cellBorderColor; uint borderColor = _cellBorderColor;
if (c < fixedCols || r < fixedRows) { if (c < fixedCols || r < fixedRows) {
// fixed cell background // fixed cell background