diff --git a/graphics/twm4nx/src/cwindow.cxx b/graphics/twm4nx/src/cwindow.cxx index 73f668f08..fc45dd8a2 100644 --- a/graphics/twm4nx/src/cwindow.cxx +++ b/graphics/twm4nx/src/cwindow.cxx @@ -160,7 +160,8 @@ CWindow::CWindow(CTwm4Nx *twm4nx) // Dragging - m_drag = false; + m_clicked = false; + m_dragging = false; m_dragPos.x = 0; m_dragPos.y = 0; m_dragCSize.w = 0; @@ -679,6 +680,7 @@ bool CWindow::createMainWindow(FAR const nxgl_size_s *winsize, // handler FAR CWindowEvent *control = new CWindowEvent(m_twm4nx, (FAR void *)this); + control->registerDragEventHandler(this, (uintptr_t)1); // 4. Create the window @@ -769,7 +771,7 @@ bool CWindow::createToolbar(void) // style for now. CWindowEvent derives from CWidgetControl. FAR CWindowEvent *control = new CWindowEvent(m_twm4nx, (FAR void *)this); - control->registerDragEventHandler(this); + control->registerDragEventHandler(this, (uintptr_t)0); // 3. Get the toolbar sub-window from the framed window @@ -1190,7 +1192,7 @@ void CWindow::handleClickEvent(const NXWidgets::CWidgetEventArgs &e) // We are interested only the the press event on the title box and // only if we are not already dragging the window - if (!m_drag && m_tbTitle->isClicked()) + if (!m_dragging && m_tbTitle->isClicked()) { // Generate the event @@ -1231,7 +1233,7 @@ void CWindow::handleReleaseEvent(const NXWidgets::CWidgetEventArgs &e) // Handle the case where a release event was received, but the // window was not dragged. - if (m_drag && !m_tbTitle->isClicked()) + if (m_dragging && !m_tbTitle->isClicked()) { // A click with no drag should raise the window. @@ -1299,27 +1301,33 @@ void CWindow::handleActionEvent(const NXWidgets::CWidgetEventArgs &e) * * @param pos The current mouse/touch X/Y position in toolbar relative * coordinates. - * @return True: if the drage event was processed; false it is was + * @return True: if the drag event was processed; false it is was * ignored. The event should be ignored if there is not actually * a drag event in progress */ -bool CWindow::dragEvent(FAR const struct nxgl_point_s &pos) +bool CWindow::dragEvent(FAR const struct nxgl_point_s &pos, + uintptr_t arg) { - twminfo("m_drag=%u pos=(%d,%d)\n", m_drag, pos.x, pos.y); + twminfo("m_dragging=%u pos=(%d,%d)\n", m_dragging, pos.x, pos.y); // We are interested only the drag event while we are in the dragging // state. - if (m_drag) + if (m_dragging) { - // Conver the + // arg == 0 means that this a tooolbar event vs s main window event. + // Since the position is relative in both cases, we need a fix-up in + // the height to keep the same toolbar relative position in all cases. + + nxgl_coord_t yIncr = ((arg == 0) ? 0 : m_tbHeight); + // Generate the event struct SEventMsg msg; msg.eventID = EVENT_WINDOW_DRAG; msg.pos.x = pos.x; - msg.pos.y = pos.y; + msg.pos.y = pos.y + yIncr; msg.context = EVENT_CONTEXT_TOOLBAR; msg.handler = (FAR CTwm4NxEvent *)0; msg.obj = (FAR void *)this; @@ -1353,14 +1361,15 @@ bool CWindow::dragEvent(FAR const struct nxgl_point_s &pos) * * @param pos The last mouse/touch X/Y position in toolbar relative * coordinates. - * @return True: if the drage event was processed; false it is was + * @return True: If the drag event was processed; false it is was * ignored. The event should be ignored if there is not actually * a drag event in progress */ -bool CWindow::dropEvent(FAR const struct nxgl_point_s &pos) +bool CWindow::dropEvent(FAR const struct nxgl_point_s &pos, + uintptr_t arg) { - twminfo("m_drag=%u pos=(%d,%d)\n", m_drag, pos.x, pos.y); + twminfo("m_dragging=%u pos=(%d,%d)\n", m_dragging, pos.x, pos.y); // We are interested only the the drag drop event on the title box while we // are in the dragging state. @@ -1369,17 +1378,47 @@ bool CWindow::dropEvent(FAR const struct nxgl_point_s &pos) // will return false. It is sufficient to verify that the isClicked() is // not true to exit the drag. - if (m_drag) + if (m_dragging) { // Yes.. handle the drop event - handleUngrabEvent(pos.x, pos.y); + // arg == 0 means that this a tooolbar event vs s main window event. + // Since the position is relative in both cases, we need a fix-up in + // the height to keep the same toolbar relative position in all cases. + + nxgl_coord_t yIncr = ((arg == 0) ? 0 : m_tbHeight); + + handleUngrabEvent(pos.x, pos.y + yIncr); return true; } return false; } +/** + * Is dragging enabled? + * + * @param arg The user-argument provided that accompanies the callback + * @return True: If the dragging is enabled. + */ + +bool CWindow::isDragging(uintptr_t arg) +{ + return m_clicked; +} + +/** + * Enable/disable dragging + * + * @param enable. True: Enable dragging + * @param arg The user-argument provided that accompanies the callback + */ + +void CWindow::setDragging(bool enable, uintptr_t arg) +{ + m_clicked = enable; +} + /** * Handle the TOOLBAR_GRAB event. That corresponds to a left * mouse click on the title widget in the toolbar @@ -1400,7 +1439,7 @@ bool CWindow::toolbarGrab(FAR struct SEventMsg *eventmsg) // Indicate that dragging has started. - m_drag = true; + m_dragging = true; // Get the frame position. @@ -1442,7 +1481,7 @@ bool CWindow::windowDrag(FAR struct SEventMsg *eventmsg) { twminfo("DRAG (%d,%d)\n", eventmsg->pos.x, eventmsg->pos.y); - if (m_drag) + if (m_dragging) { // The coordinates in the eventmsg or relative to the origin // of the toolbar. @@ -1535,7 +1574,7 @@ bool CWindow::toolbarUngrab(FAR struct SEventMsg *eventmsg) // Indicate no longer dragging - m_drag = false; + m_dragging = false; // No longer modal diff --git a/graphics/twm4nx/src/cwindowevent.cxx b/graphics/twm4nx/src/cwindowevent.cxx index 5a38683aa..19cc4a941 100644 --- a/graphics/twm4nx/src/cwindowevent.cxx +++ b/graphics/twm4nx/src/cwindowevent.cxx @@ -82,7 +82,7 @@ CWindowEvent::CWindowEvent(FAR CTwm4Nx *twm4nx, FAR void *obj, // Dragging m_dragHandler = (FAR IDragEvent *)0; // No drag handler callbacks - m_dragging = false; // Not dragging + m_dragArg = (uintptr_t)0; // No callback argument // Open a message queue to send raw NX events. This cannot fail! @@ -214,87 +214,97 @@ void CWindowEvent::handleRedrawEvent(FAR const nxgl_rect_s *nxRect, #ifdef CONFIG_NX_XYINPUT /** * Handle an NX window mouse input event. + * + * One complexity is that with framed windows, the click starts in the + * toolbar, but can easily move into the main window (or even outside + * of the window!). To these case, there may be two instances of + * CWindowEvent, one for the toolbar and one for the main window. The + * IDragEvent implementation (along with the user arguement) can keep a + * consistent drag context across both instances. + * + * NOTE: NX will continually forward the mouse events to the same raw + * window in all cases.. even when the mouse position moves outside of + * the window. It is the NxTK layer that converts the reports mouse + * event to either toolar or main window reports. */ void CWindowEvent::handleMouseEvent(FAR const struct nxgl_point_s *pos, uint8_t buttons) { - twminfo("Mouse input: m_dragging=%u\n", m_dragging); + // Check if dragging can be supported - // Check if are dragging - // - // STATE LEFT BUTTON ACTION - // dragging clicked dragEvent - // dragging released dropEvent - // NOT dragging clicked May be detected as a grab - // NOT dragging released None - - if (m_dragging) + if (m_dragHandler != (FAR IDragEvent *)0) { - // Save the new drag position in window relative display coordinates + twminfo("Mouse input: dragging=%u\n", + m_dragHandler->isDragging(m_dragArg)); - m_dragPos.x = pos->x; - m_dragPos.y = pos->y; + // STATE LEFT BUTTON ACTION + // dragging clicked dragEvent + // dragging released dropEvent + // NOT dragging clicked May be detected as a grab + // NOT dragging released None - // Is the left button still pressed? - - if ((buttons & MOUSE_BUTTON_1) != 0) + if (m_dragHandler->isDragging(m_dragArg)) { - twminfo("Continue dragging (%d,%d) buttons=%02x m_dragHandler=%p\n", - m_dragPos.x, m_dragPos.y, buttons, m_dragHandler); + // The new drag position in window relative display coordinates - // Yes.. generate a drag event if we have a drag event handler + struct nxgl_point_s dragPos; + dragPos.x = pos->x; + dragPos.y = pos->y; - if (m_dragHandler != (FAR IDragEvent *)0 && - m_dragHandler->dragEvent(m_dragPos)) + // Is the left button still pressed? + + if ((buttons & MOUSE_BUTTON_1) != 0) { - // Skip the input poll until the drag completes + twminfo("Continue dragging (%d,%d) buttons=%02x m_dragHandler=%p\n", + dragPos.x, dragPos.y, buttons, m_dragHandler); - return; + // Yes.. generate a drag event if we have a drag event handler + + if (m_dragHandler->dragEvent(dragPos, m_dragArg)) + { + // Skip the input poll until the drag completes + + return; + } + } + else + { + twminfo("Stop dragging (%d,%d) buttons=%02x m_dragHandler=%p\n", + dragPos.x, dragPos.y, buttons, m_dragHandler); + + // No.. then we are no longer dragging + + m_dragHandler->setDragging(false, m_dragArg); + + // Generate a dropEvent + + if (m_dragHandler->dropEvent(dragPos, m_dragArg)) + { + // If the drop event was processed then skip the + // input poll until AFTER the drag completes + + return; + } } } - else + + // If we are not currently dragging but the left button is pressed, then + // start the drag event + + else if ((buttons & MOUSE_BUTTON_1) != 0) { - twminfo("Stop dragging (%d,%d) buttons=%02x m_dragHandler=%p\n", - m_dragPos.x, m_dragPos.y, buttons, m_dragHandler); + // Indicate that we are (or may be) dragging - // No.. then we are no longer dragging + m_dragHandler->setDragging(true, m_dragArg); - m_dragging = false; + twminfo("Start dragging (%d,%d) buttons=%02x m_dragHandler=%p\n", + pos->x, pos->y, buttons, m_dragHandler); - // Generate a dropEvent - - if (m_dragHandler != (FAR IDragEvent *)0 && - m_dragHandler->dropEvent(m_dragPos)) - { - // If the drop event was processed then skip the - // input poll until AFTER the drag completes - - return; - } + // But take no other actions until the window recognizes the grab } } - // If we are not currently dragging but the left button is pressed, then - // start the drag event - - else if ((buttons & MOUSE_BUTTON_1) != 0) - { - // Indicate that we are (or may be) dragging - - m_dragging = true; - - // Save the initial drag position - - m_dragPos.x = pos->x; - m_dragPos.y = pos->y; - - twminfo("Start dragging (%d,%d) buttons=%02x m_dragHandler=%p\n", - m_dragPos.x, m_dragPos.y, buttons, m_dragHandler); - - // But take no other actions until the window recognizes the grab - } - // Stimulate an input poll sendInputEvent(); diff --git a/include/graphics/twm4nx/cwindow.hxx b/include/graphics/twm4nx/cwindow.hxx index cf691918b..c11cdf887 100644 --- a/include/graphics/twm4nx/cwindow.hxx +++ b/include/graphics/twm4nx/cwindow.hxx @@ -171,7 +171,8 @@ namespace Twm4Nx struct nxgl_point_s m_dragPos; /**< Last reported mouse position */ struct nxgl_size_s m_dragCSize; /**< The grab cursor size */ - bool m_drag; /**< Drag in-progress */ + bool m_dragging; /**< True: Drag in-progress */ + volatile bool m_clicked; /**< True: Mouse left button is clicked */ /** * Create the main window @@ -284,12 +285,14 @@ namespace Twm4Nx * This function overrides the virtual IDragEvent::dragEvent method. * * @param pos The current mouse/touch X/Y position. + * @param arg The user-argument provided that accompanies the callback * @return True: if the drage event was processed; false it is was * ignored. The event should be ignored if there is not actually * a drag event in progress */ - bool dragEvent(FAR const struct nxgl_point_s &pos); + bool dragEvent(FAR const struct nxgl_point_s &pos, + uintptr_t arg); /** * This function is called if the mouse left button is released or @@ -298,12 +301,33 @@ namespace Twm4Nx * * This function overrides the virtual IDragEvent::dropEvent method. * + * @param pos The last mouse/touch X/Y position. + * @param arg The user-argument provided that accompanies the callback * @return True: if the drage event was processed; false it is was * ignored. The event should be ignored if there is not actually * a drag event in progress */ - bool dropEvent(FAR const struct nxgl_point_s &pos); + bool dropEvent(FAR const struct nxgl_point_s &pos, + uintptr_t arg); + + /** + * Is dragging enabled? + * + * @param arg The user-argument provided that accompanies the callback + * @return True: If the dragging is enabled. + */ + + bool isDragging(uintptr_t arg); + + /** + * Enable/disable dragging + * + * @param enable. True: Enable dragging + * @param arg The user-argument provided that accompanies the callback + */ + + void setDragging(bool enable, uintptr_t arg); /** * Handle the TOOLBAR_GRAB event. That corresponds to a left diff --git a/include/graphics/twm4nx/cwindowevent.hxx b/include/graphics/twm4nx/cwindowevent.hxx index 87a8e21eb..d3a673eef 100644 --- a/include/graphics/twm4nx/cwindowevent.hxx +++ b/include/graphics/twm4nx/cwindowevent.hxx @@ -82,12 +82,14 @@ namespace Twm4Nx * * @param pos The current mouse/touch X/Y position in toolbar relative * coordinates. - * @return True: if the drage event was processed; false it is was + * @param arg The user-argument provided that accompanies the callback + * @return True: if the drag event was processed; false it is was * ignored. The event should be ignored if there is not actually * a drag event in progress */ - virtual bool dragEvent(FAR const struct nxgl_point_s &pos) = 0; + virtual bool dragEvent(FAR const struct nxgl_point_s &pos, + uintptr_t arg) = 0; /** * This function is called if the mouse left button is released or @@ -96,12 +98,32 @@ namespace Twm4Nx * * @param pos The last mouse/touch X/Y position in toolbar relative * coordinates. - * @return True: if the drage event was processed; false it is was + * @param arg The user-argument provided that accompanies the callback + * @return True: If the drag event was processed; false it is was * ignored. The event should be ignored if there is not actually * a drag event in progress */ - virtual bool dropEvent(FAR const struct nxgl_point_s &pos) = 0; + virtual bool dropEvent(FAR const struct nxgl_point_s &pos, + uintptr_t arg) = 0; + + /** + * Is dragging enabled? + * + * @param arg The user-argument provided that accompanies the callback + * @return True: If the dragging is enabled. + */ + + virtual bool isDragging(uintptr_t arg) = 0; + + /** + * Enable/disable dragging + * + * @param enable. True: Enable dragging + * @param arg The user-argument provided that accompanies the callback + */ + + virtual void setDragging(bool enable, uintptr_t arg) = 0; }; /** @@ -117,16 +139,15 @@ namespace Twm4Nx public NXWidgets::CWidgetControl { private: - FAR CTwm4Nx *m_twm4nx; /**< Cached instance of CTwm4Nx */ - mqd_t m_eventq; /**< NxWidget event message queue */ - FAR void *m_object; /**< Window object (context specific) */ - bool m_isBackground; /**< True if this serves the background window */ + FAR CTwm4Nx *m_twm4nx; /**< Cached instance of CTwm4Nx */ + mqd_t m_eventq; /**< NxWidget event message queue */ + FAR void *m_object; /**< Window object (context specific) */ + bool m_isBackground; /**< True if this serves the background window */ // Dragging - FAR IDragEvent *m_dragHandler; /**< Drag event handlers (may be NULL) */ - bool m_dragging; /**< True: dragging */ - struct nxgl_point_s m_dragPos; /**< Last mouse/touch position */ + FAR IDragEvent *m_dragHandler; /**< Drag event handlers (may be NULL) */ + uintptr_t m_dragArg; /**< User argument associated with callback */ /** * Send the EVENT_MSG_POLL input event message to the Twm4Nx event loop. @@ -204,9 +225,11 @@ namespace Twm4Nx * @param cb A reference to the IDragEvent callback interface. */ - inline void registerDragEventHandler(FAR IDragEvent *dragHandler) + inline void registerDragEventHandler(FAR IDragEvent *dragHandler, + uintptr_t arg) { m_dragHandler = dragHandler; + m_dragArg = arg; } }; }