| ///////////////////////////////////////////////////////////////////////////// |
| // apps/graphics/twm4nx/src/cresize.cxx |
| // |
| // Copyright (C) 2019 Gregory Nutt. All rights reserved. |
| // Author: Gregory Nutt <gnutt@nuttx.org> |
| // |
| // Largely an original work but derives from TWM 1.0.10 in many ways: |
| // |
| // Copyright 1989,1998 The Open Group |
| // Copyright 1988 by Evans & Sutherland Computer Corporation, |
| // |
| // Please refer to apps/twm4nx/COPYING for detailed copyright information. |
| // Although not listed as a copyright holder, thanks and recognition need |
| // to go to Tom LaStrange, the original author of TWM. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions |
| // are met: |
| // |
| // 1. Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // 2. Redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in |
| // the documentation and/or other materials provided with the |
| // distribution. |
| // 3. Neither the name NuttX nor the names of its contributors may be |
| // used to endorse or promote products derived from this software |
| // without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
| // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| // POSSIBILITY OF SUCH DAMAGE. |
| // |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Included Files |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| #include <cstdio> |
| #include <cerrno> |
| |
| #include <nuttx/nx/nxbe.h> |
| |
| #include "graphics/nxwidgets/cnxfont.hxx" |
| #include "graphics/nxwidgets/clabel.hxx" |
| |
| #include "graphics/twm4nx/twm4nx_config.hxx" |
| #include "graphics/twm4nx/ctwm4nx.hxx" |
| #include "graphics/twm4nx/cmenus.hxx" |
| #include "graphics/twm4nx/ciconmgr.hxx" |
| #include "graphics/twm4nx/cwindowevent.hxx" |
| #include "graphics/twm4nx/cfonts.hxx" |
| #include "graphics/twm4nx/cwindow.hxx" |
| #include "graphics/twm4nx/ctwm4nxevent.hxx" |
| #include "graphics/twm4nx/twm4nx_events.hxx" |
| #include "graphics/twm4nx/cresize.hxx" |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Pre-processor Definitions |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| #define MINHEIGHT 0 // had been 32 |
| #define MINWIDTH 0 // had been 60 |
| |
| #define makemult(a,b) ((b==1) ? (a) : (((int)((a) / (b))) * (b))) |
| |
| #ifndef MIN |
| # define MIN(a,b) (((a) < (b)) ? (a) : (b)) |
| #endif |
| |
| ///////////////////////////////////////////////////////////////////////////// |
| // Class Implementations |
| ///////////////////////////////////////////////////////////////////////////// |
| |
| using namespace Twm4Nx; |
| |
| /** |
| * CResize Constructor |
| */ |
| |
| CResize::CResize(CTwm4Nx *twm4nx) |
| { |
| m_twm4nx = twm4nx; // Save the Twm4Nx session |
| m_eventq = (mqd_t)-1; // No widget message queue yet |
| m_sizeWindow = (FAR NXWidgets::CNxTkWindow *)0; // No resize dimension windows yet |
| m_sizeLabel = (FAR NXWidgets::CLabel *)0; // No resize dismsion label |
| m_resizeWindow = (FAR CWindow *)0; // The window being resized |
| m_savedTap = (FAR IEventTap *)0; // Saved IEventTap |
| m_savedTapArg = 0; // Saved IEventTap argument |
| m_lastPos.x = 0; // Last window position |
| m_lastPos.y = 0; |
| m_lastSize.w = 0; // Last window size |
| m_lastSize.h = 0; |
| m_mousePos.x = 0; // Last mouse position |
| m_resizing = false; // No resize in progress |
| m_resized = false; // The size has not changed |
| m_mouseValid = false; // The mouse position is not valid |
| m_paused = false; // The window was not un-clicked |
| } |
| |
| /** |
| * CResize Destructor |
| */ |
| |
| CResize::~CResize(void) |
| { |
| // Close the NxWidget event message queue |
| |
| if (m_eventq != (mqd_t)-1) |
| { |
| (void)mq_close(m_eventq); |
| m_eventq = (mqd_t)-1; |
| } |
| |
| // Delete the resize dimension label |
| |
| if (m_sizeLabel != (FAR NXWidgets::CLabel *)0) |
| { |
| delete m_sizeLabel; |
| m_sizeLabel = (FAR NXWidgets::CLabel *)0; |
| } |
| |
| // Delete the resize dimensions window |
| |
| if (m_sizeWindow != (FAR NXWidgets::CNxTkWindow *)0) |
| { |
| delete m_sizeWindow; |
| m_sizeWindow = (FAR NXWidgets::CNxTkWindow *)0; |
| } |
| } |
| |
| /** |
| * CResize Initializer. Performs the parts of the CResize construction |
| * that may fail. |
| * |
| * @result True is returned on success |
| */ |
| |
| bool CResize::initialize(void) |
| { |
| // Open a message queue to NX events. |
| |
| FAR const char *mqname = m_twm4nx->getEventQueueName(); |
| m_eventq = mq_open(mqname, O_WRONLY | O_NONBLOCK); |
| if (m_eventq == (mqd_t)-1) |
| { |
| twmerr("ERROR: Failed open message queue '%s': %d\n", |
| mqname, errno); |
| return false; |
| } |
| |
| // Create the size window |
| |
| if (!createSizeWindow()) |
| { |
| twmerr("ERROR: Failed to create menu window\n"); |
| return false; |
| } |
| |
| // Create the size label widget |
| |
| if (!createSizeLabel()) |
| { |
| twmerr("ERROR: Failed to recreate size label\n"); |
| |
| delete m_sizeWindow; |
| m_sizeWindow = (FAR NXWidgets::CNxTkWindow *)0; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Handle RESIZE events. |
| * |
| * @param eventmsg. The received NxWidget RESIZE event message. |
| * @return True if the message was properly handled. false is |
| * return on any failure. |
| */ |
| |
| bool CResize::event(FAR struct SEventMsg *eventmsg) |
| { |
| bool success = true; |
| |
| switch (eventmsg->eventID) |
| { |
| case EVENT_RESIZE_XYINPUT: |
| { |
| // Poll for XY input -- None is needed at present |
| } |
| break; |
| |
| case EVENT_RESIZE_BUTTON: |
| { |
| // Start the resize operation on the first resize button press |
| // (with m_resizing == false); Stop the resize operation on the |
| // second resize button press (with m_resizing == true) |
| |
| if (m_resizing) |
| { |
| success = endResize(eventmsg); |
| } |
| else |
| { |
| success = startResize(eventmsg); |
| } |
| } |
| break; |
| |
| case EVENT_RESIZE_MOVE: |
| { |
| // Update window size when a new mouse position is available |
| |
| success = updateSize(eventmsg); |
| } |
| break; |
| |
| case EVENT_RESIZE_PAUSE: |
| { |
| // Pause the resizee operation when the window is unclicked |
| |
| success = pauseResize(eventmsg); |
| } |
| break; |
| |
| case EVENT_RESIZE_RESUME: |
| { |
| // Resume the resize operation if the window is re-clicked |
| |
| success = resumeResize(eventmsg); |
| } |
| break; |
| |
| default: |
| success = false; |
| break; |
| } |
| |
| return success; |
| } |
| |
| /** |
| * Create the size window |
| */ |
| |
| bool CResize::createSizeWindow(void) |
| { |
| // Create the main window |
| // 1. Get the server instance. m_twm4nx inherits from NXWidgets::CNXServer |
| // so we all ready have the server instance. |
| // 2. Create the style, using the selected colors (REVISIT) |
| |
| // 3. Create a Widget control instance for the window using the default |
| // style for now. CWindowEvent derives from CWidgetControl. |
| |
| struct SAppEvents events; |
| events.eventObj = (FAR void *)this; |
| events.redrawEvent = EVENT_SYSTEM_NOP; |
| events.mouseEvent = EVENT_RESIZE_XYINPUT; |
| events.kbdEvent = EVENT_SYSTEM_NOP; |
| events.closeEvent = EVENT_SYSTEM_NOP; |
| |
| FAR CWindowEvent *control = |
| new CWindowEvent(m_twm4nx, (FAR CWindow *)0, events); |
| |
| // 4. Create the main window |
| |
| uint8_t wflags = (NXBE_WINDOW_RAMBACKED | NXBE_WINDOW_HIDDEN); |
| |
| m_sizeWindow = m_twm4nx->createFramedWindow(control, wflags); |
| if (m_sizeWindow == (FAR NXWidgets::CNxTkWindow *)0) |
| { |
| delete control; |
| return false; |
| } |
| |
| // 5. Open and initialize the main window |
| |
| bool success = m_sizeWindow->open(); |
| if (!success) |
| { |
| delete m_sizeWindow; |
| m_sizeWindow = (FAR NXWidgets::CNxTkWindow *)0; |
| return false; |
| } |
| |
| // 6. Set the initial window size |
| |
| // Create the resize dimension window |
| |
| FAR CFonts *fonts = m_twm4nx->getFonts(); |
| FAR NXWidgets::CNxFont *sizeFont = fonts->getSizeFont(); |
| |
| struct nxgl_size_s size; |
| size.w = sizeFont->getStringWidth(" 8888 x 8888 "); |
| size.h = sizeFont->getHeight() + CONFIG_TWM4NX_ICONMGR_VSPACING * 2; |
| |
| if (!m_sizeWindow->setSize(&size)) |
| { |
| delete m_sizeWindow; |
| m_sizeWindow = (FAR NXWidgets::CNxTkWindow *)0; |
| return false; |
| } |
| |
| // 7. Set the initial window position |
| |
| struct nxgl_point_s pos = |
| { |
| .x = 0, |
| .y = 0 |
| }; |
| |
| if (!m_sizeWindow->setPosition(&pos)) |
| { |
| delete m_sizeWindow; |
| m_sizeWindow = (FAR NXWidgets::CNxTkWindow *)0; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Create the size label widget |
| */ |
| |
| bool CResize::createSizeLabel(void) |
| { |
| // The size of label is selected to fill the entire size window |
| |
| struct nxgl_size_s labelSize; |
| if (!m_sizeWindow->getSize(&labelSize)) |
| { |
| twmerr("ERROR: Failed to get window size\n"); |
| return false; |
| } |
| |
| // Position the label at the origin of the window. |
| |
| struct nxgl_point_s labelPos; |
| labelPos.x = 0; |
| labelPos.y = 0; |
| |
| // Get the Widget control instance from the size window. This |
| // will force all widget drawing to go to the size window. |
| |
| FAR NXWidgets:: CWidgetControl *control = |
| m_sizeWindow->getWidgetControl(); |
| |
| if (control == (FAR NXWidgets:: CWidgetControl *)0) |
| { |
| // Should not fail |
| |
| return false; |
| } |
| |
| // Create the size label widget |
| |
| m_sizeLabel = new NXWidgets::CLabel(control, labelPos.x, labelPos.y, |
| labelSize.w, labelSize.h, |
| " 8888 x 8888 "); |
| if (m_sizeLabel == (FAR NXWidgets::CLabel *)0) |
| { |
| twmerr("ERROR: Failed to construct size label widget\n"); |
| return false; |
| } |
| |
| // Configure the size label |
| |
| FAR CFonts *fonts = m_twm4nx->getFonts(); |
| FAR NXWidgets::CNxFont *sizeFont = fonts->getSizeFont(); |
| |
| m_sizeLabel->setFont(sizeFont); |
| m_sizeLabel->setBorderless(true); |
| m_sizeLabel->disableDrawing(); |
| m_sizeLabel->setTextAlignmentHoriz(NXWidgets::CLabel::TEXT_ALIGNMENT_HORIZ_CENTER); |
| m_sizeLabel->setTextAlignmentVert(NXWidgets::CLabel::TEXT_ALIGNMENT_VERT_CENTER); |
| m_sizeLabel->setRaisesEvents(false); |
| |
| // Register to get events from the mouse clicks on the image |
| |
| m_sizeLabel->addWidgetEventHandler(this); |
| return true; |
| } |
| |
| /** |
| * Set the Window Size |
| */ |
| |
| bool CResize::setWindowSize(FAR struct nxgl_size_s *size) |
| { |
| // Set the window size |
| |
| if (!m_sizeWindow->setSize(size)) |
| { |
| return false; |
| } |
| |
| // Set the label size to match |
| |
| if (!m_sizeLabel->resize(size->w, size->h)) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Update the size show in the size dimension label. |
| * |
| * @param windowSize The new size of the window |
| */ |
| |
| void CResize::updateSizeLabel(FAR struct nxgl_size_s &windowSize) |
| { |
| // Do nothing if the size has not changed |
| |
| struct nxgl_size_s labelSize; |
| m_sizeLabel->getSize(labelSize); |
| |
| if (labelSize.w == windowSize.w && labelSize.h == windowSize.h) |
| { |
| return; |
| } |
| |
| FAR char *str; |
| (void)asprintf(&str, " %4d x %-4d ", windowSize.w, windowSize.h); |
| if (str == (FAR char *)0) |
| { |
| twmerr("ERROR: Failed to get size string\n"); |
| return; |
| } |
| |
| // Un-hide the window and bring the window to the top of the hierarchy |
| |
| m_sizeWindow->show(); |
| |
| // Add the string to the label widget |
| |
| m_sizeLabel->disableDrawing(); |
| m_sizeLabel->setRaisesEvents(false); |
| |
| m_sizeLabel->setText(str); |
| std::free(str); |
| |
| // Re-enable and redraw the label widget |
| |
| m_sizeLabel->enableDrawing(); |
| m_sizeLabel->setRaisesEvents(true); |
| m_sizeLabel->redraw(); |
| } |
| |
| /** |
| * This function handles the EVENT_RESIZE_BUTTON event. It will start a new |
| * resize sequence. This occurs the first time that the toolbar resize |
| * icon resize icon is clicked. |
| * |
| * @param msg. The received NxWidget RESIZE event message. |
| * @return True if the message was properly handled. false is |
| * return on any failure. |
| */ |
| |
| bool CResize::startResize(FAR struct SEventMsg *eventmsg) |
| { |
| // Save the window that we are operating on |
| |
| m_resizeWindow = (FAR CWindow *)eventmsg->obj; |
| |
| // Get the window current position and size |
| |
| if (!m_resizeWindow->getFramePosition(&m_lastPos)) |
| { |
| gerr("ERROR: Failed to get frame position"); |
| return false; |
| } |
| |
| if (!m_resizeWindow->getFrameSize(&m_lastSize)) |
| { |
| gerr("ERROR: Failed to get frame size"); |
| return false; |
| } |
| |
| // Save the current touch position |
| |
| m_mousePos.x = eventmsg->pos.x; |
| m_mousePos.y = eventmsg->pos.y; |
| m_mouseValid = false; // RESVISIT: Why is position invalid? |
| |
| // Update the size label |
| |
| updateSizeLabel(m_lastSize); |
| |
| // Disable all other toolbar buttons |
| |
| m_resizeWindow->disableToolbarButtons(DISABLE_MENU_BUTTON | |
| DISABLE_DELETE_BUTTON | |
| DISABLE_MINIMIZE_BUTTON); |
| |
| // Unhide the size window |
| |
| m_sizeWindow->show(); |
| |
| // Set up the temporary event tap |
| |
| m_resizeWindow->getEventTap(m_savedTap, m_savedTapArg); |
| m_resizeWindow->installEventTap(this, (uintptr_t)0); |
| |
| // Make the size window modal so that it will stay at the top of the |
| // hierarchy |
| |
| m_sizeWindow->modal(true); |
| m_resizing = true; |
| m_resized = false; |
| |
| #ifdef CONFIG_TWM4NX_MOUSE |
| // Select the resize cursor |
| |
| # warning Missing logic |
| #endif |
| |
| return true; |
| } |
| |
| /** |
| * This function handles the EVENT_RESIZE_MOVE event. It will update |
| * the resize information based on the new mouse position. |
| * |
| * @param msg. The received NxWidget RESIZE event message. |
| * @return True if the message was properly handled. false is |
| * return on any failure. |
| */ |
| |
| bool CResize::updateSize(FAR struct SEventMsg *eventmsg) |
| { |
| // REVISIT: This is a kludge. It appears that in startResize(), the |
| // received mouse position is always (0,0). So we have to waste one update |
| // to get a valid size. |
| |
| if (!m_mouseValid) |
| { |
| m_mousePos.x = eventmsg->pos.x; |
| m_mousePos.y = eventmsg->pos.y; |
| m_mouseValid = true; |
| return true; |
| } |
| |
| // The unconstrained, new window size is the old window size plus the |
| // change in the mouse position. |
| |
| struct nxgl_size_s newSize; |
| newSize.w = m_lastSize.w + eventmsg->pos.x - m_mousePos.x; |
| newSize.h = m_lastSize.h + eventmsg->pos.y - m_mousePos.y; |
| |
| // Create a bounding box for the new window |
| |
| struct nxgl_rect_s windowBounds; |
| windowBounds.pt1.x = m_lastPos.x; |
| windowBounds.pt1.y = m_lastPos.y; |
| windowBounds.pt2.x = m_lastPos.x + newSize.w - 1; |
| windowBounds.pt2.y = m_lastPos.y + newSize.h - 1; |
| |
| // If the new size could exceed the right limit of the window, then |
| // move the left position to keep the window within the display. |
| |
| struct nxgl_size_s displaySize; |
| m_twm4nx->getDisplaySize(&displaySize); |
| |
| if (windowBounds.pt2.x >= displaySize.w) |
| { |
| // Stretch the left side and truncate the right side |
| |
| windowBounds.pt1.x = displaySize.w - newSize.w; |
| windowBounds.pt2.x = displaySize.w - 1; |
| |
| // Clip the left side if necessary |
| |
| if (windowBounds.pt1.x < 0) |
| { |
| windowBounds.pt1.x = 0; |
| } |
| } |
| |
| // If the new size could exceed the left limit of the window, then |
| // move the right position to keep the window within the display. |
| |
| else if (windowBounds.pt1.x < 0) |
| { |
| windowBounds.pt1.x = 0; |
| windowBounds.pt2.x = newSize.w - 1; |
| |
| // Clip the right side if necessary |
| |
| if (windowBounds.pt2.x >= displaySize.w) |
| { |
| windowBounds.pt2.x = displaySize.w - 1; |
| } |
| } |
| |
| // If the new size could exceed the bottom limit of the window, then |
| // move the top position to keep the window within the display. |
| |
| if (windowBounds.pt2.y >= displaySize.h) |
| { |
| // Stretch the left side and truncate the right side |
| |
| windowBounds.pt1.y = displaySize.h - newSize.h; |
| windowBounds.pt2.y = displaySize.h - 1; |
| |
| // Clip the top side if necessary |
| |
| if (windowBounds.pt1.y < 0) |
| { |
| windowBounds.pt1.y = 0; |
| } |
| } |
| |
| // If the new size could exceed the top limit of the window, then |
| // move the bottom position to keep the window within the display. |
| |
| else if (windowBounds.pt1.y < 0) |
| { |
| windowBounds.pt1.y = 0; |
| windowBounds.pt2.y = newSize.h - 1; |
| |
| // Clip the bottom side if necessary |
| |
| if (windowBounds.pt2.x > displaySize.h) |
| { |
| windowBounds.pt2.x = displaySize.h - 1; |
| } |
| } |
| |
| // Check if the size changed |
| |
| newSize.w = windowBounds.pt2.x - windowBounds.pt1.x + 1; |
| newSize.h = windowBounds.pt2.y - windowBounds.pt1.y + 1; |
| |
| // Don't do more unless the size has actually changed |
| |
| if (m_lastSize.w != newSize.h || m_lastSize.h != newSize.h) |
| { |
| // Do we want to try a continuous resize? If so, we should call |
| // m_resizeWindow->resizeFrame() here. This probably a bit much for the |
| // typical embedded MCU to handle. So we, instead, just display the |
| // updated size. The window will not be resized until the resize button |
| // is pressed a second time. |
| |
| updateSizeLabel(newSize); |
| m_resized = true; |
| } |
| |
| // Reset every thing in preparation for the next mouse report |
| |
| m_lastSize.w = newSize.w; |
| m_lastSize.h = newSize.h; |
| m_lastPos.x = windowBounds.pt1.x; |
| m_lastPos.y = windowBounds.pt1.y; |
| m_mousePos.x = eventmsg->pos.x; |
| m_mousePos.y = eventmsg->pos.y; |
| |
| return true; |
| } |
| |
| /** |
| * This function handles the EVENT_RESIZE_PAUSE event. This occurs |
| * when the window is un-clicked. Another click in the window |
| * will resume the resize operation. |
| * |
| * @param msg. The received NxWidget RESIZE event message. |
| * @return True if the message was properly handled. false is |
| * return on any failure. |
| */ |
| |
| bool CResize::pauseResize(FAR struct SEventMsg *eventmsg) |
| { |
| // m_paused should have already been set asychronously |
| |
| bool success = false; |
| if (m_paused) |
| { |
| // One last update to the mouse release position |
| |
| if (!updateSize(eventmsg)) |
| { |
| gerr("ERROR: Failed to update the window size\n"); |
| } |
| |
| // Set the new frame position and size if the size has changed |
| |
| else if (m_resized && !m_resizeWindow->resizeFrame(&m_lastSize, &m_lastPos)) |
| { |
| twmerr("ERROR: Failed to resize frame\n"); |
| } |
| else |
| { |
| m_resized = false; |
| success = true; |
| } |
| } |
| |
| return success; |
| } |
| |
| /** |
| * This function handles the EVENT_RESIZE_RESUME event. This occurs |
| * when the window is clicked while paused. |
| * |
| * @param msg. The received NxWidget RESIZE event message. |
| * @return True if the message was properly handled. false is |
| * return on any failure. |
| */ |
| |
| bool CResize::resumeResize(FAR struct SEventMsg *eventmsg) |
| { |
| // Make sure the we are in the resizing state |
| |
| if (!m_resizing) |
| { |
| return false; |
| } |
| |
| #ifdef CONFIG_TWM4NX_MOUSE |
| // Restore the normal cursor |
| |
| # warning Missing logic |
| #endif |
| |
| // Reset the the window position and size |
| |
| if (!m_resizeWindow->getFramePosition(&m_lastPos)) |
| { |
| gerr("ERROR: Failed to get frame position"); |
| return false; |
| } |
| |
| if (!m_resizeWindow->getFrameSize(&m_lastSize)) |
| { |
| gerr("ERROR: Failed to get frame size"); |
| return false; |
| } |
| |
| // Save the current touch position |
| |
| m_mousePos.x = eventmsg->pos.x; |
| m_mousePos.y = eventmsg->pos.y; |
| |
| // Update the size label |
| |
| updateSizeLabel(m_lastSize); |
| return true; |
| } |
| |
| /** |
| * This function handles the EVENT_RESIZE_STOP event. It will terminate a |
| * resize sequence. |
| * |
| * @param msg. The received NxWidget RESIZE event message. |
| * @return True if the message was properly handled. false is |
| * return on any failure. |
| */ |
| |
| bool CResize::endResize(FAR struct SEventMsg *eventmsg) |
| { |
| // Make sure the we are in the resizing state |
| |
| if (!m_resizing) |
| { |
| return false; |
| } |
| |
| // Restore the event tap |
| |
| m_resizeWindow->installEventTap(m_savedTap, m_savedTapArg); |
| |
| // Re-enable toolbar buttons |
| |
| m_resizeWindow->disableToolbarButtons(DISABLE_NO_BUTTONS); |
| |
| // The size window should no longer be modal |
| |
| m_sizeWindow->modal(false); |
| |
| // Hide the size window |
| |
| m_sizeWindow->hide(); |
| |
| // Has the size changed? |
| |
| bool success = true; |
| if (m_resized) |
| { |
| // If the window was the Icon manager, then we need to deal with the |
| // contained widget. |
| |
| if (m_resizeWindow->isIconMgr()) |
| { |
| // Adjust the Icon Manager button array to account for the resize |
| |
| CIconMgr *iconMgr = m_resizeWindow->getIconMgr(); |
| iconMgr->resizeIconManager(); |
| } |
| |
| // Set the new window frame position and size |
| |
| if (!m_resizeWindow->resizeFrame(&m_lastSize, &m_lastPos)) |
| { |
| twmerr("ERROR: Failed to resize frame\n"); |
| success = false; |
| } |
| else |
| { |
| m_resized = false; |
| } |
| } |
| |
| m_resizing = false; |
| return success; |
| } |
| |
| /** |
| * This function is called when there is any movement of the mouse or |
| * touch position that would indicate that the object is being moved. |
| * |
| * This function overrides the virtual IEventTap::moveEvent method. |
| * |
| * @param pos The current mouse/touch X/Y position. |
| * @param arg The user-argument provided that accompanies the callback |
| * @return True: if the movement event was processed; false it was |
| * ignored. The event should be ignored if there is not actually |
| * a movement event in progress |
| */ |
| |
| bool CResize::moveEvent(FAR const struct nxgl_point_s &pos, |
| uintptr_t arg) |
| { |
| twminfo("MOVE event...\n"); |
| |
| // Send the aEVENT_RESIZE_MOVE event |
| |
| struct SEventMsg outmsg; |
| outmsg.eventID = EVENT_RESIZE_MOVE; |
| outmsg.obj = (FAR void *)this; |
| outmsg.pos.x = pos.x; |
| outmsg.pos.y = pos.y; |
| outmsg.context = EVENT_CONTEXT_RESIZE; |
| outmsg.handler = (FAR void *)0; |
| |
| int ret = mq_send(m_eventq, (FAR const char *)&outmsg, |
| sizeof(struct SEventMsg), 100); |
| if (ret < 0) |
| { |
| twmerr("ERROR: mq_send failed: %d\n", errno); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * This function is called if the mouse left button is released or |
| * if the touchscreen touch is lost. This indicates that the |
| * movement sequence is complete. |
| * |
| * In this usage, this indicates the end of a resize sequence. |
| * |
| * This function overrides the virtual IEventTap::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 drop event was processed; false it was |
| * ignored. The event should be ignored if there is not actually |
| * a movement event in progress |
| */ |
| |
| bool CResize::dropEvent(FAR const struct nxgl_point_s &pos, |
| uintptr_t arg) |
| { |
| twminfo("Drop event...\n"); |
| |
| // Send the aEVENT_RESIZE_PAUSE event |
| |
| struct SEventMsg outmsg; |
| outmsg.eventID = EVENT_RESIZE_PAUSE; |
| outmsg.obj = (FAR void *)this; |
| outmsg.pos.x = pos.x; |
| outmsg.pos.y = pos.y; |
| outmsg.context = EVENT_CONTEXT_RESIZE; |
| outmsg.handler = (FAR void *)0; |
| |
| int ret = mq_send(m_eventq, (FAR const char *)&outmsg, |
| sizeof(struct SEventMsg), 100); |
| if (ret < 0) |
| { |
| twmerr("ERROR: mq_send failed: %d\n", errno); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Enable/disable the resizing. The disable event will cause resizing |
| * to be paused. |
| * |
| * True is provided when (1) isActive() returns false, but (2) a mouse |
| * report with a left-click is received. |
| * False is provided when (1) isActive() returns true, but (2) a mouse |
| * report without a left-click is received. |
| * |
| * In the latter is redundant since dropEvent() will be called immediately |
| * afterward. |
| * |
| * @param pos. The mouse position at the time of the click or release |
| * @param enable. True: Enable the tap |
| * @param arg The user-argument provided that accompanies the callback |
| */ |
| |
| void CResize::enableMovement(FAR const struct nxgl_point_s &pos, |
| bool enable, uintptr_t arg) |
| { |
| // If we are already dragging, but paused, then send the resume event. |
| // NOTE that we don't have to do anything in pause case because we |
| // will get the redundant dropEvent |
| |
| if (m_paused && m_resizing) |
| { |
| // Send the aEVENT_RESIZE_RESUME event |
| |
| struct SEventMsg outmsg; |
| outmsg.eventID = EVENT_RESIZE_RESUME; |
| outmsg.obj = (FAR void *)this; |
| outmsg.pos.x = pos.x; |
| outmsg.pos.y = pos.y; |
| outmsg.context = EVENT_CONTEXT_RESIZE; |
| outmsg.handler = (FAR void *)0; |
| |
| int ret = mq_send(m_eventq, (FAR const char *)&outmsg, |
| sizeof(struct SEventMsg), 100); |
| if (ret < 0) |
| { |
| twmerr("ERROR: mq_send failed: %d\n", errno); |
| } |
| } |
| |
| // Otherwise, just track the state |
| |
| m_paused = !enable; |
| } |