#include <nuttx/config.h>
#include <cerrno>
#include <fcntl.h>
#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"
using namespace Twm4Nx;
* CBackground Constructor
*
* @param hWnd - NX server handle
*/
CBackground::CBackground(FAR CTwm4Nx *twm4nx)
{
m_twm4nx = twm4nx;
m_eventq = (mqd_t)-1;
m_backWindow = (NXWidgets::CBgWindow *)0;
#ifdef CONFIG_TWM4NX_BACKGROUND_HASIMAGE
m_backImage = (NXWidgets::CImage *)0;
#endif
}
* CBackground Destructor
*/
CBackground::~CBackground(void)
{
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");
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;
}
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");
#ifdef CONFIG_TWM4NX_BACKGROUND_HASIMAGE
if (!createBackgroundImage(sbitmap))
{
twmerr("ERROR: Failed to create the background image\n");
cleanup();
return false;
}
#endif
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)
{
NXWidgets::CWidgetControl *control = m_backWindow->getWidgetControl();
NXWidgets::CRect rect = control->getWindowBoundingBox();
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)
{
#ifdef CONFIG_TWM4NX_BACKGROUND_HASIMAGE
if (m_backImage != (NXWidgets::CImage *)0)
{
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);
}
#endif
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");
NXWidgets::CWidgetControl *control = m_backWindow->getWidgetControl();
NXWidgets::CGraphicsPort *port = control->getGraphicsPort();
struct nxgl_size_s redrawSize;
redrawSize.w = rect->pt2.x - rect->pt1.x + 1;
redrawSize.h = rect->pt2.y - rect->pt1.y + 1;
port->drawFilledRect(rect->pt1.x, rect->pt1.y,
redrawSize.w, redrawSize.h,
CONFIG_TWM4NX_DEFAULT_BACKGROUNDCOLOR);
#ifdef CONFIG_TWM4NX_BACKGROUND_HASIMAGE
if (m_backImage != (NXWidgets::CImage *)0)
{
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))
{
m_backImage->enableDrawing();
m_backImage->redraw();
}
}
#endif
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);
bool success = true;
switch (eventmsg->eventID)
{
case EVENT_BACKGROUND_XYINPUT:
{
NXWidgets::CWidgetControl *control =
m_backWindow->getWidgetControl();
FAR struct SXyInputEventMsg *xymsg =
(FAR struct SXyInputEventMsg *)eventmsg;
if (!control->pollEvents())
{
showMainMenu(xymsg->pos, xymsg->buttons);
}
#ifdef CONFIG_TWM4NX_BACKGROUND_HASIMAGE
else if (m_backImage != (NXWidgets::CImage *)0 &&
m_backImage->isClicked())
{
showMainMenu(xymsg->pos, xymsg->buttons);
}
#endif
}
break;
case EVENT_BACKGROUND_REDRAW:
{
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)
{
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;
events.deleteEvent = EVENT_WINDOW_DELETE;
FAR CWindowEvent *control =
new CWindowEvent(m_twm4nx, (FAR void *)0, events);
m_backWindow = m_twm4nx->getBgWindow(control);
if (m_backWindow == (FAR NXWidgets::CBgWindow *)0)
{
twmerr("ERROR: Failed to create BG window\n");
return false;
}
if (!m_backWindow->open())
{
twmerr("ERROR: Failed to open the BG window\n");
delete m_backWindow;
m_backWindow = (FAR NXWidgets::CBgWindow *)0;
return false;
}
NXWidgets::CGraphicsPort *port = control->getGraphicsPort();
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;
}
port->drawFilledRect(0, 0, windowSize.w, windowSize.h,
CONFIG_TWM4NX_DEFAULT_BACKGROUNDCOLOR);
return true;
}
* Create the background image.
*
* @return true on success
*/
#ifdef CONFIG_TWM4NX_BACKGROUND_HASIMAGE
bool CBackground::
createBackgroundImage(FAR const struct NXWidgets::SRlePaletteBitmap *sbitmap)
{
struct nxgl_size_s windowSize;
if (!m_backWindow->getSize(&windowSize))
{
twmerr("ERROR: getSize failed\n");
return false;
}
NXWidgets::CWidgetControl *control = m_backWindow->getWidgetControl();
NXWidgets::CRlePaletteBitmap *cbitmap =
new NXWidgets::CRlePaletteBitmap(sbitmap);
if (cbitmap == (NXWidgets::CRlePaletteBitmap *)0)
{
twmerr("ERROR: Failed to create bitmap\n");
return false;
}
struct nxgl_size_s imageSize;
imageSize.w = cbitmap->getWidth();
imageSize.h = (nxgl_coord_t)cbitmap->getHeight();
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;
}
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;
}
m_backImage->setBorderless(true);
m_backImage->setRaisesEvents(true);
m_backImage->enable();
m_backImage->enableDrawing();
m_backImage->redraw();
return true;
}
#endif
* Bring up the main menu (if it is not already up).
*
* @param pos The window click position.
* @param buttons The set of mouse button presses.
*/
void CBackground::showMainMenu(FAR struct nxgl_point_s &pos,
uint8_t buttons)
{
FAR CMainMenu *cmain = m_twm4nx->getMainMenu();
if (!cmain->isVisible() && (buttons & MOUSE_BUTTON_1) != 0)
{
struct SEventMsg outmsg;
outmsg.eventID = EVENT_MAINMENU_SELECT;
outmsg.pos.x = pos.x;
outmsg.pos.y = 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);
}
}
}
* Release resources held by the background.
*/
void CBackground::cleanup(void)
{
if (m_eventq != (mqd_t)-1)
{
mq_close(m_eventq);
m_eventq = (mqd_t)-1;
}
#ifdef CONFIG_TWM4NX_BACKGROUND_HASIMAGE
if (m_backImage != (NXWidgets::CImage *)0)
{
delete m_backImage;
m_backImage = (NXWidgets::CImage *)0;
}
#endif
if (m_backWindow != (NXWidgets::CBgWindow *)0)
{
NXWidgets::CWidgetControl *control = m_backWindow->getWidgetControl();
if (control != (NXWidgets::CWidgetControl *)0)
{
delete control;
}
delete m_backWindow;
m_backWindow = (NXWidgets::CBgWindow *)0;
}
}