grid mouse handling - select cell

This commit is contained in:
Vadim Lopatin 2014-06-03 16:57:29 +04:00
parent 1a849c1970
commit 305e020de7
3 changed files with 149 additions and 27 deletions

View File

@ -240,24 +240,44 @@ enum MouseAction : ubyte {
/// mouse flag bits /// mouse flag bits
enum MouseFlag : ushort { enum MouseFlag : ushort {
/// Ctrl key is down // mouse buttons
Control = 0x0008,
/// Left mouse button is down /// Left mouse button is down
LButton = 0x0001, LButton = 0x0001,
/// Middle mouse button is down /// Middle mouse button is down
MButton = 0x0010, MButton = 0x0010,
/// Right mouse button is down /// Right mouse button is down
RButton = 0x0002, RButton = 0x0002,
/// Shift key is down
Shift = 0x0004,
/// X1 mouse button is down /// X1 mouse button is down
XButton1= 0x0020, XButton1= 0x0020,
/// X2 mouse button is down /// X2 mouse button is down
XButton2= 0x0040, XButton2= 0x0040,
// keyboard modifiers
/// Ctrl key is down
Control = 0x0008,
/// Shift key is down
Shift = 0x0004,
/// Alt key is down /// Alt key is down
Alt = 0x0080 Alt = 0x0080,
} }
/// mouse button
enum MouseButton : ubyte {
/// no button
None,
/// left mouse button
Left = MouseFlag.LButton,
/// right mouse button
Right = MouseFlag.RButton,
/// right mouse button
Middle = MouseFlag.MButton,
/// additional mouse button 1
XButton1 = MouseFlag.XButton1, // additional button 1
/// additional mouse button 2
XButton2 = MouseFlag.XButton2, // additional button 2
}
/// mouse button state details /// mouse button state details
struct ButtonDetails { struct ButtonDetails {
/// Clock.currStdTime() for down event of this button (0 if button is up). /// Clock.currStdTime() for down event of this button (0 if button is up).
@ -297,22 +317,6 @@ struct ButtonDetails {
@property ushort downFlags() { return _downFlags; } @property ushort downFlags() { return _downFlags; }
} }
/// mouse button
enum MouseButton : ubyte {
/// no button
None,
/// left mouse button
Left,
/// right mouse button
Right,
/// right mouse button
Middle,
/// additional mouse button 1
XButton1, // additional button
/// additional mouse button 2
XButton2, // additional button
}
/// mouse event /// mouse event
class MouseEvent { class MouseEvent {
protected long _eventTimestamp; protected long _eventTimestamp;

View File

@ -41,8 +41,11 @@ module dlangui.core.types;
import std.algorithm; import std.algorithm;
/// 2D point
struct Point { struct Point {
/// x coordinate
int x; int x;
/// y coordinate
int y; int y;
this(int x0, int y0) { this(int x0, int y0) {
x = x0; x = x0;
@ -50,25 +53,35 @@ struct Point {
} }
} }
/// 2D rectangle
struct Rect { struct Rect {
/// x coordinate of top left corner
int left; int left;
/// y coordinate of top left corner
int top; int top;
/// x coordinate of bottom right corner
int right; int right;
/// y coordinate of bottom right corner
int bottom; int bottom;
/// returns average of left, right
@property int middlex() { return (left + right) / 2; } @property int middlex() { return (left + right) / 2; }
/// returns average of top, bottom
@property int middley() { return (top + bottom) / 2; } @property int middley() { return (top + bottom) / 2; }
/// add offset to horizontal and vertical coordinates
void offset(int dx, int dy) { void offset(int dx, int dy) {
left += dx; left += dx;
right += dx; right += dx;
top += dy; top += dy;
bottom += dy; bottom += dy;
} }
/// expand rectangle dimensions
void expand(int dx, int dy) { void expand(int dx, int dy) {
left -= dx; left -= dx;
right += dx; right += dx;
top -= dy; top -= dy;
bottom += dy; bottom += dy;
} }
/// shrink rectangle dimensions
void shrink(int dx, int dy) { void shrink(int dx, int dy) {
left += dx; left += dx;
right -= dx; right -= dx;
@ -97,6 +110,7 @@ struct Rect {
@property bool empty() { @property bool empty() {
return right <= left || bottom <= top; return right <= left || bottom <= top;
} }
/// translate rectangle coordinates by (x,y) - add deltax to x coordinates, and deltay to y coordinates
void moveBy(int deltax, int deltay) { void moveBy(int deltax, int deltay) {
left += deltax; left += deltax;
right += deltax; right += deltax;
@ -187,10 +201,13 @@ class RefCountedObject {
~this() {} ~this() {}
} }
/// reference counting
struct Ref(T) { // if (T is RefCountedObject) struct Ref(T) { // if (T is RefCountedObject)
private T _data; private T _data;
alias get this; alias get this;
/// returns true if object is not assigned
@property bool isNull() const { return _data is null; } @property bool isNull() const { return _data is null; }
/// returns counter of references
@property int refCount() const { return _data !is null ? _data.refCount : 0; } @property int refCount() const { return _data !is null ? _data.refCount : 0; }
this(T data) { this(T data) {
_data = data; _data = data;
@ -231,15 +248,18 @@ struct Ref(T) { // if (T is RefCountedObject)
_data.addRef(); _data.addRef();
return this; return this;
} }
/// clears reference
void clear() { void clear() {
if (_data !is null) { if (_data !is null) {
_data.releaseRef(); _data.releaseRef();
_data = null; _data = null;
} }
} }
/// returns object reference (null if not assigned)
@property T get() { @property T get() {
return _data; return _data;
} }
/// returns const reference from const object
@property const(T) get() const { @property const(T) get() const {
return _data; return _data;
} }
@ -249,8 +269,10 @@ struct Ref(T) { // if (T is RefCountedObject)
} }
} }
//================================================================================
// some utility functions // some utility functions
string fromStringz(const(char[]) s) { string fromStringz(const(char[]) s) {
if (s is null) if (s is null)
return null; return null;

View File

@ -125,6 +125,11 @@ class StringGridWidget : GridWidgetBase {
protected int _scrollCol; protected int _scrollCol;
/// row scroll offset, relative to last fixed row; 0 = not scrolled /// row scroll offset, relative to last fixed row; 0 = not scrolled
protected int _scrollRow; protected int _scrollRow;
/// selected cell column
protected int _col;
/// selected cell row
protected int _row;
this(string ID = null) { this(string ID = null) {
super(ID); super(ID);
_headerCols = 1; _headerCols = 1;
@ -135,6 +140,13 @@ class StringGridWidget : GridWidgetBase {
addChild(_hscrollbar); addChild(_hscrollbar);
styleId = "EDIT_BOX"; styleId = "EDIT_BOX";
resize(20, 30); 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;
}
}
} }
@property override int cols() { @property override int cols() {
return _cols; return _cols;
@ -202,7 +214,7 @@ class StringGridWidget : GridWidgetBase {
for (int i = _cols; i < cols; i++) { for (int i = _cols; i < cols; i++) {
if (i >= _headerCols) if (i >= _headerCols)
_data[0][i] = genColHeader(i - _headerCols); _data[0][i] = genColHeader(i - _headerCols);
_colWidths[i] = i == 0 ? 20 : 80; _colWidths[i] = i == 0 ? 20 : 100;
} }
_rowHeights.length = rows; _rowHeights.length = rows;
int fontHeight = font.height; int fontHeight = font.height;
@ -254,6 +266,82 @@ class StringGridWidget : GridWidgetBase {
} }
return rc; return rc;
} }
/// converts client rect relative coordinates to cell coordinates
bool pointToCell(int x, int y, ref int col, ref int row, ref Rect cellRect) {
col = row = -1;
cellRect = Rect();
Rect rc;
int xx = 0;
for (int i = 0; i < _cols; i++) {
rc.left = xx;
xx += colWidth(i);
rc.right = xx;
if (rc.left < rc.right && x >= rc.left && x < rc.right) {
col = i;
break;
}
if (xx > x)
break;
}
int yy = 0;
for (int i = 0; i < _rows; i++) {
rc.top = yy;
yy += rowHeight(i);
rc.bottom = yy;
if (rc.top < rc.bottom && y >= rc.top && y < rc.bottom) {
row = i;
break;
}
if (yy > y)
break;
}
if (col >= 0 && row >= 0) {
cellRect = rc;
return true;
}
return false;
}
/// handle mouse wheel events
override bool onMouseEvent(MouseEvent event) {
if (visibility != Visibility.Visible)
return false;
int c, r; // col, row
Rect rc;
bool cellFound = false;
bool normalCell = false;
// convert coordinates
if (event.action == MouseAction.ButtonUp || event.action == MouseAction.ButtonDown || event.action == MouseAction.Move) {
int x = event.x;
int y = event.y;
x -= _clientRect.left;
y -= _clientRect.top;
cellFound = pointToCell(x, y, c, r, rc);
normalCell = c >= _fixedCols && r >= _fixedRows;
}
if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
if (cellFound && normalCell) {
_col = c;
_row = r;
invalidate();
}
return true;
}
if (event.action == MouseAction.Move && (event.flags & MouseFlag.LButton)) {
// TODO: selection
if (cellFound && normalCell) {
_col = c;
_row = r;
invalidate();
}
return true;
}
return super.onMouseEvent(event);
}
/// returns row header title /// returns row header title
dstring rowTitle(int row) { dstring rowTitle(int row) {
return _rowTitles[row]; return _rowTitles[row];
@ -331,7 +419,7 @@ class StringGridWidget : GridWidgetBase {
/// draw cell content /// draw cell content
void drawCell(DrawBuf buf, Rect rc, int col, int row) { void drawCell(DrawBuf buf, Rect rc, int col, int row) {
rc.shrink(1, 1); rc.shrink(2, 1);
FontRef fnt = font; FontRef fnt = font;
dstring txt = cellText(col, row); dstring txt = cellText(col, row);
Point sz = fnt.textSize(txt); Point sz = fnt.textSize(txt);
@ -351,15 +439,23 @@ class StringGridWidget : GridWidgetBase {
vborder.left = vborder.right - 1; vborder.left = vborder.right - 1;
hborder.top = hborder.bottom - 1; hborder.top = hborder.bottom - 1;
hborder.right--; hborder.right--;
bool selectedCol = _col == col;
bool selectedRow = _row == row;
bool selectedCell = selectedCol && selectedRow;
if (col < _headerCols || row < _headerRows) { if (col < _headerCols || row < _headerRows) {
// draw header cell background // draw header cell background
buf.fillRect(rc, 0x80808080); uint cl = 0x80909090;
buf.fillRect(vborder, 0x80FFFFFF); if (selectedCol || selectedRow)
buf.fillRect(hborder, 0x80FFFFFF); cl = 0x80FFC040;
buf.fillRect(rc, cl);
buf.fillRect(vborder, 0x80202020);
buf.fillRect(hborder, 0x80202020);
} else { } else {
// normal cell background // normal cell background
buf.fillRect(vborder, 0x80C0C0C0); buf.fillRect(vborder, 0x80C0C0C0);
buf.fillRect(hborder, 0x80C0C0C0); buf.fillRect(hborder, 0x80C0C0C0);
if (selectedCell)
buf.drawFrame(rc, 0x404040FF, Rect(1,1,1,1), 0xC0FFFF00);
} }
} }