apps/graphics/twm4nx: Other toolbar buttons need to be disabled while resizing. Lots of problems if you decide to iconify or exit while resizing. CResize now disables all buttons except for the RESIZE button while resizing. apps/graphics/twm4nx: Add an event and logic to support notification of changes in the size of a window to NxTerm. Various updates to adapt to change in boardctl() interface. apps/graphics/twm4nx: Correct an error in the NxTerm resize logic apps/graphics/twm4nx: Update debug output when failures to send a message occur. The returned value of -1 is not interested, need to show the errno value instead. apps/graphics/twm4nx: Correct the maximum size of a message. Recent changes caused message send failures because a message exceed that previous maximum size. apps/graphics/twm4nx: Fix routing of redraw events.
541 lines
15 KiB
C++
541 lines
15 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// apps/graphics/twm4nx/include/cbackground.cxx
|
|
// Manage background image
|
|
//
|
|
// Copyright (C) 2019 Gregory Nutt. All rights reserved.
|
|
// Author: Gregory Nutt <gnutt@nuttx.org>
|
|
//
|
|
// 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 <nuttx/config.h>
|
|
|
|
#include <cfcntl>
|
|
#include <cerrno>
|
|
|
|
#include <nuttx/nx/nxglib.h>
|
|
|
|
#include "graphics/nxwidgets/cscaledbitmap.hxx"
|
|
#include "graphics/nxwidgets/cbgwindow.hxx"
|
|
#include "graphics/nxwidgets/cwidgetcontrol.hxx"
|
|
#include "graphics/nxwidgets/crlepalettebitmap.hxx"
|
|
#include "graphics/nxwidgets/crect.hxx"
|
|
#include "graphics/nxwidgets/cimage.hxx"
|
|
|
|
#include "graphics/twm4nx/twm4nx_config.hxx"
|
|
#include "graphics/twm4nx/cwindowevent.hxx"
|
|
#include "graphics/twm4nx/cwindowfactory.hxx"
|
|
#include "graphics/twm4nx/cmainmenu.hxx"
|
|
#include "graphics/twm4nx/cbackground.hxx"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CBackground Method Implementations
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
using namespace Twm4Nx;
|
|
|
|
/**
|
|
* CBackground Constructor
|
|
*
|
|
* @param hWnd - NX server handle
|
|
*/
|
|
|
|
CBackground::CBackground(FAR CTwm4Nx *twm4nx)
|
|
{
|
|
m_twm4nx = twm4nx; // Save the session instance
|
|
m_eventq = (mqd_t)-1; // No NxWidget event message queue yet
|
|
m_backWindow = (NXWidgets::CBgWindow *)0; // No background window yet
|
|
m_backImage = (NXWidgets::CImage *)0; // No background image yet
|
|
}
|
|
|
|
/**
|
|
* CBackground Destructor
|
|
*/
|
|
|
|
CBackground::~CBackground(void)
|
|
{
|
|
// Free resources helf by the background
|
|
|
|
cleanup();
|
|
}
|
|
|
|
/**
|
|
* Finish construction of the background instance. This performs
|
|
* That are not appropriate for the constructor because they may
|
|
* fail.
|
|
*
|
|
* @param sbitmap. Identifies the bitmap to paint on background
|
|
* @return true on success
|
|
*/
|
|
|
|
bool CBackground::
|
|
initialize(FAR const struct NXWidgets::SRlePaletteBitmap *sbitmap)
|
|
{
|
|
twminfo("Create the background window\n");
|
|
|
|
// Open a message queue to send fully digested NxWidget 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 background window (if we have not already done so)
|
|
|
|
if (m_backWindow == (NXWidgets::CBgWindow *)0 &&
|
|
!createBackgroundWindow())
|
|
{
|
|
twmerr("ERROR: Failed to create the background window\n");
|
|
cleanup();
|
|
return false;
|
|
}
|
|
|
|
twminfo("Create the background image\n");
|
|
|
|
// Create the new background image
|
|
|
|
if (!createBackgroundImage(sbitmap))
|
|
{
|
|
twmerr("ERROR: Failed to create the background image\n");
|
|
cleanup();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get the size of the physical display device which is equivalent to
|
|
* size of the background window.
|
|
* size of the background window.
|
|
*
|
|
* @return The size of the display
|
|
*/
|
|
|
|
void CBackground::getDisplaySize(FAR struct nxgl_size_s &size)
|
|
{
|
|
// Get the widget control from the task bar window. The physical window geometry
|
|
// should be the same for all windows.
|
|
|
|
NXWidgets::CWidgetControl *control = m_backWindow->getWidgetControl();
|
|
|
|
// Get the window bounding box from the widget control
|
|
|
|
NXWidgets::CRect rect = control->getWindowBoundingBox();
|
|
|
|
// And return the size of the window
|
|
|
|
rect.getSize(size);
|
|
}
|
|
|
|
/**
|
|
* Check if the region within 'bounds' collides with any other reserved
|
|
* region on the desktop. This is used for icon placement.
|
|
*
|
|
* @param iconBounds The candidate bounding box
|
|
* @param collision The bounding box of the reserved region that the
|
|
* candidate collides with
|
|
* @return Returns true if there is a collision
|
|
*/
|
|
|
|
bool CBackground::checkCollision(FAR const struct nxgl_rect_s &bounds,
|
|
FAR struct nxgl_rect_s &collision)
|
|
{
|
|
// Is there a background image
|
|
|
|
if (m_backImage != (NXWidgets::CImage *)0)
|
|
{
|
|
// Create a bounding box for the background image
|
|
|
|
struct nxgl_size_s imageSize;
|
|
m_backImage->getSize(imageSize);
|
|
|
|
struct nxgl_point_s imagePos;
|
|
m_backImage->getPos(imagePos);
|
|
|
|
collision.pt1.x = imagePos.x;
|
|
collision.pt1.y = imagePos.y;
|
|
collision.pt2.x = imagePos.x + imageSize.w - 1;
|
|
collision.pt2.y = imagePos.y + imageSize.h - 1;
|
|
|
|
return nxgl_intersecting(&bounds, &collision);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Handle the background window redraw.
|
|
*
|
|
* @param nxRect The region in the window that must be redrawn.
|
|
* @param more True means that more re-draw requests will follow
|
|
* @return true on success
|
|
*/
|
|
|
|
bool CBackground::redrawBackgroundWindow(FAR const struct nxgl_rect_s *rect,
|
|
bool more)
|
|
{
|
|
twminfo("Redrawing..\n");
|
|
|
|
// Get the widget control from the background window
|
|
|
|
NXWidgets::CWidgetControl *control = m_backWindow->getWidgetControl();
|
|
|
|
// Get the graphics port for drawing on the background window
|
|
|
|
NXWidgets::CGraphicsPort *port = control->getGraphicsPort();
|
|
|
|
// Get the size of the region to redraw
|
|
|
|
struct nxgl_size_s redrawSize;
|
|
redrawSize.w = rect->pt2.x - rect->pt1.x + 1;
|
|
redrawSize.h = rect->pt2.y - rect->pt1.y + 1;
|
|
|
|
// Fill the redraw region with the background color
|
|
|
|
port->drawFilledRect(rect->pt1.x, rect->pt1.y,
|
|
redrawSize.w, redrawSize.h,
|
|
CONFIG_TWM4NX_DEFAULT_BACKGROUNDCOLOR);
|
|
|
|
if (m_backImage != (NXWidgets::CImage *)0)
|
|
{
|
|
// Does any part of the image need to be redrawn?
|
|
|
|
FAR NXWidgets::CRect cimageRect = m_backImage->getBoundingBox();
|
|
|
|
struct nxgl_rect_s imageRect;
|
|
cimageRect.getNxRect(&imageRect);
|
|
|
|
struct nxgl_rect_s intersection;
|
|
nxgl_rectintersect(&intersection, rect, &imageRect);
|
|
|
|
if (!nxgl_nullrect(&intersection))
|
|
{
|
|
// Then re-draw the background image on the window
|
|
|
|
m_backImage->enableDrawing();
|
|
m_backImage->redraw();
|
|
}
|
|
}
|
|
|
|
// Now redraw any background icons that need to be redrawn
|
|
|
|
FAR CWindowFactory *factory = m_twm4nx->getWindowFactory();
|
|
factory->redrawIcons(rect);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Handle EVENT_BACKGROUND events.
|
|
*
|
|
* @param eventmsg. The received NxWidget WINDOW event message.
|
|
* @return True if the message was properly handled. false is
|
|
* return on any failure.
|
|
*/
|
|
|
|
bool CBackground::event(FAR struct SEventMsg *eventmsg)
|
|
{
|
|
twminfo("eventID: %u\n", eventmsg->eventID);
|
|
|
|
// Handle the event
|
|
|
|
bool success = true;
|
|
switch (eventmsg->eventID)
|
|
{
|
|
case EVENT_BACKGROUND_XYINPUT: // Poll for icon mouse/touch events
|
|
{
|
|
// This event message is sent from CWindowEvent whenever mouse,
|
|
// touchscreen, or keyboard entry events are received in the
|
|
// background window.
|
|
|
|
NXWidgets::CWidgetControl *control =
|
|
m_backWindow->getWidgetControl();
|
|
|
|
// pollEvents() returns true if any interesting event occurred
|
|
// within a widget that is associated with the background window.
|
|
// false is not a failure.
|
|
|
|
if (!control->pollEvents())
|
|
{
|
|
// If there is no interesting widget event, then this might be
|
|
// a background click. In that case, we should bring up the
|
|
// main menu (if it is not already up).
|
|
|
|
// Is the main menu already up? Was the mouse left button
|
|
// pressed?
|
|
|
|
FAR struct SXyInputEventMsg *xymsg =
|
|
(FAR struct SXyInputEventMsg *)eventmsg;
|
|
|
|
FAR CMainMenu *cmain = m_twm4nx->getMainMenu();
|
|
if (!cmain->isVisible() &&
|
|
(xymsg->buttons & MOUSE_BUTTON_1) != 0)
|
|
{
|
|
// Bring up the main menu
|
|
|
|
struct SEventMsg outmsg;
|
|
outmsg.eventID = EVENT_MAINMENU_SELECT;
|
|
outmsg.pos.x = eventmsg->pos.x;
|
|
outmsg.pos.y = eventmsg->pos.y;
|
|
outmsg.context = EVENT_CONTEXT_BACKGROUND;
|
|
outmsg.handler = (FAR void *)0;
|
|
outmsg.obj = (FAR void *)this;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EVENT_BACKGROUND_REDRAW: // Redraw the background
|
|
{
|
|
FAR struct SRedrawEventMsg *redrawmsg =
|
|
(FAR struct SRedrawEventMsg *)eventmsg;
|
|
|
|
success = redrawBackgroundWindow(&redrawmsg->rect,
|
|
redrawmsg->more);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
success = false;
|
|
break;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
/**
|
|
* Create the background window.
|
|
*
|
|
* @return true on success
|
|
*/
|
|
|
|
bool CBackground::createBackgroundWindow(void)
|
|
{
|
|
// Create an instance of the background 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_BACKGROUND_REDRAW;
|
|
events.resizeEvent = EVENT_SYSTEM_NOP;
|
|
events.mouseEvent = EVENT_BACKGROUND_XYINPUT;
|
|
events.kbdEvent = EVENT_SYSTEM_NOP;
|
|
events.closeEvent = EVENT_SYSTEM_NOP;
|
|
|
|
FAR CWindowEvent *control =
|
|
new CWindowEvent(m_twm4nx, (FAR CWindow *)0, events);
|
|
|
|
// Create the background window (CTwm4Nx inherits from CNxServer)
|
|
|
|
m_backWindow = m_twm4nx->getBgWindow(control);
|
|
if (m_backWindow == (FAR NXWidgets::CBgWindow *)0)
|
|
{
|
|
twmerr("ERROR: Failed to create BG window\n");
|
|
return false;
|
|
}
|
|
|
|
// Open the background window
|
|
|
|
if (!m_backWindow->open())
|
|
{
|
|
twmerr("ERROR: Failed to open the BG window\n");
|
|
delete m_backWindow;
|
|
m_backWindow = (FAR NXWidgets::CBgWindow *)0;
|
|
return false;
|
|
}
|
|
|
|
// Get the graphics port for drawing on the background window
|
|
|
|
NXWidgets::CGraphicsPort *port = control->getGraphicsPort();
|
|
|
|
// Get the size of the region to redraw (the whole display)
|
|
|
|
struct nxgl_size_s windowSize;
|
|
if (!m_backWindow->getSize(&windowSize))
|
|
{
|
|
twmerr("ERROR: getSize failed\n");
|
|
delete m_backWindow;
|
|
m_backWindow = (FAR NXWidgets::CBgWindow *)0;
|
|
return false;
|
|
}
|
|
|
|
// Fill the display with the background color
|
|
|
|
port->drawFilledRect(0, 0, windowSize.w, windowSize.h,
|
|
CONFIG_TWM4NX_DEFAULT_BACKGROUNDCOLOR);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Create the background image.
|
|
*
|
|
* @return true on success
|
|
*/
|
|
|
|
bool CBackground::
|
|
createBackgroundImage(FAR const struct NXWidgets::SRlePaletteBitmap *sbitmap)
|
|
{
|
|
// Get the size of the display
|
|
|
|
struct nxgl_size_s windowSize;
|
|
if (!m_backWindow->getSize(&windowSize))
|
|
{
|
|
twmerr("ERROR: getSize failed\n");
|
|
return false;
|
|
}
|
|
|
|
// Get the widget control from the background window
|
|
|
|
NXWidgets::CWidgetControl *control = m_backWindow->getWidgetControl();
|
|
|
|
// Create the sbitmap object
|
|
|
|
NXWidgets::CRlePaletteBitmap *cbitmap =
|
|
new NXWidgets::CRlePaletteBitmap(sbitmap);
|
|
|
|
if (cbitmap == (NXWidgets::CRlePaletteBitmap *)0)
|
|
{
|
|
twmerr("ERROR: Failed to create bitmap\n");
|
|
return false;
|
|
}
|
|
|
|
// Get the size of the bitmap image
|
|
|
|
struct nxgl_size_s imageSize;
|
|
imageSize.w = cbitmap->getWidth();
|
|
imageSize.h = (nxgl_coord_t)cbitmap->getHeight();
|
|
|
|
// Pick an X/Y position such that the image will be centered in the display
|
|
|
|
struct nxgl_point_s imagePos;
|
|
if (imageSize.w >= windowSize.w)
|
|
{
|
|
imagePos.x = 0;
|
|
}
|
|
else
|
|
{
|
|
imagePos.x = (windowSize.w - imageSize.w) >> 1;
|
|
}
|
|
|
|
if (imageSize.h >= windowSize.h)
|
|
{
|
|
imagePos.y = 0;
|
|
}
|
|
else
|
|
{
|
|
imagePos.y = (windowSize.h - imageSize.h) >> 1;
|
|
}
|
|
|
|
// Now we have enough information to create the image
|
|
|
|
m_backImage = new NXWidgets::CImage(control, imagePos.x, imagePos.y,
|
|
imageSize.w, imageSize.h, cbitmap);
|
|
if (m_backImage == (NXWidgets::CImage *)0)
|
|
{
|
|
twmerr("ERROR: Failed to create CImage\n");
|
|
delete cbitmap;
|
|
return false;
|
|
}
|
|
|
|
// Configure and draw the background image
|
|
|
|
m_backImage->setBorderless(true);
|
|
m_backImage->setRaisesEvents(false);
|
|
|
|
m_backImage->enable();
|
|
m_backImage->enableDrawing();
|
|
m_backImage->redraw();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Release resources held by the background.
|
|
*/
|
|
|
|
void CBackground::cleanup(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 background image
|
|
|
|
if (m_backImage != (NXWidgets::CImage *)0)
|
|
{
|
|
delete m_backImage;
|
|
m_backImage = (NXWidgets::CImage *)0;
|
|
}
|
|
|
|
// Delete the background
|
|
|
|
if (m_backWindow != (NXWidgets::CBgWindow *)0)
|
|
{
|
|
// Delete the contained widget control. We are responsible for it
|
|
// because we created it
|
|
|
|
NXWidgets::CWidgetControl *control = m_backWindow->getWidgetControl();
|
|
if (control != (NXWidgets::CWidgetControl *)0)
|
|
{
|
|
delete control;
|
|
}
|
|
|
|
// Then delete the background
|
|
|
|
delete m_backWindow;
|
|
m_backWindow = (NXWidgets::CBgWindow *)0;
|
|
}
|
|
}
|