diff --git a/examples/example1/src/main.d b/examples/example1/src/main.d index b4717d58..b1767650 100644 --- a/examples/example1/src/main.d +++ b/examples/example1/src/main.d @@ -294,7 +294,7 @@ extern (C) int UIAppMain(string[] args) { caption = "Open Text File"d; FileDialog dlg = new FileDialog(caption, window); dlg.onDialogResult = delegate(Dialog dlg, Action result) { - // + Log.d("FileDialog.onDialogResult"); }; dlg.show(); return true; diff --git a/src/dlangui/core/events.d b/src/dlangui/core/events.d index 0f7b7193..d39ab105 100644 --- a/src/dlangui/core/events.d +++ b/src/dlangui/core/events.d @@ -309,25 +309,42 @@ enum MouseButton : ubyte { /// Mouse button state details for MouseEvent struct ButtonDetails { /// Clock.currStdTime() for down event of this button (0 if button is up). - long _downTs; + protected long _downTs; /// Clock.currStdTime() for up event of this button (0 if button is still down). - long _upTs; + protected long _upTs; /// x coordinates of down event - short _downX; + protected short _downX; /// y coordinates of down event - short _downY; + protected short _downY; /// mouse button flags when down event occured - ushort _downFlags; + protected ushort _downFlags; + /// true if button is made down shortly after up - valid if button is down + protected bool _doubleClick; + + /// Returns true if button is made down shortly after up + @property bool doubleClick() { + return _doubleClick; + } + + static final long DOUBLE_CLICK_THRESHOLD_MS = 200; + /// update for button down void down(short x, short y, ushort flags) { + //Log.d("Button down ", x, ",", y, " _downTs=", _downTs, " _upTs=", _upTs); + long oldDownTs = _downTs; _downX = x; _downY = y; _downFlags = flags; _upTs = 0; _downTs = std.datetime.Clock.currStdTime; + long downIntervalMs = (_downTs - oldDownTs) / 10000; + //Log.d("Button down ", x, ",", y, " _downTs=", _downTs, " _upTs=", _upTs, " downInterval=", downIntervalMs); + _doubleClick = (oldDownTs && downIntervalMs < DOUBLE_CLICK_THRESHOLD_MS); } /// update for button up void up(short x, short y, ushort flags) { + //Log.d("Button up ", x, ",", y, " _downTs=", _downTs, " _upTs=", _upTs); + _doubleClick = false; _upTs = std.datetime.Clock.currStdTime; } /// returns true if button is currently pressed @@ -383,6 +400,14 @@ class MouseEvent { @property ref ButtonDetails rbutton() { return _rbutton; } /// middle button state details @property ref ButtonDetails mbutton() { return _mbutton; } + /// button state details for event's button + @property ref ButtonDetails buttonDetails() { + if (_button == MouseButton.Right) + return _rbutton; + if (_button == MouseButton.Middle) + return _mbutton; + return _lbutton; + } /// button which caused ButtonUp or ButtonDown action @property MouseButton button() { return _button; } /// action @@ -397,6 +422,14 @@ class MouseEvent { @property short x() { return _x; } /// y coordinate of mouse pointer (relative to window client area) @property short y() { return _y; } + + /// Returns true for ButtonDown event when button is pressed second time in short interval after pressing first time + @property bool doubleClick() { + if (_action != MouseAction.ButtonDown) + return false; + return buttonDetails.doubleClick; + } + /// get event tracking widget to override @property Widget trackingWidget() { return _trackingWidget; } /// returns mouse button tracking flag diff --git a/src/dlangui/dialogs/filedlg.d b/src/dlangui/dialogs/filedlg.d index 747cd407..ebf9683f 100644 --- a/src/dlangui/dialogs/filedlg.d +++ b/src/dlangui/dialogs/filedlg.d @@ -69,11 +69,13 @@ class FileDialog : Dialog, CustomGridCellAdapter { protected DirEntry[] _entries; protected bool _isRoot; - this(UIString caption, Window parent, uint fileDialogFlags = DialogFlag.Modal | FileDialogFlag.FileMustExist) { + this(UIString caption, Window parent, uint fileDialogFlags = DialogFlag.Modal | DialogFlag.Resizable | FileDialogFlag.FileMustExist) { super(caption, parent, fileDialogFlags); } protected bool openDirectory(string dir) { + dir = buildNormalizedPath(dir); + Log.d("FileDialog.openDirectory(", dir, ")"); list.rows = 0; string[] filters; if (!listDirectory(dir, true, true, filters, _entries)) @@ -146,18 +148,27 @@ class FileDialog : Dialog, CustomGridCellAdapter { btn.orientation = Orientation.Vertical; btn.styleId = "TRANSPARENT_BUTTON_BACKGROUND"; btn.focusable = false; - btn.onClickListener = delegate(Widget source) { - openDirectory(root.path); - return true; - }; adapter.widgets.add(btn); } list.ownAdapter = adapter; list.layoutWidth = WRAP_CONTENT; list.layoutHeight = FILL_PARENT; + list.onItemClickListener = delegate(Widget source, int itemIndex) { + openDirectory(_roots[itemIndex].path); + return true; + }; return list; } + protected void onItemActivated(int index) { + DirEntry e = _entries[index]; + if (e.isDir) { + openDirectory(e.name); + } else if (e.isFile) { + } + + } + /// override to implement creation of dialog controls override void init() { _roots = getRootPaths; @@ -204,7 +215,15 @@ class FileDialog : Dialog, CustomGridCellAdapter { //Log.d("path: ", path); list.customCellAdapter = this; + list.onCellActivated = delegate(GridWidgetBase source, int col, int row) { + onItemActivated(row); + }; openDirectory(currentDir); + minWidth = 600; + minHeight = 400; + layoutWidth = FILL_PARENT; + list.layoutHeight = FILL_PARENT; + layoutHeight = FILL_PARENT; } } diff --git a/src/dlangui/platforms/sdl/sdlapp.d b/src/dlangui/platforms/sdl/sdlapp.d index a8ea4199..046e7a79 100644 --- a/src/dlangui/platforms/sdl/sdlapp.d +++ b/src/dlangui/platforms/sdl/sdlapp.d @@ -406,6 +406,23 @@ class SDLWindow : Window { event = new MouseEvent(action, btn, lastFlags, lastx, lasty); } if (event) { + ButtonDetails * pbuttonDetails = null; + if (button == MouseButton.Left) + pbuttonDetails = &_lbutton; + else if (button == MouseButton.Right) + pbuttonDetails = &_rbutton; + else if (button == MouseButton.Middle) + pbuttonDetails = &_mbutton; + if (pbuttonDetails) { + if (action == MouseAction.ButtonDown) { + pbuttonDetails.down(cast(short)x, cast(short)y, lastFlags); + } else if (action == MouseAction.ButtonUp) { + pbuttonDetails.up(cast(short)x, cast(short)y, lastFlags); + } + } + event.lbutton = _lbutton; + event.rbutton = _rbutton; + event.mbutton = _mbutton; bool res = dispatchMouseEvent(event); if (res) { debug(mouse) Log.d("Calling update() after mouse event"); diff --git a/src/dlangui/widgets/grid.d b/src/dlangui/widgets/grid.d index 150b250a..d71cbb85 100644 --- a/src/dlangui/widgets/grid.d +++ b/src/dlangui/widgets/grid.d @@ -202,6 +202,7 @@ enum GridActions : int { SelectDocumentEnd, } +/// Adapter for custom drawing of some cells in grid widgets interface CustomGridCellAdapter { /// return true for custom drawn cell bool isCustomCell(int col, int row); @@ -211,8 +212,23 @@ interface CustomGridCellAdapter { void drawCell(DrawBuf buf, Rect rc, int col, int row); } +/// Callback for handling of cell selection +interface CellSelectedHandler { + void onCellSelected(GridWidgetBase source, int col, int row); +} + +/// Callback for handling of cell double click or Enter key press +interface CellActivatedHandler { + void onCellActivated(GridWidgetBase source, int col, int row); +} + /// Abstract grid widget class GridWidgetBase : ScrollWidgetBase { + /// Callback to handle selection change + Listener!CellSelectedHandler onCellSelected; + /// Callback to handle cell double click + Listener!CellActivatedHandler onCellActivated; + protected CustomGridCellAdapter _customCellAdapter; /// Get adapter to override drawing of some particular cells @@ -589,6 +605,18 @@ class GridWidgetBase : ScrollWidgetBase { calcScrollableAreaPos(); if (makeVisible) makeCellVisible(_col, _row); + if (onCellSelected.assigned) + onCellSelected(this, _col, _row); + return true; + } + + /// Select cell and call onCellActivated handler + bool activateCell(int col, int row) { + if (_col != col || _row != row) { + selectCell(col, row, true); + } + if (onCellActivated.assigned) + onCellActivated(this, this.col, this.row); return true; } @@ -611,7 +639,11 @@ class GridWidgetBase : ScrollWidgetBase { } if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { if (cellFound && normalCell) { - selectCell(c, r); + if (c == _col && r == _row && event.doubleClick) { + activateCell(c, r); + } else { + selectCell(c, r); + } } return true; }