apps/graphics/twm4nx: Extend the IDragEvents interfaces and user's thereof to better handle the cases when dragging where the mouse position gets ahead of the window updates and the reported mouse position lies not in the toolbar window, but in the main window or even outside of the window.

This commit is contained in:
Gregory Nutt 2019-05-07 18:20:42 -06:00
parent d244b7a11d
commit 598bf28f34
4 changed files with 188 additions and 92 deletions

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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;
}
};
}