From eeb5d4433cb554ae269c44858937dd72b121e9a8 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 14 May 2019 08:15:36 -0600 Subject: [PATCH] Squashed commit of the following: apps/graphics/twm4nx: Add logic to detect collisions with reserved regions in the backgroud or with other icons when moving an icon on the desktop. apps/graphics/twm4nx: When moving icons, erase the old icon image before drawing the new one. --- graphics/twm4nx/src/cbackground.cxx | 4 +- graphics/twm4nx/src/ciconwidget.cxx | 146 +++++++++++++++++++-- graphics/twm4nx/src/cwindowfactory.cxx | 110 ++++++++-------- include/graphics/twm4nx/ciconwidget.hxx | 3 +- include/graphics/twm4nx/cwindowfactory.hxx | 30 ++--- 5 files changed, 209 insertions(+), 84 deletions(-) diff --git a/graphics/twm4nx/src/cbackground.cxx b/graphics/twm4nx/src/cbackground.cxx index 27117f568..0adedd9bf 100644 --- a/graphics/twm4nx/src/cbackground.cxx +++ b/graphics/twm4nx/src/cbackground.cxx @@ -190,8 +190,8 @@ bool CBackground::checkCollision(FAR const struct nxgl_rect_s &bounds, collision.pt1.x = imagePos.x; collision.pt1.y = imagePos.y; - collision.pt1.x = imagePos.x + imageSize.w - 1; - collision.pt1.y = imagePos.y + imageSize.h - 1; + collision.pt2.x = imagePos.x + imageSize.w - 1; + collision.pt2.y = imagePos.y + imageSize.h - 1; return nxgl_intersecting(&bounds, &collision); } diff --git a/graphics/twm4nx/src/ciconwidget.cxx b/graphics/twm4nx/src/ciconwidget.cxx index df44d2007..7d497c814 100644 --- a/graphics/twm4nx/src/ciconwidget.cxx +++ b/graphics/twm4nx/src/ciconwidget.cxx @@ -57,6 +57,8 @@ #include "graphics/twm4nx/ctwm4nx.hxx" #include "graphics/twm4nx/cfonts.hxx" #include "graphics/twm4nx/cwindow.hxx" +#include "graphics/twm4nx/cwindowfactory.hxx" +#include "graphics/twm4nx/cbackground.hxx" #include "graphics/twm4nx/ciconwidget.hxx" #include "graphics/twm4nx/twm4nx_widgetevents.hxx" #include "graphics/twm4nx/twm4nx_cursor.hxx" @@ -636,18 +638,18 @@ bool CIconWidget::iconGrab(FAR struct SEventMsg *eventmsg) // Indicate that dragging has started but the icon has not // yet been moved. - m_dragging = true; - m_moved = false; + m_dragging = true; + m_moved = false; + m_collision = false; // Get the icon position. - struct nxgl_point_s widgetPos; - getPos(widgetPos); + getPos(m_dragPos); // Determine the relative position of the icon and the mouse - m_dragOffset.x = widgetPos.x - eventmsg->pos.x; - m_dragOffset.y = widgetPos.y - eventmsg->pos.y; + m_dragOffset.x = m_dragPos.x - eventmsg->pos.x; + m_dragOffset.y = m_dragPos.y - eventmsg->pos.y; #ifdef CONFIG_TWM4NX_MOUSE // Select the grab cursor image @@ -655,7 +657,8 @@ bool CIconWidget::iconGrab(FAR struct SEventMsg *eventmsg) m_twm4nx->setCursorImage(&CONFIG_TWM4NX_GBCURSOR_IMAGE); #endif - // Remember the grab cursor size + // Remember the grab cursor size. This, of course, makes + // little since if we are using a touchscreen. m_dragCSize.w = CONFIG_TWM4NX_GBCURSOR_IMAGE.size.w; m_dragCSize.h = CONFIG_TWM4NX_GBCURSOR_IMAGE.size.h; @@ -712,14 +715,83 @@ bool CIconWidget::iconDrag(FAR struct SEventMsg *eventmsg) if (oldpos.x != newpos.x || oldpos.y != newpos.y) { - // Set the new window position + // Re-draw the widget at the new background window position. + // NOTE that this is done before moving erasing the old position which + // probably overlaps the new position. + disableDrawing(); if (!moveTo(newpos.x, newpos.y)) { twmerr("ERROR: moveTo() failed\n"); return false; } + // Redraw the background window in the rectangle previously occupied by + // the widget. + + struct nxgl_size_s widgetSize; + getSize(widgetSize); + + struct nxgl_rect_s bounds; + bounds.pt1.x = oldpos.x; + bounds.pt1.y = oldpos.y; + bounds.pt2.x = oldpos.x + widgetSize.w - 1; + bounds.pt2.y = oldpos.y + widgetSize.h - 1; + + FAR CBackground *backgd = m_twm4nx->getBackground(); + if (!backgd->redrawBackgroundWindow(&bounds, false)) + { + twmerr("ERROR: redrawBackgroundWindow() failed\n"); + return false; + } + + // Now redraw the icon in its new position + + enableDrawing(); + redraw(); + + // Check if the icon at this position intersects any reserved + // region on the background. If not, check if some other icon is + // already occupying this position + + + bounds.pt1.x = newpos.x; + bounds.pt1.y = newpos.y; + bounds.pt2.x = newpos.x + widgetSize.w - 1; + bounds.pt2.y = newpos.y + widgetSize.h - 1; + + struct nxgl_rect_s collision; + if (backgd->checkCollision(bounds, collision)) + { + // Yes.. Remember that we are at a colliding position when + // the if the icon is ungrabbed. + + m_collision = true; + } + + // No.. Check if some other icon is already occupying this + // position + + else + { + FAR CWindowFactory *factory = m_twm4nx->getWindowFactory(); + if (factory->checkCollision(m_parent, bounds, collision)) + { + // Yes.. Remember that we are at a colliding position when + // the if the icon is ungrabbed. + + m_collision = true; + } + else + { + // No collision.. Remember the last good position + + m_dragPos.x = newpos.x; + m_dragPos.y = newpos.y; + m_collision = false; + } + } + // The icon was moved... we are really dragging! m_moved = true; @@ -755,6 +827,8 @@ bool CIconWidget::iconUngrab(FAR struct SEventMsg *eventmsg) m_twm4nx->setCursorImage(&CONFIG_TWM4NX_CURSOR_IMAGE); #endif + bool success = true; + // There are two possibilities: (1) The icon was moved. In this case, we // leave the icon up and in its new position. Or (2) the icon was simply // clicked in which case we need to de-iconify the window. We also check @@ -766,10 +840,60 @@ bool CIconWidget::iconUngrab(FAR struct SEventMsg *eventmsg) m_parent->deIconify(); } + // Another possibility is that the icon was drug into a position that + // collides with a reserved area on the background or that overlaps another + // icon. In that case, we need to revert to last known good position. + + else if (m_dragging && m_collision) + { + // Get the current, colliding position. + + struct nxgl_point_s oldpos; + getPos(oldpos); + + // Move the widget to the last known good position. + // NOTE that this is done before moving erasing the old position which + // probably overlaps the new position. + + disableDrawing(); + if (!moveTo(m_dragPos.x, m_dragPos.y)) + { + twmerr("ERROR: moveTo() failed\n"); + success = false; + } + else + { + // Redraw the background window in the rectangle previously occupied + // by the widget. + + struct nxgl_size_s widgetSize; + getSize(widgetSize); + + struct nxgl_rect_s bounds; + bounds.pt1.x = oldpos.x; + bounds.pt1.y = oldpos.y; + bounds.pt2.x = oldpos.x + widgetSize.w - 1; + bounds.pt2.y = oldpos.y + widgetSize.h - 1; + + FAR CBackground *backgd = m_twm4nx->getBackground(); + if (!backgd->redrawBackgroundWindow(&bounds, false)) + { + twmerr("ERROR: redrawBackgroundWindow() failed\n"); + return false; + } + + // Now redraw the icon in its new position + + enableDrawing(); + redraw(); + } + } + // Indicate no longer dragging - m_dragging = false; - m_moved = false; + m_dragging = false; + m_collision = false; + m_moved = false; - return true; + return success; } diff --git a/graphics/twm4nx/src/cwindowfactory.cxx b/graphics/twm4nx/src/cwindowfactory.cxx index 0b71a6e5c..efa8f4007 100644 --- a/graphics/twm4nx/src/cwindowfactory.cxx +++ b/graphics/twm4nx/src/cwindowfactory.cxx @@ -349,7 +349,7 @@ bool CWindowFactory::placeIcon(FAR CWindow *cwin, iconBounds.pt2.y = tmppos.y + iconSize.h - 1; // Check if this box intersects any reserved region on the background. - // If nt, check if so other icon is already occupying this position + // If not, check if some other icon is already occupying this position struct nxgl_rect_s collision; if (!backgd->checkCollision(iconBounds, collision) && @@ -435,6 +435,60 @@ void CWindowFactory::redrawIcons(FAR const nxgl_rect_s *nxRect) } } +/** + * Check if the icon within iconBounds collides with any other icon on the + * desktop. + * + * @param cwin The window containing the Icon of interest + * @param iconBounds The candidate Icon bounding box + * @param collision The bounding box of the icon that the candidate collides + * with + * @return Returns true if there is a collision + */ + +bool CWindowFactory::checkCollision(FAR CWindow *cwin, + FAR const struct nxgl_rect_s &iconBounds, + FAR struct nxgl_rect_s &collision) +{ + // Try every window + + for (FAR struct SWindow *win = m_windowHead; + win != (FAR struct SWindow *)0; + win = win->flink) + { + // Ignore 'this' window, any windows that are not iconified, and any + // windows that have no icons. + + if (win->cwin != cwin && win->cwin->hasIcon() && + win->cwin->isIconified()) + { + // Create a bounding box for the icon + + struct nxgl_size_s iconSize; + (void)win->cwin->getIconWidgetSize(iconSize); + + struct nxgl_point_s iconPos; + (void)win->cwin->getIconWidgetPosition(iconPos); + + collision.pt1.x = iconPos.x; + collision.pt1.y = iconPos.y; + collision.pt2.x = iconPos.x + iconSize.w - 1; + collision.pt2.y = iconPos.y + iconSize.h - 1; + + // Return true if there is an intersection + + if (nxgl_intersecting(&iconBounds, &collision)) + { + return true; + } + } + } + + // No collision + + return false; +} + /** * Handle WINDOW events. * @@ -552,60 +606,6 @@ FAR struct SWindow *CWindowFactory::findWindow(FAR CWindow *cwin) return (FAR struct SWindow *)0; } -/** - * Check if the icon within iconBounds collides with any other icon on the - * desktop. - * - * @param cwin The window containing the Icon of interest - * @param iconBounds The candidate Icon bounding box - * @param collision The bounding box of the icon that the candidate collides - * with - * @return Returns true if there is a collision - */ - -bool CWindowFactory::checkCollision(FAR CWindow *cwin, - FAR const struct nxgl_rect_s &iconBounds, - FAR struct nxgl_rect_s &collision) -{ - // Try every window - - for (FAR struct SWindow *win = m_windowHead; - win != (FAR struct SWindow *)0; - win = win->flink) - { - // Ignore 'this' window, any windows that are not iconified, and any - // windows that have no icons. - - if (win->cwin != cwin && win->cwin->hasIcon() && - win->cwin->isIconified()) - { - // Create a bounding box for the icon - - struct nxgl_size_s iconSize; - (void)win->cwin->getIconWidgetSize(iconSize); - - struct nxgl_point_s iconPos; - (void)win->cwin->getIconWidgetPosition(iconPos); - - collision.pt1.x = iconPos.x; - collision.pt1.y = iconPos.y; - collision.pt2.x = iconPos.x + iconSize.w - 1; - collision.pt2.y = iconPos.y + iconSize.h - 1; - - // Return true if there is an intersection - - if (nxgl_intersecting(&iconBounds, &collision)) - { - return true; - } - } - } - - // No collision - - return false; -} - /** * This is the function that responds to the EVENT_WINDOW_DESKTOP. It * iconifies all windows so that the desktop is visible. diff --git a/include/graphics/twm4nx/ciconwidget.hxx b/include/graphics/twm4nx/ciconwidget.hxx index 1b91a401f..65aae1d0a 100644 --- a/include/graphics/twm4nx/ciconwidget.hxx +++ b/include/graphics/twm4nx/ciconwidget.hxx @@ -179,10 +179,11 @@ namespace Twm4Nx // Dragging - struct nxgl_point_s m_dragPos; /**< Last mouse position */ + struct nxgl_point_s m_dragPos; /**< Last good icon position */ struct nxgl_point_s m_dragOffset; /**< Offset from mouse to window origin */ struct nxgl_size_s m_dragCSize; /**< The grab cursor size */ bool m_dragging; /**< Drag in-progress */ + bool m_collision; /**< Current position collides */ bool m_moved; /**< Icon has been moved */ /** diff --git a/include/graphics/twm4nx/cwindowfactory.hxx b/include/graphics/twm4nx/cwindowfactory.hxx index c12ac1d46..51af6dfc3 100644 --- a/include/graphics/twm4nx/cwindowfactory.hxx +++ b/include/graphics/twm4nx/cwindowfactory.hxx @@ -179,21 +179,6 @@ namespace Twm4Nx FAR struct SWindow *findWindow(FAR CWindow *cwin); - /** - * Check if the icon within iconBounds collides with any other icon on - * the desktop. - * - * @param cwin The window containing the Icon of interest - * @param iconBounds The candidate Icon bounding box - * @param collision The bounding box of the icon that the candidate - * collides with - * @return Returns true if there is a collision - */ - - bool checkCollision(FAR CWindow *cwin, - FAR const struct nxgl_rect_s &iconBounds, - FAR struct nxgl_rect_s &collision); - /** * This is the function that responds to the EVENT_WINDOW_DESKTOP. It * iconifies all windows so that the desktop is visible. @@ -295,6 +280,21 @@ namespace Twm4Nx void redrawIcons(FAR const nxgl_rect_s *nxRect); + /** + * Check if the icon within iconBounds collides with any other icon on + * the desktop. + * + * @param cwin The window containing the Icon of interest + * @param iconBounds The candidate Icon bounding box + * @param collision The bounding box of the icon that the candidate + * collides with + * @return Returns true if there is a collision + */ + + bool checkCollision(FAR CWindow *cwin, + FAR const struct nxgl_rect_s &iconBounds, + FAR struct nxgl_rect_s &collision); + /** * Handle WINDOW events. *