mirror of https://github.com/buggins/dlangui.git
editor: text hover timeout (tooltip) support
This commit is contained in:
parent
8e31308767
commit
7c435d772a
|
|
@ -627,6 +627,9 @@ class MouseEvent {
|
|||
/// y coordinate of mouse pointer (relative to window client area)
|
||||
@property short y() { return _y; }
|
||||
|
||||
/// returns point for mouse cursor position
|
||||
@property Point pos() { return Point(_x, _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)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,12 @@ struct Rect {
|
|||
@property int middley() { return (top + bottom) / 2; }
|
||||
/// returns middle point
|
||||
@property Point middle() { return Point(middlex, middley); }
|
||||
|
||||
/// returns top left point of rectangle
|
||||
@property Point topLeft() { return Point(left, top); }
|
||||
/// returns bottom right point of rectangle
|
||||
@property Point bottomRight() { return Point(right, bottom); }
|
||||
|
||||
/// add offset to horizontal and vertical coordinates
|
||||
void offset(int dx, int dy) {
|
||||
left += dx;
|
||||
|
|
|
|||
|
|
@ -520,7 +520,7 @@ struct SimpleTextFormatter {
|
|||
lineEndX = widths[lastWordEnd - 1];
|
||||
}
|
||||
// add line
|
||||
dstring line = cast(dstring)text[lineStart .. lastWordEnd];
|
||||
dstring line = cast(dstring)text[lineStart .. lineEnd]; //lastWordEnd];
|
||||
int lineWidth = lineEndX - lineStartX;
|
||||
sz.y += lineHeight;
|
||||
if (sz.x < lineWidth)
|
||||
|
|
|
|||
|
|
@ -862,6 +862,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
protected ulong _caretTimerId;
|
||||
protected bool _caretBlinkingPhase;
|
||||
protected long _lastBlinkStartTs;
|
||||
|
||||
protected void startCaretBlinking() {
|
||||
if (window) {
|
||||
long ts = currentTimeMillis;
|
||||
|
|
@ -876,6 +877,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
protected void stopCaretBlinking() {
|
||||
if (window) {
|
||||
if (_caretTimerId) {
|
||||
|
|
@ -884,6 +886,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// handle timer; return true to repeat timer event after next interval, false cancel timer
|
||||
override bool onTimer(ulong id) {
|
||||
if (id == _caretTimerId) {
|
||||
|
|
@ -893,18 +896,25 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
invalidate();
|
||||
return focused;
|
||||
}
|
||||
if (id == _hoverTimer) {
|
||||
cancelHoverTimer();
|
||||
onHoverTimeout(_hoverMousePosition, _hoverTextPosition);
|
||||
return false;
|
||||
}
|
||||
return super.onTimer(id);
|
||||
}
|
||||
|
||||
/// override to handle focus changes
|
||||
override protected void handleFocusChange(bool focused) {
|
||||
if (focused)
|
||||
startCaretBlinking();
|
||||
else
|
||||
else {
|
||||
stopCaretBlinking();
|
||||
cancelHoverTimer();
|
||||
}
|
||||
super.handleFocusChange(focused);
|
||||
}
|
||||
|
||||
|
||||
/// returns cursor rectangle
|
||||
protected Rect caretRect() {
|
||||
Rect caretRc = textPosToClient(_caretPos);
|
||||
|
|
@ -1546,6 +1556,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
/// handle keys
|
||||
override bool onKeyEvent(KeyEvent event) {
|
||||
if (focused) startCaretBlinking();
|
||||
cancelHoverTimer();
|
||||
bool ctrlOrAltPressed = false; //(event.flags & (KeyFlag.Control /* | KeyFlag.Alt */));
|
||||
if (event.action == KeyAction.Text && event.text.length && !ctrlOrAltPressed) {
|
||||
Log.d("text entered: ", event.text);
|
||||
|
|
@ -1568,20 +1579,53 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
|
||||
/// Handle Ctrl + Left mouse click on text
|
||||
protected void onControlClick() {
|
||||
// override to do something useful on Ctrl + Left mouse click in text
|
||||
}
|
||||
|
||||
protected TextPosition _hoverTextPosition;
|
||||
protected Point _hoverMousePosition;
|
||||
protected ulong _hoverTimer;
|
||||
protected long _hoverTimeoutMillis = 800;
|
||||
|
||||
/// override to handle mouse hover timeout in text
|
||||
protected void onHoverTimeout(Point pt, TextPosition pos) {
|
||||
// override to do something useful on hover timeout
|
||||
}
|
||||
|
||||
protected void onHover(Point pos) {
|
||||
if (_hoverMousePosition == pos)
|
||||
return;
|
||||
Log.d("onHover ", pos);
|
||||
int x = pos.x - left - _leftPaneWidth;
|
||||
int y = pos.y - top;
|
||||
_hoverMousePosition = pos;
|
||||
_hoverTextPosition = clientToTextPos(Point(x, y));
|
||||
cancelHoverTimer();
|
||||
_hoverTimer = setTimer(_hoverTimeoutMillis);
|
||||
}
|
||||
|
||||
protected void cancelHoverTimer() {
|
||||
if (_hoverTimer) {
|
||||
cancelTimer(_hoverTimer);
|
||||
_hoverTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// process mouse event; return true if event is processed by widget.
|
||||
override bool onMouseEvent(MouseEvent event) {
|
||||
//Log.d("onMouseEvent ", id, " ", event.action, " (", event.x, ",", event.y, ")");
|
||||
// support onClick
|
||||
if (event.action == MouseAction.ButtonDown && event.x < _clientRect.left && event.x >= _clientRect.left - _leftPaneWidth) {
|
||||
bool insideLeftPane = event.x < _clientRect.left && event.x >= _clientRect.left - _leftPaneWidth;
|
||||
if (event.action == MouseAction.ButtonDown && insideLeftPane) {
|
||||
setFocus();
|
||||
cancelHoverTimer();
|
||||
if (onLeftPaneMouseClick(event))
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
|
||||
setFocus();
|
||||
startCaretBlinking();
|
||||
cancelHoverTimer();
|
||||
if (event.doubleClick) {
|
||||
selectWordByMouse(event.x - _clientRect.left, event.y - _clientRect.top);
|
||||
} else {
|
||||
|
|
@ -1596,16 +1640,29 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
updateCaretPositionByMouse(event.x - _clientRect.left, event.y - _clientRect.top, true);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.Move && event.flags == 0) {
|
||||
// hover
|
||||
if (focused && !insideLeftPane) {
|
||||
onHover(event.pos);
|
||||
} else {
|
||||
cancelHoverTimer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) {
|
||||
cancelHoverTimer();
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {
|
||||
cancelHoverTimer();
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.FocusIn) {
|
||||
cancelHoverTimer();
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.Wheel) {
|
||||
cancelHoverTimer();
|
||||
uint keyFlags = event.flags & (MouseFlag.Shift | MouseFlag.Control | MouseFlag.Alt);
|
||||
if (event.wheelDelta < 0) {
|
||||
if (keyFlags == MouseFlag.Shift)
|
||||
|
|
@ -1621,6 +1678,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
return handleAction(new Action(EditorActions.ScrollLineUp));
|
||||
}
|
||||
}
|
||||
cancelHoverTimer();
|
||||
return super.onMouseEvent(event);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ enum PopupAlign : uint {
|
|||
Center = 1,
|
||||
/// place popup below anchor widget close to lower bound
|
||||
Below = 2,
|
||||
/// place popup below anchor widget close to lower bound
|
||||
Above = 16,
|
||||
/// place popup below anchor widget close to right bound (when no space enough, align near left bound)
|
||||
Right = 4,
|
||||
/// align to specified point
|
||||
|
|
@ -52,6 +54,8 @@ enum PopupFlags : uint {
|
|||
CloseOnClickOutside = 1,
|
||||
/// modal popup - keypresses and mouse events can be routed to this popup only
|
||||
Modal = 2,
|
||||
/// close popup when mouse is moved outside this popup
|
||||
CloseOnMouseMoveOutside = 4,
|
||||
}
|
||||
|
||||
/** interface - slot for onPopupCloseListener */
|
||||
|
|
@ -124,6 +128,15 @@ class PopupWidget : LinearLayout {
|
|||
if (anchor.alignment & PopupAlign.Point) {
|
||||
r.left = anchor.x;
|
||||
r.top = anchor.y;
|
||||
if (anchor.alignment & PopupAlign.Center) {
|
||||
// center around center of anchor widget
|
||||
r.left -= w / 2;
|
||||
r.top -= h / 2;
|
||||
} else if (anchor.alignment & PopupAlign.Below) {
|
||||
} else if (anchor.alignment & PopupAlign.Above) {
|
||||
r.top -= h;
|
||||
} else if (anchor.alignment & PopupAlign.Right) {
|
||||
}
|
||||
} else {
|
||||
if (anchor.alignment & PopupAlign.Center) {
|
||||
// center around center of anchor widget
|
||||
|
|
@ -132,6 +145,9 @@ class PopupWidget : LinearLayout {
|
|||
} else if (anchor.alignment & PopupAlign.Below) {
|
||||
r.left = anchorrc.left;
|
||||
r.top = anchorrc.bottom;
|
||||
} else if (anchor.alignment & PopupAlign.Above) {
|
||||
r.left = anchorrc.left;
|
||||
r.top = anchorrc.top - h;
|
||||
} else if (anchor.alignment & PopupAlign.Right) {
|
||||
r.left = anchorrc.right;
|
||||
r.top = anchorrc.top;
|
||||
|
|
@ -164,6 +180,16 @@ class PopupWidget : LinearLayout {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (_flags & PopupFlags.CloseOnMouseMoveOutside) {
|
||||
if (event.action == MouseAction.Move || event.action == MouseAction.Wheel) {
|
||||
int threshold = 3;
|
||||
if (event.x < _pos.left - threshold || event.x > _pos.right + threshold || event.y < _pos.top - threshold || event.y > _pos.bottom + threshold) {
|
||||
Log.d("Closing popup due to PopupFlags.CloseOnMouseMoveOutside flag");
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,6 +121,13 @@ class ScrollWidgetBase : WidgetGroup, OnScrollHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/// vertical scrollbar mode
|
||||
@property ScrollBarMode vscrollbarMode() { return _vscrollbarMode; }
|
||||
@property void vscrollbarMode(ScrollBarMode m) { _vscrollbarMode = m; }
|
||||
/// horizontal scrollbar mode
|
||||
@property ScrollBarMode hscrollbarMode() { return _hscrollbarMode; }
|
||||
@property void hscrollbarMode(ScrollBarMode m) { _hscrollbarMode = m; }
|
||||
|
||||
/// returns client area rectangle
|
||||
@property Rect clientRect() { return _clientRect; }
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue