From 5b358236f2de489a6d7bffd423a63f62f80cfb90 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 18 Mar 2014 11:45:33 +0400 Subject: [PATCH] fix mouse processing --- src/dlangui/platforms/common/platform.d | 19 +- src/dlangui/platforms/x11/x11app.d | 58 +++-- src/dlangui/widgets/controls.d | 318 ++++++++++++------------ 3 files changed, 214 insertions(+), 181 deletions(-) diff --git a/src/dlangui/platforms/common/platform.d b/src/dlangui/platforms/common/platform.d index 13966928..97165a2b 100644 --- a/src/dlangui/platforms/common/platform.d +++ b/src/dlangui/platforms/common/platform.d @@ -113,7 +113,17 @@ class Window { protected Widget _mouseTrackingWidget; /// widget which tracks all events after processed ButtonDown protected Widget _mouseCaptureWidget; + protected ushort _mouseCaptureButtons; protected bool _mouseCaptureFocusedOut; + + protected bool dispatchCancel(MouseEvent event) { + event.changeAction(MouseAction.Cancel); + bool res = _mouseCaptureWidget.onMouseEvent(event); + _mouseCaptureWidget = null; + _mouseCaptureFocusedOut = false; + return res; + } + /// dispatch mouse event to window content widgets bool dispatchMouseEvent(MouseEvent event) { // ignore events if there is no root @@ -127,23 +137,29 @@ class Window { _mouseTrackingWidget = null; bool res = false; + ushort currentButtons = event.flags & (MouseFlag.LButton|MouseFlag.RButton|MouseFlag.MButton); if (_mouseCaptureWidget !is null) { // try to forward message directly to active widget if (event.action == MouseAction.Move) { if (!_mouseCaptureWidget.isPointInside(event.x, event.y)) { + if (currentButtons != _mouseCaptureButtons) + return dispatchCancel(event); // point is no more inside of captured widget if (!_mouseCaptureFocusedOut) { // sending FocusOut message event.changeAction(MouseAction.FocusOut); _mouseCaptureFocusedOut = true; + _mouseCaptureButtons = event.flags & (MouseFlag.LButton|MouseFlag.RButton|MouseFlag.MButton); return _mouseCaptureWidget.onMouseEvent(event); } return true; } else { // point is inside widget if (_mouseCaptureFocusedOut) { - event.changeAction(MouseAction.FocusIn); // back in after focus out _mouseCaptureFocusedOut = false; + if (currentButtons != _mouseCaptureButtons) + return dispatchCancel(event); + event.changeAction(MouseAction.FocusIn); // back in after focus out } return _mouseCaptureWidget.onMouseEvent(event); } @@ -152,6 +168,7 @@ class Window { // sending FocusOut message event.changeAction(MouseAction.FocusOut); _mouseCaptureFocusedOut = true; + _mouseCaptureButtons = event.flags & (MouseFlag.LButton|MouseFlag.RButton|MouseFlag.MButton); return _mouseCaptureWidget.onMouseEvent(event); } return true; diff --git a/src/dlangui/platforms/x11/x11app.d b/src/dlangui/platforms/x11/x11app.d index 813749f2..b409bdf3 100644 --- a/src/dlangui/platforms/x11/x11app.d +++ b/src/dlangui/platforms/x11/x11app.d @@ -34,24 +34,6 @@ version(linux) { Log.d("Destroying window"); } - /// request window redraw - override void invalidate() { - - xcb_expose_event_t * event = cast(xcb_expose_event_t*)std.c.stdlib.malloc(xcb_expose_event_t.sizeof); - event.response_type = XCB_EXPOSE; /* The type of the event, here it is XCB_EXPOSE */ - event.sequence = 0; - event.window = _w; /* The Id of the window that receives the event (in case */ - /* our application registered for events on several windows */ - event.x = 0; /* The x coordinate of the top-left part of the window that needs to be redrawn */ - event.y = 0; /* The y coordinate of the top-left part of the window that needs to be redrawn */ - event.width = cast(ushort)_dx; /* The width of the part of the window that needs to be redrawn */ - event.height = cast(ushort)_dy; /* The height of the part of the window that needs to be redrawn */ - event.count = 1; - - xcb_void_cookie_t res = xcb_send_event(_xcbconnection, false, _w, XCB_EVENT_MASK_EXPOSURE, cast(char *)event); - xcb_flush(_xcbconnection); - } - bool create() { uint mask; uint values[2]; @@ -209,10 +191,32 @@ version(linux) { } ColorDrawBuf _drawbuf; + bool _exposeSent; void processExpose(xcb_expose_event_t * event) { redraw(); + _exposeSent = false; } - + + /// request window redraw + override void invalidate() { + if (_exposeSent) + return; + _exposeSent = true; + xcb_expose_event_t * event = cast(xcb_expose_event_t*)std.c.stdlib.malloc(xcb_expose_event_t.sizeof); + event.response_type = XCB_EXPOSE; /* The type of the event, here it is XCB_EXPOSE */ + event.sequence = 0; + event.window = _w; /* The Id of the window that receives the event (in case */ + /* our application registered for events on several windows */ + event.x = 0; /* The x coordinate of the top-left part of the window that needs to be redrawn */ + event.y = 0; /* The y coordinate of the top-left part of the window that needs to be redrawn */ + event.width = cast(ushort)_dx; /* The width of the part of the window that needs to be redrawn */ + event.height = cast(ushort)_dy; /* The height of the part of the window that needs to be redrawn */ + event.count = 1; + + xcb_void_cookie_t res = xcb_send_event(_xcbconnection, false, _w, XCB_EVENT_MASK_EXPOSURE, cast(char *)event); + xcb_flush(_xcbconnection); + } + protected ButtonDetails _lbutton; protected ButtonDetails _mbutton; protected ButtonDetails _rbutton; @@ -238,14 +242,20 @@ version(linux) { case 1: button = MouseButton.Left; pbuttonDetails = &_lbutton; + if (action == MouseAction.ButtonDown) + flags |= MouseFlag.LButton; break; case 2: button = MouseButton.Middle; pbuttonDetails = &_mbutton; + if (action == MouseAction.ButtonDown) + flags |= MouseFlag.MButton; break; case 3: button = MouseButton.Right; pbuttonDetails = &_rbutton; + if (action == MouseAction.ButtonDown) + flags |= MouseFlag.RButton; break; case 4: if (action == MouseAction.ButtonUp) @@ -464,8 +474,14 @@ version(linux) { } case XCB_LEAVE_NOTIFY: { xcb_leave_notify_event_t *leave = cast(xcb_leave_notify_event_t *)e; - - Log.d("XCB_LEAVE_NOTIFY ", leave.event, " at coords ", leave.event_x, ", ", leave.event_y); + Log.d("XCB_LEAVE_NOTIFY ", leave.event, " at coords ", leave.event_x, ", ", leave.event_y); + XCBWindow window = getWindow(leave.event); + if (window !is null) { + // + window.processMouseEvent(MouseAction.Leave, 0, leave.state, leave.event_x, leave.event_y); + } else { + Log.w("Received message for unknown window", leave.event); + } break; } case XCB_KEY_PRESS: { diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d index 7819bc32..67c0e2d5 100644 --- a/src/dlangui/widgets/controls.d +++ b/src/dlangui/widgets/controls.d @@ -1,159 +1,159 @@ -module dlangui.widgets.controls; - -import dlangui.widgets.widget; - -/// static text widget -class TextWidget : Widget { - this(string ID = null) { - super(ID); - styleId = "TEXT"; - } - protected dstring _text; - /// get widget text - override @property dstring text() { return _text; } - /// set text to show - override @property Widget text(dstring s) { - _text = s; - requestLayout(); - return this; - } - - override void measure(int parentWidth, int parentHeight) { - FontRef font = font(); - Point sz = font.textSize(text); - measuredContent(parentWidth, parentHeight, sz.x, sz.y); - } - - bool onClick() { - // override it - Log.d("Button.onClick ", id); - return false; - } - - override void onDraw(DrawBuf buf) { - if (visibility != Visibility.Visible) - return; - super.onDraw(buf); - Rect rc = _pos; - applyMargins(rc); - ClipRectSaver(buf, rc); - applyPadding(rc); - FontRef font = font(); - Point sz = font.textSize(text); - applyAlign(rc, sz); - font.drawText(buf, rc.left, rc.top, text, textColor); - } -} - -/// image widget -class ImageWidget : Widget { - - protected string _drawableId; - protected DrawableRef _drawable; - - this(string ID = null) { - super(ID); - } - - /// get drawable image id - @property string drawableId() { return _drawableId; } - /// set drawable image id - @property ImageWidget drawableId(string id) { - _drawableId = id; - _drawable.clear(); - requestLayout(); - return this; - } - /// get drawable - @property ref DrawableRef drawable() { - if (!_drawable.isNull) - return _drawable; - if (_drawableId !is null) - _drawable = drawableCache.get(_drawableId); - return _drawable; - } - /// set custom drawable (not one from resources) - @property ImageWidget drawable(DrawableRef img) { - _drawable = img; - _drawableId = null; - return this; - } - - override void measure(int parentWidth, int parentHeight) { - DrawableRef img = drawable; - int w = 0; - int h = 0; - if (!img.isNull) { - w = img.width; - h = img.height; - } - measuredContent(parentWidth, parentHeight, w, h); - } - override void onDraw(DrawBuf buf) { - if (visibility != Visibility.Visible) - return; - super.onDraw(buf); - Rect rc = _pos; - applyMargins(rc); - ClipRectSaver(buf, rc); - applyPadding(rc); - DrawableRef img = drawable; - if (!img.isNull) { - Point sz; - sz.x = img.width; - sz.y = img.height; - applyAlign(rc, sz); - img.drawTo(buf, rc); - } - } -} - -class Button : Widget { - protected dstring _text; - override @property dstring text() { return _text; } - override @property Widget text(dstring s) { _text = s; requestLayout(); return this; } - this(string ID = null) { - super(ID); - styleId = "BUTTON"; - } - override void measure(int parentWidth, int parentHeight) { - FontRef font = font(); - Point sz = font.textSize(text); - measuredContent(parentWidth, parentHeight, sz.x, sz.y); - } - override void onDraw(DrawBuf buf) { - super.onDraw(buf); - Rect rc = _pos; - applyMargins(rc); - buf.fillRect(_pos, backgroundColor); - applyPadding(rc); - ClipRectSaver(buf, rc); - FontRef font = font(); - Point sz = font.textSize(text); - applyAlign(rc, sz); - font.drawText(buf, rc.left, rc.top, text, textColor); - } - - override bool onMouseEvent(MouseEvent event) { - if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { - setState(State.Pressed); - Log.d("Button state: ", state); - return true; - } - if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) { - resetState(State.Pressed); - Log.d("Button state: ", state); - return true; - } - if (event.action == MouseAction.FocusOut) { - resetState(State.Pressed); - return true; - } - if (event.action == MouseAction.FocusIn) { - setState(State.Pressed); - return true; - } - return false; - } - -} +module dlangui.widgets.controls; + +import dlangui.widgets.widget; + +/// static text widget +class TextWidget : Widget { + this(string ID = null) { + super(ID); + styleId = "TEXT"; + } + protected dstring _text; + /// get widget text + override @property dstring text() { return _text; } + /// set text to show + override @property Widget text(dstring s) { + _text = s; + requestLayout(); + return this; + } + + override void measure(int parentWidth, int parentHeight) { + FontRef font = font(); + Point sz = font.textSize(text); + measuredContent(parentWidth, parentHeight, sz.x, sz.y); + } + + bool onClick() { + // override it + Log.d("Button.onClick ", id); + return false; + } + + override void onDraw(DrawBuf buf) { + if (visibility != Visibility.Visible) + return; + super.onDraw(buf); + Rect rc = _pos; + applyMargins(rc); + ClipRectSaver(buf, rc); + applyPadding(rc); + FontRef font = font(); + Point sz = font.textSize(text); + applyAlign(rc, sz); + font.drawText(buf, rc.left, rc.top, text, textColor); + } +} + +/// image widget +class ImageWidget : Widget { + + protected string _drawableId; + protected DrawableRef _drawable; + + this(string ID = null) { + super(ID); + } + + /// get drawable image id + @property string drawableId() { return _drawableId; } + /// set drawable image id + @property ImageWidget drawableId(string id) { + _drawableId = id; + _drawable.clear(); + requestLayout(); + return this; + } + /// get drawable + @property ref DrawableRef drawable() { + if (!_drawable.isNull) + return _drawable; + if (_drawableId !is null) + _drawable = drawableCache.get(_drawableId); + return _drawable; + } + /// set custom drawable (not one from resources) + @property ImageWidget drawable(DrawableRef img) { + _drawable = img; + _drawableId = null; + return this; + } + + override void measure(int parentWidth, int parentHeight) { + DrawableRef img = drawable; + int w = 0; + int h = 0; + if (!img.isNull) { + w = img.width; + h = img.height; + } + measuredContent(parentWidth, parentHeight, w, h); + } + override void onDraw(DrawBuf buf) { + if (visibility != Visibility.Visible) + return; + super.onDraw(buf); + Rect rc = _pos; + applyMargins(rc); + ClipRectSaver(buf, rc); + applyPadding(rc); + DrawableRef img = drawable; + if (!img.isNull) { + Point sz; + sz.x = img.width; + sz.y = img.height; + applyAlign(rc, sz); + img.drawTo(buf, rc); + } + } +} + +class Button : Widget { + protected dstring _text; + override @property dstring text() { return _text; } + override @property Widget text(dstring s) { _text = s; requestLayout(); return this; } + this(string ID = null) { + super(ID); + styleId = "BUTTON"; + } + override void measure(int parentWidth, int parentHeight) { + FontRef font = font(); + Point sz = font.textSize(text); + measuredContent(parentWidth, parentHeight, sz.x, sz.y); + } + override void onDraw(DrawBuf buf) { + super.onDraw(buf); + Rect rc = _pos; + applyMargins(rc); + buf.fillRect(_pos, backgroundColor); + applyPadding(rc); + ClipRectSaver(buf, rc); + FontRef font = font(); + Point sz = font.textSize(text); + applyAlign(rc, sz); + font.drawText(buf, rc.left, rc.top, text, textColor); + } + + override bool onMouseEvent(MouseEvent event) { + if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) { + setState(State.Pressed); + Log.d("Button state: ", state); + return true; + } + if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) { + resetState(State.Pressed); + Log.d("Button state: ", state); + return true; + } + if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) { + resetState(State.Pressed); + return true; + } + if (event.action == MouseAction.FocusIn) { + setState(State.Pressed); + return true; + } + return false; + } + +}