From d244b7a11d87c6bfc482614ac0f378876935ddb0 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 7 May 2019 16:16:47 -0600 Subject: [PATCH] Squashed commit of the following: apps/graphics/twm4nx: Additional redesign. Window draggin now sort of works in an unreliable hurky-gurky way. More to be done. apps/graphics/twm4nx: First cut at redesigned dragging logic --- graphics/nxwidgets/src/cwidgetcontrol.cxx | 6 +- .../nxwidgets/src/cwindoweventhandlerlist.cxx | 5 +- graphics/nxwm/src/cwindowmessenger.cxx | 3 +- graphics/twm4nx/src/ciconmgr.cxx | 2 - graphics/twm4nx/src/ciconwidget.cxx | 13 +- graphics/twm4nx/src/cinput.cxx | 16 +- graphics/twm4nx/src/cmenus.cxx | 7 +- graphics/twm4nx/src/cwindow.cxx | 258 +++++++++++------- graphics/twm4nx/src/cwindowevent.cxx | 93 ++++++- graphics/twm4nx/src/cwindowfactory.cxx | 1 + .../nxwidgets/cwindoweventhandler.hxx | 5 +- .../nxwidgets/cwindoweventhandlerlist.hxx | 3 +- include/graphics/nxwm/cwindowmessenger.hxx | 2 +- include/graphics/twm4nx/cinput.hxx | 10 +- include/graphics/twm4nx/cwindow.hxx | 56 ++-- include/graphics/twm4nx/cwindowevent.hxx | 82 +++++- .../graphics/twm4nx/twm4nx_widgetevents.hxx | 1 - 17 files changed, 403 insertions(+), 160 deletions(-) diff --git a/graphics/nxwidgets/src/cwidgetcontrol.cxx b/graphics/nxwidgets/src/cwidgetcontrol.cxx index 4ef0bd04d..cdace6b62 100644 --- a/graphics/nxwidgets/src/cwidgetcontrol.cxx +++ b/graphics/nxwidgets/src/cwidgetcontrol.cxx @@ -1,7 +1,7 @@ /**************************************************************************** * apps/graphics/nxwidgets/src/cwidgetcontrol.cxx * - * Copyright (C) 2012-2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2012-2013, 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -566,9 +566,9 @@ void CWidgetControl::newMouseEvent(FAR const struct nxgl_point_s *pos, uint8_t b } #endif - // Notify any external logic that a keyboard event has occurred + // Notify any external logic that a mouse event has occurred - m_eventHandlers.raiseMouseEvent(); + m_eventHandlers.raiseMouseEvent(pos, buttons); #ifdef CONFIG_NXWIDGET_EVENTWAIT // Then wake up logic that may be waiting for a window event diff --git a/graphics/nxwidgets/src/cwindoweventhandlerlist.cxx b/graphics/nxwidgets/src/cwindoweventhandlerlist.cxx index b8007c058..6f5ffb435 100644 --- a/graphics/nxwidgets/src/cwindoweventhandlerlist.cxx +++ b/graphics/nxwidgets/src/cwindoweventhandlerlist.cxx @@ -137,11 +137,12 @@ void CWindowEventHandlerList::raiseGeometryEvent(void) * Raise an NX mouse window input event. */ -void CWindowEventHandlerList::raiseMouseEvent(void) +void CWindowEventHandlerList::raiseMouseEvent(FAR const struct nxgl_point_s *pos, + uint8_t buttons) { for (int i = 0; i < m_eventHandlers.size(); ++i) { - m_eventHandlers.at(i)->handleMouseEvent(); + m_eventHandlers.at(i)->handleMouseEvent(pos, buttons); } } #endif diff --git a/graphics/nxwm/src/cwindowmessenger.cxx b/graphics/nxwm/src/cwindowmessenger.cxx index c11c0227b..b69429974 100644 --- a/graphics/nxwm/src/cwindowmessenger.cxx +++ b/graphics/nxwm/src/cwindowmessenger.cxx @@ -90,7 +90,8 @@ CWindowMessenger::~CWindowMessenger(void) * Handle an NX window mouse input event. */ -void CWindowMessenger::handleMouseEvent(void) +void CWindowMessenger::handleMouseEvent(FAR const struct nxgl_point_s *pos, + uint8_t buttons) { // The logic path here is tortuous but flexible: // diff --git a/graphics/twm4nx/src/ciconmgr.cxx b/graphics/twm4nx/src/ciconmgr.cxx index f12a6e04d..b362a068a 100644 --- a/graphics/twm4nx/src/ciconmgr.cxx +++ b/graphics/twm4nx/src/ciconmgr.cxx @@ -823,8 +823,6 @@ void CIconMgr::handleActionEvent(const NXWidgets::CWidgetEventArgs &e) struct SEventMsg msg; msg.pos.x = e.getX(); msg.pos.y = e.getY(); - msg.delta.x = 0; - msg.delta.y = 0; msg.context = EVENT_CONTEXT_ICONMGR; msg.handler = (FAR CTwm4NxEvent *)0; msg.obj = (FAR void *)swin->cwin; diff --git a/graphics/twm4nx/src/ciconwidget.cxx b/graphics/twm4nx/src/ciconwidget.cxx index a53a3c1f2..9fc8baac7 100644 --- a/graphics/twm4nx/src/ciconwidget.cxx +++ b/graphics/twm4nx/src/ciconwidget.cxx @@ -107,7 +107,8 @@ CIconWidget::CIconWidget(FAR CTwm4Nx *twm4nx, // Configure the widget - m_flags.borderless = true; // The widget is borless (and transparent) + m_flags.borderless = true; // The widget is borderless (and transparent) + m_flags.draggable = true; // This widget may be dragged } /** @@ -461,8 +462,6 @@ void CIconWidget::handleUngrabEvent(const NXWidgets::CWidgetEventArgs &e) msg.eventID = EVENT_ICONWIDGET_UNGRAB; msg.pos.x = e.getX(); msg.pos.y = e.getY(); - msg.delta.x = 0; - msg.delta.y = 0; msg.context = EVENT_CONTEXT_ICON; msg.handler = (FAR CTwm4NxEvent *)0; msg.obj = (FAR void *)this; @@ -490,8 +489,8 @@ void CIconWidget::handleUngrabEvent(const NXWidgets::CWidgetEventArgs &e) void CIconWidget::handleDragEvent(const NXWidgets::CWidgetEventArgs &e) { - // We don't care which widget is being dragged, only that we are in the - // dragging state. + // We don't care which component of the icon widget was clicked only that + // we are not currently being dragged if (m_drag) { @@ -501,8 +500,6 @@ void CIconWidget::handleDragEvent(const NXWidgets::CWidgetEventArgs &e) msg.eventID = EVENT_ICONWIDGET_DRAG; msg.pos.x = e.getX(); msg.pos.y = e.getY(); - msg.delta.x = e.getVX(); - msg.delta.y = e.getVY(); msg.context = EVENT_CONTEXT_ICON; msg.handler = (FAR CTwm4NxEvent *)0; msg.obj = (FAR void *)this; @@ -562,8 +559,6 @@ void CIconWidget::handleClickEvent(const NXWidgets::CWidgetEventArgs &e) msg.eventID = EVENT_ICONWIDGET_GRAB; msg.pos.x = e.getX(); msg.pos.y = e.getY(); - msg.delta.x = 0; - msg.delta.y = 0; msg.context = EVENT_CONTEXT_ICON; msg.handler = (FAR CTwm4NxEvent *)0; msg.obj = (FAR void *)this; diff --git a/graphics/twm4nx/src/cinput.cxx b/graphics/twm4nx/src/cinput.cxx index b819d3bb2..c54f20588 100644 --- a/graphics/twm4nx/src/cinput.cxx +++ b/graphics/twm4nx/src/cinput.cxx @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -95,6 +96,8 @@ using namespace Twm4Nx; CInput::CInput(CTwm4Nx *twm4nx) { + // Session + m_twm4nx = twm4nx; // Save the NX server #ifndef CONFIG_TWM4NX_NOKEYBOARD m_kbdFd = -1; // Keyboard driver is not opened @@ -102,14 +105,21 @@ CInput::CInput(CTwm4Nx *twm4nx) #ifndef CONFIG_TWM4NX_NOMOUSE m_mouseFd = -1; // Mouse/touchscreen driver is not opened #endif + + // Listener + m_state = LISTENER_NOTRUNNING; // The listener thread is not running yet -#ifdef CONFIG_TWM4NX_TOUCHSCREEN - m_calib = false; // Use raw touches until calibrated -#endif // Initialize the semaphore used to synchronize with the listener thread sem_init(&m_waitSem, 0, 0); + sem_setprotocol(&m_waitSem, SEM_PRIO_NONE); + +#ifdef CONFIG_TWM4NX_TOUCHSCREEN + // Calibration + + m_calib = false; // Use raw touches until calibrated +#endif } /** diff --git a/graphics/twm4nx/src/cmenus.cxx b/graphics/twm4nx/src/cmenus.cxx index 63b07d9dd..76da383ef 100644 --- a/graphics/twm4nx/src/cmenus.cxx +++ b/graphics/twm4nx/src/cmenus.cxx @@ -180,8 +180,7 @@ bool CMenus::initialize(FAR NXWidgets::CNxString &name) bool CMenus::addMenuItem(FAR NXWidgets::CNxString &text, FAR CMenus *subMenu, FAR CTwm4NxEvent *handler, uint16_t event) { - twminfo("Adding menu text=\"%s\", subMenu=%p, event=%04x\n", - text->getCharArray(), subMenu, event); + twminfo("Adding: subMenu=%p, event=%04x\n", subMenu, event); // Allocate a new menu item entry @@ -317,8 +316,6 @@ bool CMenus::event(FAR struct SEventMsg *eventmsg) newmsg.eventID = item->event; newmsg.pos.x = eventmsg->pos.x; newmsg.pos.y = eventmsg->pos.y; - newmsg.delta.x = 0; - newmsg.delta.y = 0; newmsg.context = eventmsg->context; newmsg.handler = item->handler; newmsg.obj = eventmsg->obj; @@ -862,8 +859,6 @@ void CMenus::handleValueChangeEvent(const NXWidgets::CWidgetEventArgs &e) msg.eventID = item->event; msg.pos.x = e.getX(); msg.pos.y = e.getY(); - msg.delta.x = 0; - msg.delta.y = 0; msg.context = EVENT_CONTEXT_TOOLBAR; msg.handler = item->handler; msg.obj = (FAR void *)this; diff --git a/graphics/twm4nx/src/cwindow.cxx b/graphics/twm4nx/src/cwindow.cxx index fe0e3c131..73f668f08 100644 --- a/graphics/twm4nx/src/cwindow.cxx +++ b/graphics/twm4nx/src/cwindow.cxx @@ -161,8 +161,8 @@ CWindow::CWindow(CTwm4Nx *twm4nx) // Dragging m_drag = false; - m_dragOffset.x = 0; - m_dragOffset.y = 0; + m_dragPos.x = 0; + m_dragPos.y = 0; m_dragCSize.w = 0; m_dragCSize.h = 0; @@ -675,6 +675,8 @@ bool CWindow::createMainWindow(FAR const nxgl_size_s *winsize, // 3. Create a Widget control instance for the window using the default // style for now. CWindowEvent derives from CWidgetControl. + // Setup the the CWindowEvent instance to use our inherited drag event + // handler FAR CWindowEvent *control = new CWindowEvent(m_twm4nx, (FAR void *)this); @@ -767,6 +769,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); // 3. Get the toolbar sub-window from the framed window @@ -1145,19 +1148,18 @@ bool CWindow::createToolbarTitle(FAR const char *name) * virtual event handling methods. It just combines some common event- * handling logic. * - * @param e The event data. + * @param x The mouse/touch X position. + * @param y The mouse/touch y position. */ -void CWindow::handleUngrabEvent(const NXWidgets::CWidgetEventArgs &e) +void CWindow::handleUngrabEvent(nxgl_coord_t x, nxgl_coord_t y) { // Generate the un-grab event struct SEventMsg msg; msg.eventID = EVENT_TOOLBAR_UNGRAB; - msg.pos.x = e.getX(); - msg.pos.y = e.getY(); - msg.delta.x = 0; - msg.delta.y = 0; + msg.pos.x = x; + msg.pos.y = y; msg.context = EVENT_CONTEXT_TOOLBAR; msg.handler = (FAR CTwm4NxEvent *)0; msg.obj = (FAR void *)this; @@ -1177,70 +1179,6 @@ void CWindow::handleUngrabEvent(const NXWidgets::CWidgetEventArgs &e) } } -/** - * Override the mouse button drag event. - * - * @param e The event data. - */ - -void CWindow::handleDragEvent(const NXWidgets::CWidgetEventArgs &e) -{ - // We are interested only the the drag event on the title box while we are - // in the dragging state. - - if (m_drag && m_tbTitle->isBeingDragged()) - { - // Generate the event - - struct SEventMsg msg; - msg.eventID = EVENT_WINDOW_DRAG; - msg.pos.x = e.getX(); - msg.pos.y = e.getY(); - msg.delta.x = e.getVX(); - msg.delta.y = e.getVY(); - msg.context = EVENT_CONTEXT_TOOLBAR; - msg.handler = (FAR CTwm4NxEvent *)0; - msg.obj = (FAR void *)this; - - // NOTE that we cannot block because we are on the same thread - // as the message reader. If the event queue becomes full then - // we have no other option but to lose events. - // - // I suppose we could recurse and call Twm4Nx::dispatchEvent at - // the risk of runaway stack usage. - - int ret = mq_send(m_eventq, (FAR const char *)&msg, - sizeof(struct SEventMsg), 100); - if (ret < 0) - { - twmerr("ERROR: mq_send failed: %d\n", ret); - } - } -} - -/** - * Override a drop event, triggered when the widget has been dragged-and-dropped. - * - * @param e The event data. - */ - -void CWindow::handleDropEvent(const NXWidgets::CWidgetEventArgs &e) -{ - // We are interested only the the drag drop event on the title box while we - // are in the dragging state. - // - // When the Drop Event is received, both isClicked and isBeingDragged() - // will return false. It is sufficient to verify that the isClicked() is - // not true to exit the drag. - - if (m_drag && !m_tbTitle->isClicked()) - { - // Yes.. handle the drop event - - handleUngrabEvent(e); - } -} - /** * Handle a mouse click event. * @@ -1260,8 +1198,6 @@ void CWindow::handleClickEvent(const NXWidgets::CWidgetEventArgs &e) msg.eventID = EVENT_TOOLBAR_GRAB; msg.pos.x = e.getX(); msg.pos.y = e.getY(); - msg.delta.x = 0; - msg.delta.y = 0; msg.context = EVENT_CONTEXT_TOOLBAR; msg.handler = (FAR CTwm4NxEvent *)0; msg.obj = (FAR void *)this; @@ -1303,7 +1239,7 @@ void CWindow::handleReleaseEvent(const NXWidgets::CWidgetEventArgs &e) // Handle the non-drag drop event - handleUngrabEvent(e); + handleUngrabEvent(e.getX(), e.getY()); } } @@ -1334,8 +1270,6 @@ void CWindow::handleActionEvent(const NXWidgets::CWidgetEventArgs &e) msg.eventID = GToolBarInfo[btindex].event; msg.pos.x = e.getX(); msg.pos.y = e.getY(); - msg.delta.x = 0; - msg.delta.y = 0; msg.context = EVENT_CONTEXT_TOOLBAR; msg.handler = (FAR CTwm4NxEvent *)0; msg.obj = (FAR void *)this; @@ -1357,6 +1291,95 @@ void CWindow::handleActionEvent(const NXWidgets::CWidgetEventArgs &e) } } +/** + * This function is called when there is any moved of the mouse or + * touch position that would indicate that the object is being moved. + * + * This function overrides the virtual IDragEvent::dragEvent method. + * + * @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 + * 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) +{ + twminfo("m_drag=%u pos=(%d,%d)\n", m_drag, pos.x, pos.y); + + // We are interested only the drag event while we are in the dragging + // state. + + if (m_drag) + { + // Conver the + // Generate the event + + struct SEventMsg msg; + msg.eventID = EVENT_WINDOW_DRAG; + msg.pos.x = pos.x; + msg.pos.y = pos.y; + msg.context = EVENT_CONTEXT_TOOLBAR; + msg.handler = (FAR CTwm4NxEvent *)0; + msg.obj = (FAR void *)this; + + // NOTE that we cannot block because we are on the same thread + // as the message reader. If the event queue becomes full then + // we have no other option but to lose events. + // + // I suppose we could recurse and call Twm4Nx::dispatchEvent at + // the risk of runaway stack usage. + + int ret = mq_send(m_eventq, (FAR const char *)&msg, + sizeof(struct SEventMsg), 100); + if (ret < 0) + { + twmerr("ERROR: mq_send failed: %d\n", ret); + } + + return true; + } + + return false; +} + +/** + * This function is called if the mouse left button is released or + * if the touchscrreen touch is lost. This indicates that the + * dragging sequence is complete. + * + * This function overrides the virtual IDragEvent::dropEvent method. + * + * @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 + * 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) +{ + twminfo("m_drag=%u pos=(%d,%d)\n", m_drag, pos.x, pos.y); + + // We are interested only the the drag drop event on the title box while we + // are in the dragging state. + // + // When the Drop Event is received, both isClicked and isBeingDragged() + // will return false. It is sufficient to verify that the isClicked() is + // not true to exit the drag. + + if (m_drag) + { + // Yes.. handle the drop event + + handleUngrabEvent(pos.x, pos.y); + return true; + } + + return false; +} + /** * Handle the TOOLBAR_GRAB event. That corresponds to a left * mouse click on the title widget in the toolbar @@ -1368,6 +1391,8 @@ void CWindow::handleActionEvent(const NXWidgets::CWidgetEventArgs &e) bool CWindow::toolbarGrab(FAR struct SEventMsg *eventmsg) { + twminfo("GRAB (%d,%d)\n", eventmsg->pos.x, eventmsg->pos.y); + // Promote the window to a modal window m_modal = true; @@ -1382,19 +1407,25 @@ bool CWindow::toolbarGrab(FAR struct SEventMsg *eventmsg) struct nxgl_point_s framePos; getFramePosition(&framePos); - // Determine the relative position of the frame and the mouse + twminfo("Position (%d,%d)\n", framePos.x, framePos.y); - m_dragOffset.x = framePos.x - eventmsg->pos.x; - m_dragOffset.y = framePos.y - eventmsg->pos.y; + // Save the toolbar-relative mouse position in order to detect the amount + // of movement in the next drag event. + m_dragPos.x = eventmsg->pos.x; + m_dragPos.y = eventmsg->pos.y; + +#ifdef CONFIG_TWM4NX_MOUSE // Select the grab cursor image m_twm4nx->setCursorImage(&CONFIG_TWM4NX_GBCURSOR_IMAGE); +#endif // Remember the grab cursor size m_dragCSize.w = CONFIG_TWM4NX_GBCURSOR_IMAGE.size.w; m_dragCSize.h = CONFIG_TWM4NX_GBCURSOR_IMAGE.size.h; + return true; } @@ -1409,13 +1440,31 @@ bool CWindow::toolbarGrab(FAR struct SEventMsg *eventmsg) bool CWindow::windowDrag(FAR struct SEventMsg *eventmsg) { + twminfo("DRAG (%d,%d)\n", eventmsg->pos.x, eventmsg->pos.y); + if (m_drag) { - // Calculate the new Window position + // The coordinates in the eventmsg or relative to the origin + // of the toolbar. - struct nxgl_point_s newpos; - newpos.x = eventmsg->pos.x + m_dragOffset.x; - newpos.y = eventmsg->pos.y + m_dragOffset.y; + struct nxgl_point_s oldPos; + if (!getFramePosition(&oldPos)) + { + gerr("ERROR: getFramePosition() failed\n") ; + return false; + } + + // We want to set the new frame position so that it has the same + // relative mouse position as when we grabbed the toolbar. + + struct nxgl_point_s newPos; + newPos.x = oldPos.x + eventmsg->pos.x - m_dragPos.x; + newPos.y = oldPos.y + eventmsg->pos.y - m_dragPos.y; + + // Save the new mouse position + + m_dragPos.x = eventmsg->pos.x; + m_dragPos.y = eventmsg->pos.y; // Keep the window on the display (at least enough of it so that we // can still grab it) @@ -1423,27 +1472,41 @@ bool CWindow::windowDrag(FAR struct SEventMsg *eventmsg) struct nxgl_size_s displaySize; m_twm4nx->getDisplaySize(&displaySize); - if (newpos.x < 0) + if (newPos.x < 0) { - newpos.x = 0; + newPos.x = 0; } - else if (newpos.x + m_dragCSize.w > displaySize.w) + else if (newPos.x + m_dragCSize.w > displaySize.w) { - newpos.x = displaySize.w - m_dragCSize.w; + newPos.x = displaySize.w - m_dragCSize.w; } - if (newpos.y < 0) + if (newPos.y < 0) { - newpos.y = 0; + newPos.y = 0; } - else if (newpos.y + m_dragCSize.h > displaySize.h) + else if (newPos.y + m_dragCSize.h > displaySize.h) { - newpos.y = displaySize.h - m_dragCSize.h; + newPos.y = displaySize.h - m_dragCSize.h; } - // Set the new window position + // Set the new window position if it has changed - return setFramePosition(&newpos); + twminfo("Position (%d,%d)->(%d,%d)\n", + oldPos.x, oldPos.y, newPos.x, newPos.y); + + if (newPos.x != oldPos.x || newPos.y != oldPos.y) + { + if (!setFramePosition(&newPos)) + { + gerr("ERROR: setFramePosition failed\n"); + return false; + } + + m_nxWin->synchronize(); + } + + return true; } return false; @@ -1453,13 +1516,16 @@ bool CWindow::windowDrag(FAR struct SEventMsg *eventmsg) * Handle the TOOLBAR_UNGRAB event. The corresponds to a mouse * left button release while in the grabbed state * - * @param eventmsg. The received NxWidget event message. + * @param eventmsg. The received NxWidget event message in window relative + * coordinates. * @return True if the message was properly handled. false is * return on any failure. */ bool CWindow::toolbarUngrab(FAR struct SEventMsg *eventmsg) { + twminfo("UNGRAB (%d,%d)\n", eventmsg->pos.x, eventmsg->pos.y); + // One last position update if (!windowDrag(eventmsg)) @@ -1476,9 +1542,11 @@ bool CWindow::toolbarUngrab(FAR struct SEventMsg *eventmsg) m_modal = false; m_nxWin->modal(false); +#ifdef CONFIG_TWM4NX_MOUSE // Restore the normal cursor image m_twm4nx->setCursorImage(&CONFIG_TWM4NX_CURSOR_IMAGE); +#endif return true; } diff --git a/graphics/twm4nx/src/cwindowevent.cxx b/graphics/twm4nx/src/cwindowevent.cxx index 763d53247..5a38683aa 100644 --- a/graphics/twm4nx/src/cwindowevent.cxx +++ b/graphics/twm4nx/src/cwindowevent.cxx @@ -42,8 +42,11 @@ #include #include +#include #include +#include + #include "graphics/nxwidgets/cwidgetcontrol.hxx" #include "graphics/twm4nx/twm4nx_config.hxx" @@ -72,9 +75,14 @@ CWindowEvent::CWindowEvent(FAR CTwm4Nx *twm4nx, FAR void *obj, FAR const NXWidgets::CWidgetStyle *style) : NXWidgets::CWidgetControl(style) { - m_twm4nx = twm4nx; // Cache the Twm4Nx session - m_object = obj; // Used for event message construction - m_isBackground = isBackground; // Background window? + m_twm4nx = twm4nx; // Cache the Twm4Nx session + m_object = obj; // Used for event message construction + m_isBackground = isBackground; // Background window? + + // Dragging + + m_dragHandler = (FAR IDragEvent *)0; // No drag handler callbacks + m_dragging = false; // Not dragging // Open a message queue to send raw NX events. This cannot fail! @@ -208,9 +216,84 @@ void CWindowEvent::handleRedrawEvent(FAR const nxgl_rect_s *nxRect, * Handle an NX window mouse input event. */ -void CWindowEvent::handleMouseEvent(void) +void CWindowEvent::handleMouseEvent(FAR const struct nxgl_point_s *pos, + uint8_t buttons) { - twminfo("Mouse input...\n"); + twminfo("Mouse input: m_dragging=%u\n", m_dragging); + + // 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) + { + // Save the new drag position in window relative display coordinates + + m_dragPos.x = pos->x; + m_dragPos.y = pos->y; + + // Is the left button still pressed? + + if ((buttons & MOUSE_BUTTON_1) != 0) + { + twminfo("Continue dragging (%d,%d) buttons=%02x m_dragHandler=%p\n", + m_dragPos.x, m_dragPos.y, buttons, m_dragHandler); + + // Yes.. generate a drag event if we have a drag event handler + + if (m_dragHandler != (FAR IDragEvent *)0 && + m_dragHandler->dragEvent(m_dragPos)) + { + // Skip the input poll until the drag completes + + return; + } + } + else + { + twminfo("Stop dragging (%d,%d) buttons=%02x m_dragHandler=%p\n", + m_dragPos.x, m_dragPos.y, buttons, m_dragHandler); + + // No.. then we are no longer dragging + + m_dragging = false; + + // 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; + } + } + } + + // 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 diff --git a/graphics/twm4nx/src/cwindowfactory.cxx b/graphics/twm4nx/src/cwindowfactory.cxx index d5fa9a463..09692e3d2 100644 --- a/graphics/twm4nx/src/cwindowfactory.cxx +++ b/graphics/twm4nx/src/cwindowfactory.cxx @@ -249,6 +249,7 @@ void CWindowFactory::destroyWindow(FAR CWindow *cwin) bool CWindowFactory::event(FAR struct SEventMsg *eventmsg) { twminfo("eventID: %d\n", eventmsg->eventID); + bool success = true; switch (eventmsg->eventID) diff --git a/include/graphics/nxwidgets/cwindoweventhandler.hxx b/include/graphics/nxwidgets/cwindoweventhandler.hxx index c194360cb..6e65a3de6 100644 --- a/include/graphics/nxwidgets/cwindoweventhandler.hxx +++ b/include/graphics/nxwidgets/cwindoweventhandler.hxx @@ -98,7 +98,10 @@ namespace NXWidgets * Handle an NX window mouse input event. */ - virtual void handleMouseEvent(void) { } + virtual void handleMouseEvent(FAR const struct nxgl_point_s *pos, + uint8_t buttons) + { + } #endif #ifdef CONFIG_NX_KBD diff --git a/include/graphics/nxwidgets/cwindoweventhandlerlist.hxx b/include/graphics/nxwidgets/cwindoweventhandlerlist.hxx index 671ecbbfb..51d48dc44 100644 --- a/include/graphics/nxwidgets/cwindoweventhandlerlist.hxx +++ b/include/graphics/nxwidgets/cwindoweventhandlerlist.hxx @@ -153,7 +153,8 @@ namespace NXWidgets * Raise an NX mouse window input event. */ - void raiseMouseEvent(void); + void raiseMouseEvent(FAR const struct nxgl_point_s *pos, + uint8_t buttons); #endif #ifdef CONFIG_NX_KBD diff --git a/include/graphics/nxwm/cwindowmessenger.hxx b/include/graphics/nxwm/cwindowmessenger.hxx index 7d648e767..a02f48ce3 100644 --- a/include/graphics/nxwm/cwindowmessenger.hxx +++ b/include/graphics/nxwm/cwindowmessenger.hxx @@ -104,7 +104,7 @@ namespace NxWM * Handle an NX window mouse input event. */ - void handleMouseEvent(void); + void handleMouseEvent(FAR const struct nxgl_point_s *pos, uint8_t buttons); #endif #ifdef CONFIG_NX_KBD diff --git a/include/graphics/twm4nx/cinput.hxx b/include/graphics/twm4nx/cinput.hxx index cf9648a35..4647edd2e 100644 --- a/include/graphics/twm4nx/cinput.hxx +++ b/include/graphics/twm4nx/cinput.hxx @@ -124,6 +124,8 @@ namespace Twm4Nx * CInput state data */ + // Session + CTwm4Nx *m_twm4nx; /**< The Twm4Nx session */ #ifndef CONFIG_TWM4NX_NOKEYBOARD int m_kbdFd; /**< File descriptor of the opened keyboard device */ @@ -131,15 +133,21 @@ namespace Twm4Nx #ifndef CONFIG_TWM4NX_NOMOUSE int m_mouseFd; /**< File descriptor of the opened mouse device */ #endif + + // Listener + pthread_t m_thread; /**< The listener thread ID */ volatile enum EListenerState m_state; /**< The state of the listener thread */ sem_t m_waitSem; /**< Used to synchronize with the listener thread */ #ifdef CONFIG_TWM4NX_TOUCHSCREEN + // Calibration + bool m_calib; /**< False: Use raw, uncalibrated touches */ struct SCalibrationData m_calData; /**< Touchscreen calibration data */ #endif + #ifndef CONFIG_TWM4NX_NOKEYBOARD /** * Open the keyboard device. Not very interesting for the case of @@ -278,7 +286,7 @@ namespace Twm4Nx #endif /** - * Start the keyboard listener thread. + * Start the keyboard/mouse listener thread. * * @return True if the keyboard listener thread was correctly started. */ diff --git a/include/graphics/twm4nx/cwindow.hxx b/include/graphics/twm4nx/cwindow.hxx index a475c31ff..cf691918b 100644 --- a/include/graphics/twm4nx/cwindow.hxx +++ b/include/graphics/twm4nx/cwindow.hxx @@ -57,6 +57,7 @@ #include "graphics/nxwidgets/cwidgeteventhandler.hxx" #include "graphics/nxwidgets/cwidgeteventargs.hxx" +#include "graphics/twm4nx/cwindowevent.hxx" #include "graphics/twm4nx/ciconwidget.hxx" #include "graphics/twm4nx/ctwm4nxevent.hxx" @@ -128,7 +129,9 @@ namespace Twm4Nx // The CWindow class implements a standard, framed window with a toolbar // containing the standard buttons and the window title. - class CWindow : protected NXWidgets::CWidgetEventHandler, public CTwm4NxEvent + class CWindow : protected NXWidgets::CWidgetEventHandler, + protected IDragEvent, + public CTwm4NxEvent { private: CTwm4Nx *m_twm4nx; /**< Cached Twm4Nx session */ @@ -166,7 +169,7 @@ namespace Twm4Nx // Dragging - struct nxgl_point_s m_dragOffset; /**< Offset from mouse to window origin */ + 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 */ @@ -239,26 +242,11 @@ namespace Twm4Nx * virtual event handling methods. It just combines some common event- * handling logic. * - * @param e The event data. + * @param x The mouse/touch X position. + * @param y The mouse/touch y position. */ - void handleUngrabEvent(const NXWidgets::CWidgetEventArgs &e); - - /** - * Override the mouse button drag event. - * - * @param e The event data. - */ - - void handleDragEvent(const NXWidgets::CWidgetEventArgs &e); - - /** - * Override a drop event, triggered when the widget has been dragged-and-dropped. - * - * @param e The event data. - */ - - void handleDropEvent(const NXWidgets::CWidgetEventArgs &e); + void handleUngrabEvent(nxgl_coord_t x, nxgl_coord_t y); /** * Handle a mouse click event. @@ -289,6 +277,34 @@ namespace Twm4Nx void handleActionEvent(const NXWidgets::CWidgetEventArgs &e); + /** + * This function is called when there is any moved of the mouse or + * touch position that would indicate that the object is being moved. + * + * This function overrides the virtual IDragEvent::dragEvent method. + * + * @param pos The current mouse/touch X/Y position. + * @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); + + /** + * This function is called if the mouse left button is released or + * if the touchscrreen touch is lost. This indicates that the + * dragging sequence is complete. + * + * This function overrides the virtual IDragEvent::dropEvent method. + * + * @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); + /** * Handle the TOOLBAR_GRAB event. That corresponds to a left * mouse click on the toolbar (other than on an icon) diff --git a/include/graphics/twm4nx/cwindowevent.hxx b/include/graphics/twm4nx/cwindowevent.hxx index 66782a1b5..87a8e21eb 100644 --- a/include/graphics/twm4nx/cwindowevent.hxx +++ b/include/graphics/twm4nx/cwindowevent.hxx @@ -57,10 +57,53 @@ // Implementation Classes ///////////////////////////////////////////////////////////////////////////// -#if defined(__cplusplus) - namespace Twm4Nx { + /** + * This abstract base class provides add on methods to support dragging + * of a window. + */ + + class IDragEvent + { + public: + /** + * A virtual destructor is required in order to override the ITextBox + * destructor. We do this because if we delete ITextBox, we want the + * destructor of the class that inherits from ITextBox to run, not this + * one. + */ + + virtual ~IDragEvent(void) { } + + /** + * This function is called when there is any moved of the mouse or + * touch position that would indicate that the object is being moved. + * + * @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 + * 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; + + /** + * This function is called if the mouse left button is released or + * if the touchscrreen touch is lost. This indicates that the + * dragging sequence is complete. + * + * @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 + * 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; + }; + /** * The class CWindowEvent integrates the widget control with some special * handling of mouse and keyboard inputs needs by NxWM. It use used @@ -74,10 +117,16 @@ 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 */ /** * Send the EVENT_MSG_POLL input event message to the Twm4Nx event loop. @@ -101,7 +150,8 @@ namespace Twm4Nx * Handle an NX window mouse input event. */ - void handleMouseEvent(void); + void handleMouseEvent(FAR const struct nxgl_point_s *pos, + uint8_t buttons); #endif #ifdef CONFIG_NX_KBD @@ -142,9 +192,23 @@ namespace Twm4Nx * CWindowEvent Destructor. */ - ~CWindowEvent(void); + ~CWindowEvent(void); + + /** + * Register an IDragEvent instance to provide callbacks when mouse + * movement is received. A mouse movement with the left button down + * or a touchscreen touch movement are treated as a drag event. + * Release of the mouse left button or loss of the touchscreen touch + * is treated as a drop event. + * + * @param cb A reference to the IDragEvent callback interface. + */ + + inline void registerDragEventHandler(FAR IDragEvent *dragHandler) + { + m_dragHandler = dragHandler; + } }; } -#endif // __cplusplus #endif // __APPS_INCLUDE_GRAPHICS_TWM4NX_CWINDOWEVENT_HXX diff --git a/include/graphics/twm4nx/twm4nx_widgetevents.hxx b/include/graphics/twm4nx/twm4nx_widgetevents.hxx index c69e031e0..f5cba5aed 100644 --- a/include/graphics/twm4nx/twm4nx_widgetevents.hxx +++ b/include/graphics/twm4nx/twm4nx_widgetevents.hxx @@ -197,7 +197,6 @@ namespace Twm4Nx { uint16_t eventID; /**< Encoded event ID */ struct nxgl_point_s pos; /**< X/Y position */ - struct nxgl_point_s delta; /**< X/Y change (for dragging only) */ uint8_t context; /**< Button press context */ FAR CTwm4NxEvent *handler; /**< App event handler (APP recipient only) */ FAR void *obj; /**< Window object (CWindow or CIconWidget) */