#include <nuttx/config.h>
#include <cstring>
#include <cassert>
#include <cerrno>
#include <fcntl.h>
#include <mqueue.h>
#include <nuttx/nx/nxglib.h>
#include <nuttx/nx/nxbe.h>
#include "graphics/nxglyphs.hxx"
#include "graphics/nxwidgets/cnxtkwindow.hxx"
#include "graphics/nxwidgets/cnxtoolbar.hxx"
#include "graphics/nxwidgets/crlepalettebitmap.hxx"
#include "graphics/nxwidgets/cscaledbitmap.hxx"
#include "graphics/nxwidgets/cimage.hxx"
#include "graphics/nxwidgets/clabel.hxx"
#include "graphics/nxwidgets/cnxfont.hxx"
#include "graphics/nxwidgets/singletons.hxx"
#include "graphics/nxwidgets/cwidgetstyle.hxx"
#include "graphics/twm4nx/twm4nx_config.hxx"
#include "graphics/twm4nx/ctwm4nx.hxx"
#include "graphics/twm4nx/cfonts.hxx"
#include "graphics/twm4nx/cresize.hxx"
#include "graphics/twm4nx/cbackground.hxx"
#include "graphics/twm4nx/ciconwidget.hxx"
#include "graphics/twm4nx/ciconmgr.hxx"
#include "graphics/twm4nx/cwindowevent.hxx"
#include "graphics/twm4nx/cwindow.hxx"
#include "graphics/twm4nx/cwindowfactory.hxx"
#include "graphics/twm4nx/ctwm4nxevent.hxx"
#include "graphics/twm4nx/twm4nx_events.hxx"
#include "graphics/twm4nx/twm4nx_cursor.hxx"
using namespace Twm4Nx;
struct SToolbarInfo
{
FAR const NXWidgets::SRlePaletteBitmap *bitmap;
bool rightSide;
uint16_t event;
};
struct SToolbarInfo GToolBarInfo[NTOOLBAR_BUTTONS] =
{
{
&CONFIG_TWM4NX_MENU_IMAGE, false, EVENT_TOOLBAR_MENU
},
{
&CONFIG_TWM4NX_TERMINATE_IMAGE, true, EVENT_TOOLBAR_TERMINATE
},
{
&CONFIG_TWM4NX_RESIZE_IMAGE, true, EVENT_RESIZE_BUTTON
},
{
&CONFIG_TWM4NX_MINIMIZE_IMAGE, true, EVENT_TOOLBAR_MINIMIZE
}
};
* CWindow Constructor
*
* @param twm4nx. Twm4Nx session
*/
CWindow::CWindow(CTwm4Nx *twm4nx)
{
m_twm4nx = twm4nx;
m_eventq = (mqd_t)-1;
m_nxWin = (FAR NXWidgets::CNxTkWindow *)0;
m_toolbar = (FAR NXWidgets::CNxToolbar *)0;
m_windowEvent = (FAR CWindowEvent *)0;
m_minWidth = 1;
m_modal = false;
m_appEvents.eventObj = (FAR void *)0;
m_appEvents.redrawEvent = EVENT_SYSTEM_NOP;
m_appEvents.mouseEvent = EVENT_SYSTEM_NOP;
m_appEvents.kbdEvent = EVENT_SYSTEM_NOP;
m_appEvents.closeEvent = EVENT_SYSTEM_NOP;
m_appEvents.deleteEvent = EVENT_SYSTEM_NOP;
m_tbTitle = (FAR NXWidgets::CLabel *)0;
m_tbHeight = 0;
m_tbLeftX = 0;
m_tbRightX = 0;
m_tbFlags = 0;
m_tbDisables = 0;
m_tbStyle = *NXWidgets::g_defaultWidgetStyle;
m_tbStyle.colors.background = CONFIG_TWM4NX_DEFAULT_TOOLBARCOLOR;
m_tbStyle.colors.selectedBackground = CONFIG_TWM4NX_DEFAULT_TOOLBARCOLOR;
m_iconBitMap = (FAR NXWidgets::CRlePaletteBitmap *)0;
m_iconWidget = (FAR CIconWidget *)0;
m_iconMgr = (FAR CIconMgr *)0;
m_iconified = false;
m_clicked = false;
m_dragging = false;
m_dragPos.x = 0;
m_dragPos.y = 0;
m_dragCSize.w = 0;
m_dragCSize.h = 0;
std::memset(m_tbButtons, 0, NTOOLBAR_BUTTONS * sizeof(NXWidgets::CImage *));
}
* CWindow Destructor
*/
CWindow::~CWindow(void)
{
cleanup();
}
* CWindow Initializer (unlike the constructor, this may fail)
*
* The window is initialized with all application events disabled.
* The CWindows::configureEvents() method may be called as a second
* initialization step in order to enable application events.
*
* @param name The the name of the window (and its icon)
* @param pos The initial position of the window
* @param size The initial size of the window
* @param sbitmap The Icon bitmap image. null if no icon.
* @param iconMgr Pointer to icon manager instance. To support
* multiple Icon Managers.
* @param flags Toolbar customizations see WFLAGS_NO_* definition
* @return True if the window was successfully initialize; false on
* any failure,
*/
bool CWindow::initialize(FAR const NXWidgets::CNxString &name,
FAR const struct nxgl_point_s *pos,
FAR const struct nxgl_size_s *size,
FAR const struct NXWidgets::SRlePaletteBitmap *sbitmap,
FAR CIconMgr *iconMgr, uint8_t flags)
{
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 (iconMgr == (FAR CIconMgr *)0)
{
m_iconMgr = m_twm4nx->getIconMgr();
}
else
{
m_iconMgr = iconMgr;
}
if (name.getLength() == 0)
{
m_name.setText(GNoName);
}
else
{
m_name.setText(name);
}
if (WFLAGS_HAVE_TOOLBAR(flags))
{
m_minWidth = minimumToolbarWidth(m_twm4nx, m_name, flags);
}
struct nxgl_size_s maxWindow;
m_twm4nx->maxWindowSize(&maxWindow);
struct nxgl_size_s winsize;
winsize.w = size->w;
if (winsize.w > maxWindow.w)
{
winsize.w = maxWindow.w;
}
winsize.h = size->h;
if (winsize.h > maxWindow.h)
{
winsize.h = maxWindow.h;
}
m_nxWin = (FAR NXWidgets::CNxTkWindow *)0;
m_toolbar = (FAR NXWidgets::CNxToolbar *)0;
if (!createMainWindow(&winsize, pos, flags))
{
twmerr("ERROR: createMainWindow() failed\n");
cleanup();
return false;
}
m_tbHeight = 0;
m_tbFlags = flags;
m_toolbar = (FAR NXWidgets::CNxToolbar *)0;
if (WFLAGS_HAVE_TOOLBAR(flags))
{
if (!getToolbarHeight(name))
{
twmerr("ERROR: getToolbarHeight() failed\n");
cleanup();
return false;
}
if (!createToolbar())
{
twmerr("ERROR: createToolbar() failed\n");
cleanup();
return false;
}
if (!createToolbarButtons(flags))
{
twmerr("ERROR: createToolbarButtons() failed\n");
cleanup();
return false;
}
if (!createToolbarTitle(name))
{
twmerr("ERROR: createToolbarTitle() failed\n");
cleanup();
return false;
}
}
if (sbitmap != (FAR const struct NXWidgets::SRlePaletteBitmap *)0)
{
m_iconBitMap = new NXWidgets::CRlePaletteBitmap(sbitmap);
if (m_iconBitMap == (NXWidgets::CRlePaletteBitmap *)0)
{
twmerr("ERROR: Failed to create icon image\n");
cleanup();
return false;
}
NXWidgets::CWidgetStyle style = *NXWidgets::g_defaultWidgetStyle;
style.colors.background = CONFIG_TWM4NX_DEFAULT_BACKGROUNDCOLOR;
style.colors.selectedBackground = CONFIG_TWM4NX_DEFAULT_BACKGROUNDCOLOR;
FAR CBackground *background = m_twm4nx->getBackground();
FAR NXWidgets::CWidgetControl *control = background->getWidgetControl();
m_iconWidget = new CIconWidget(m_twm4nx, control, pos->x, pos->y, &style);
if (m_iconWidget == (FAR CIconWidget *)0)
{
twmerr("ERROR: Failed to create the icon widget\n");
cleanup();
return false;
}
if (!m_iconWidget->initialize(this, m_iconBitMap, m_name))
{
twmerr("ERROR: Failed to initialize the icon widget\n");
cleanup();
return false;
}
m_iconWidget->disable();
m_iconWidget->disableDrawing();
m_iconWidget->setRaisesEvents(true);
}
enableToolbarWidgets();
return true;
}
* Configure application window events.
*
* @param events Describes the application event configuration
* @return True is returned on success
*/
bool CWindow::configureEvents(FAR const struct SAppEvents &events)
{
m_appEvents.eventObj = events.eventObj;
m_appEvents.redrawEvent = events.redrawEvent;
m_appEvents.resizeEvent = events.resizeEvent;
m_appEvents.mouseEvent = events.mouseEvent;
m_appEvents.kbdEvent = events.kbdEvent;
m_appEvents.closeEvent = events.closeEvent;
m_appEvents.deleteEvent = events.deleteEvent;
return m_windowEvent->configureEvents(events);
}
* Get the raw window size (including toolbar and frame)
*
* @param framesize Location to return the window frame size
*/
bool CWindow::getFrameSize(FAR struct nxgl_size_s *framesize)
{
struct nxgl_size_s winsize;
bool success = getWindowSize(&winsize);
if (success)
{
windowToFrameSize(&winsize, framesize);
}
return success;
}
* Update the window frame after a resize operation (includes the toolbar
* and user window)
*
* @param frameSize The new window frame size
* @param framePos The frame location which may also have changed
*/
bool CWindow::resizeFrame(FAR const struct nxgl_size_s *frameSize,
FAR const struct nxgl_point_s *framePos)
{
struct nxgl_size_s delta;
delta.w = 2 * CONFIG_NXTK_BORDERWIDTH;
delta.h = m_tbHeight + 2 * CONFIG_NXTK_BORDERWIDTH;
struct nxgl_size_s winsize;
if (frameSize->w <= m_minWidth + delta.w)
{
winsize.w = m_minWidth;
}
else
{
winsize.w = frameSize->w - delta.w;
}
if (frameSize->h <= delta.h)
{
winsize.h = 1;
}
else
{
winsize.h = frameSize->h - delta.h;
}
bool success = m_nxWin->setSize(&winsize);
if (!success)
{
twmerr("ERROR: Failed to setSize()\n");
return false;
}
if (framePos != (FAR const struct nxgl_point_s *)0)
{
success = setFramePosition(framePos);
if (!success)
{
twmerr("ERROR: Failed to setFramePosition()\n");
return false;
}
}
m_nxWin->synchronize();
success = updateToolbarLayout();
if (!success)
{
twmerr("ERROR: updateToolbarLayout() failed\n");
return false;
}
if (m_appEvents.resizeEvent != EVENT_SYSTEM_NOP)
{
twminfo("Close event...\n");
struct SEventMsg outmsg;
outmsg.eventID = m_appEvents.resizeEvent;
outmsg.obj = (FAR void *)this;
outmsg.pos.x = 0;
outmsg.pos.y = 0;
outmsg.context = EVENT_CONTEXT_WINDOW;
outmsg.handler = m_appEvents.eventObj;
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;
}
* Get the window frame position (accounting for toolbar and frame)
*
* @param size Location to return the window frame position
*/
bool CWindow::getFramePosition(FAR struct nxgl_point_s *framepos)
{
struct nxgl_point_s winpos;
bool success = m_nxWin->getPosition(&winpos);
if (success)
{
windowToFramePos(&winpos, framepos);
}
return success;
}
* Set the window frame position (accounting for toolbar and frame)
*
* @param size The new raw window position
*/
bool CWindow::setFramePosition(FAR const struct nxgl_point_s *framepos)
{
struct nxgl_point_s winpos;
frameToWindowPos(framepos, &winpos);
return m_nxWin->setPosition(&winpos);
}
* Minimize (iconify) the window
*
* @return True if the operation was successful
*/
bool CWindow::iconify(void)
{
if (!isIconified())
{
m_modal = false;
m_nxWin->modal(false);
m_nxWin->hide();
if (hasIcon())
{
m_iconWidget->enable();
struct nxgl_point_s iconPos;
m_iconWidget->getPos(iconPos);
FAR CWindowFactory *factory = m_twm4nx->getWindowFactory();
if (factory->placeIcon(this, iconPos, iconPos))
{
m_iconWidget->moveTo(iconPos.x, iconPos.y);
}
m_iconWidget->enableDrawing();
m_iconWidget->redraw();
}
m_iconified = true;
m_nxWin->synchronize();
}
return true;
}
* De-iconify the window
*
* @return True if the operation was successful
*/
bool CWindow::deIconify(void)
{
if (isIconified())
{
m_iconified = false;
m_nxWin->show();
if (hasIcon())
{
m_iconWidget->disableDrawing();
m_iconWidget->disable();
struct nxgl_size_s size;
m_iconWidget->getSize(size);
struct nxgl_rect_s rect;
m_iconWidget->getPos(rect.pt1);
rect.pt2.x = rect.pt1.x + size.w - 1;
rect.pt2.y = rect.pt1.y + size.h - 1;
FAR CBackground *backgd = m_twm4nx->getBackground();
if (!backgd->redrawBackgroundWindow(&rect, false))
{
twmerr("ERROR: redrawBackgroundWindow() failed\n");
}
}
m_nxWin->synchronize();
}
return true;
}
* Handle WINDOW events.
*
* @param eventmsg. The received NxWidget WINDOW event message.
* @return True if the message was properly handled. false is
* return on any failure.
*/
bool CWindow::event(FAR struct SEventMsg *eventmsg)
{
bool success = true;
switch (eventmsg->eventID)
{
case EVENT_WINDOW_RAISE:
m_nxWin->raise();
break;
case EVENT_WINDOW_LOWER:
m_nxWin->lower();
break;
case EVENT_WINDOW_DEICONIFY:
{
success = deIconify();
}
break;
case EVENT_TOOLBAR_MENU:
{
}
break;
case EVENT_TOOLBAR_MINIMIZE:
{
success = iconify();
}
break;
case EVENT_TOOLBAR_TERMINATE:
if (isIconMgr())
{
m_iconMgr->hide();
}
else
{
if (m_appEvents.closeEvent != EVENT_SYSTEM_NOP)
{
twminfo("Close event...\n");
struct SEventMsg outmsg;
outmsg.eventID = m_appEvents.closeEvent;
outmsg.obj = (FAR void *)this;
outmsg.pos.x = eventmsg->pos.x;
outmsg.pos.y = eventmsg->pos.y;
outmsg.context = eventmsg->context;
outmsg.handler = m_appEvents.eventObj;
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);
}
}
NXWidgets::CWidgetControl *control = m_nxWin->getWidgetControl();
nxtk_block(control->getWindowHandle(), (FAR void *)m_nxWin);
}
break;
case EVENT_WINDOW_DELETE:
{
FAR CWindow *cwin = (FAR CWindow *)eventmsg->obj;
success = cwin->pollToolbarEvents();
FAR CWindowFactory *factory = m_twm4nx->getWindowFactory();
factory->destroyWindow(cwin);
}
break;
case EVENT_TOOLBAR_GRAB:
success = toolbarGrab(eventmsg);
break;
case EVENT_WINDOW_DRAG:
success = windowDrag(eventmsg);
break;
case EVENT_TOOLBAR_UNGRAB:
success = toolbarUngrab(eventmsg);
break;
default:
success = false;
break;
}
return success;
}
* Create the main window
*
* Initially, the application window will generate no window-related events
* (redraw, mouse/touchscreen, keyboard input, etc.). After creating the
* window, the user may call the configureEvents() method to select the
* eventIDs of the events to be generated.
*
* @param winsize The initial window size
* @param winpos The initial window position
* @param flags Toolbar customizations see WFLAGS_NO_* definitions
*/
bool CWindow::createMainWindow(FAR const nxgl_size_s *winsize,
FAR const nxgl_point_s *winpos,
uint8_t flags)
{
m_windowEvent = new CWindowEvent(m_twm4nx, (FAR void *)this, m_appEvents);
m_windowEvent->installEventTap(this, (uintptr_t)1);
uint8_t cflags = NXBE_WINDOW_RAMBACKED;
if (WFLAGS_IS_HIDDEN(flags) | WFLAGS_IS_MENU(flags))
{
cflags |= NXBE_WINDOW_HIDDEN;
}
m_nxWin = m_twm4nx->createFramedWindow(m_windowEvent, cflags);
if (m_nxWin == (FAR NXWidgets::CNxTkWindow *)0)
{
delete m_windowEvent;
m_windowEvent = (FAR CWindowEvent *)0;
return false;
}
bool success = m_nxWin->open();
if (!success)
{
return false;
}
if (!m_nxWin->setSize(winsize))
{
return false;
}
if (!m_nxWin->setPosition(winpos))
{
return false;
}
m_iconified = WFLAGS_IS_MENU(flags);
return true;
}
* Calculate the height of the tool bar
*/
bool CWindow::getToolbarHeight(FAR const NXWidgets::CNxString &name)
{
m_tbHeight = 0;
if (name.getLength() != 0)
{
FAR CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *titleFont = fonts->getTitleFont();
m_tbHeight = titleFont->getHeight();
}
for (int btindex = 0; btindex < NTOOLBAR_BUTTONS; btindex++)
{
nxgl_coord_t btnHeight = GToolBarInfo[btindex].bitmap->height;
if (btnHeight > m_tbHeight)
{
m_tbHeight = btnHeight;
}
}
m_tbHeight += CONFIG_TWM4NX_TOOLBAR_VSPACING;
return true;
}
* Create the tool bar
*/
bool CWindow::createToolbar(void)
{
struct SAppEvents events;
events.eventObj = (FAR void *)this;
events.redrawEvent = EVENT_SYSTEM_NOP;
events.resizeEvent = EVENT_SYSTEM_NOP;
events.mouseEvent = EVENT_TOOLBAR_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 *)this,
events);
control->installEventTap(this, (uintptr_t)0);
m_toolbar = m_nxWin->openToolbar(m_tbHeight, control);
if (m_toolbar == (FAR NXWidgets::CNxToolbar *)0)
{
delete control;
return false;
}
if (!m_toolbar->open())
{
delete m_toolbar;
m_toolbar = (FAR NXWidgets::CNxToolbar *)0;
return false;
}
if (!fillToolbar())
{
delete m_toolbar;
m_toolbar = (FAR NXWidgets::CNxToolbar *)0;
return false;
}
return true;
}
* Fill the toolbar background color
*/
bool CWindow::fillToolbar(void)
{
FAR NXWidgets::CWidgetControl *control = m_toolbar->getWidgetControl();
NXWidgets::CGraphicsPort *port = control->getGraphicsPort();
struct nxgl_size_s windowSize;
if (!m_toolbar->getSize(&windowSize))
{
twmerr("ERROR: Failed to get the size of the toolbar\n");
return false;
}
port->drawFilledRect(0, 0, windowSize.w, windowSize.h,
NXWidgets::g_defaultWidgetStyle->colors.background);
return true;
}
* Update the toolbar layout, resizing the title text window and
* repositioning all windows on the toolbar.
*/
bool CWindow::updateToolbarLayout(void)
{
disableToolbarWidgets();
struct nxgl_size_s winsize;
if (!getWindowSize(&winsize))
{
twmerr("ERROR: Failed to get window size\n");
return false;
}
m_tbRightX = winsize.w;
for (int btindex = 0; btindex < NTOOLBAR_BUTTONS; btindex++)
{
if (m_tbButtons[btindex] != (FAR NXWidgets::CImage *)0 &&
GToolBarInfo[btindex].rightSide)
{
FAR NXWidgets::CImage *cimage = m_tbButtons[btindex];
struct nxgl_size_s windowSize;
getWindowSize(&windowSize);
struct nxgl_point_s pos;
pos.y = (m_tbHeight - cimage->getHeight()) / 2;
m_tbRightX -= (cimage->getWidth() + CONFIG_TWM4NX_TOOLBAR_HSPACING);
pos.x = m_tbRightX;
if (!cimage->moveTo(pos.x, pos.y))
{
twmerr("ERROR: Failed to move button image\n");
return false;
}
}
}
struct nxgl_size_s titleSize;
titleSize.h = m_tbHeight;
titleSize.w = m_tbRightX - m_tbLeftX - CONFIG_TWM4NX_TOOLBAR_HSPACING + 1;
if (!m_tbTitle->resize(titleSize.w, titleSize.h))
{
twmerr("ERROR: Failed to resize title\n");
return false;
}
if (!fillToolbar())
{
twmerr("ERROR: Failed to fill the toolbar\n");
return false;
}
enableToolbarWidgets();
return true;
}
* Disable toolbar widget drawing and widget events.
*/
bool CWindow::disableToolbarWidgets(void)
{
for (int btindex = 0; btindex < NTOOLBAR_BUTTONS; btindex++)
{
FAR NXWidgets::CImage *cimage = m_tbButtons[btindex];
if (cimage != (FAR NXWidgets::CImage *)0)
{
cimage->disableDrawing();
cimage->setRaisesEvents(false);
}
}
m_tbTitle->disableDrawing();
m_tbTitle->setRaisesEvents(false);
return true;
}
* Enable and redraw toolbar widget drawing and widget events.
*/
bool CWindow::enableToolbarWidgets(void)
{
for (int btindex = 0; btindex < NTOOLBAR_BUTTONS; btindex++)
{
FAR NXWidgets::CImage *cimage = m_tbButtons[btindex];
if (cimage != (FAR NXWidgets::CImage *)0)
{
cimage->enableDrawing();
cimage->setRaisesEvents(true);
cimage->redraw();
}
}
m_tbTitle->enableDrawing();
m_tbTitle->setRaisesEvents(true);
m_tbTitle->redraw();
return true;
}
* Create all toolbar buttons
*
* @param flags Toolbar customizations see WFLAGS_NO_* definitions
* @return True if the window was successfully initialize; false on
* any failure,
*/
bool CWindow::createToolbarButtons(uint8_t flags)
{
struct nxgl_size_s winsize;
if (!getWindowSize(&winsize))
{
return false;
}
m_tbRightX = winsize.w;
m_tbLeftX = 0;
for (int btindex = 0; btindex < NTOOLBAR_BUTTONS; btindex++)
{
if ((m_tbFlags & (1 << btindex)) != 0)
{
continue;
}
FAR const NXWidgets::SRlePaletteBitmap *sbitmap =
GToolBarInfo[btindex].bitmap;
#ifdef CONFIG_TWM4NX_TOOLBAR_ICONSCALE
struct nxgl_size_s iconSize;
iconSize.w = CONFIG_TWM4NX_TOOLBAR_ICONWIDTH;
iconSize.h = CONFIG_TWM4NX_TOOLBAR_ICONHEIGHT;
FAR NXWidgets::CScaledBitmap *scaler =
new NXWidgets::CScaledBitmap(sbitmap, iconSize);
if (scaler == (FAR NXWidgets::CScaledBitmap *)0)
{
twmerr("ERROR: Failed to created scaled bitmap\n");
return false;
}
#endif
m_tbButtons[btindex] = (FAR NXWidgets::CImage *)0;
nxgl_coord_t w = 1;
nxgl_coord_t h = 1;
NXWidgets::CWidgetControl *control = m_toolbar->getWidgetControl();
#ifdef CONFIG_TWM4NX_TOOLBAR_ICONSCALE
w = scaler->getWidth();
h = scaler->getHeight();
m_tbButtons[btindex] =
new NXWidgets::CImage(control, 0, 0, w, h, scaler, &m_tbStyle);
if (m_tbButtons[btindex] == (FAR NXWidgets::CImage *)0)
{
twmerr("ERROR: Failed to create image\n");
delete scalar;
return false;
}
#else
FAR NXWidgets::CRlePaletteBitmap *cbitmap =
new NXWidgets::CRlePaletteBitmap(sbitmap);
if (cbitmap == (FAR NXWidgets::CRlePaletteBitmap *)0)
{
twmerr("ERROR: Failed to create CrlPaletteBitmap\n");
return false;
}
w = cbitmap->getWidth();
h = cbitmap->getHeight();
m_tbButtons[btindex] =
new NXWidgets::CImage(control, 0, 0, w, h, cbitmap, &m_tbStyle);
if (m_tbButtons[btindex] == (FAR NXWidgets::CImage *)0)
{
twmerr("ERROR: Failed to create image\n");
delete cbitmap;
return false;
}
#endif
FAR NXWidgets::CImage *cimage = m_tbButtons[btindex];
cimage->setBorderless(true);
cimage->disableDrawing();
cimage->setRaisesEvents(false);
cimage->addWidgetEventHandler(this);
struct nxgl_size_s windowSize;
getWindowSize(&windowSize);
struct nxgl_point_s pos;
pos.y = (m_tbHeight - cimage->getHeight()) / 2;
if (GToolBarInfo[btindex].rightSide)
{
m_tbRightX -= (cimage->getWidth() + CONFIG_TWM4NX_TOOLBAR_HSPACING);
pos.x = m_tbRightX;
}
else
{
m_tbLeftX += CONFIG_TWM4NX_TOOLBAR_HSPACING;
pos.x = m_tbLeftX;
m_tbLeftX += cimage->getWidth();
}
if (!cimage->moveTo(pos.x, pos.y))
{
delete m_tbButtons[btindex];
m_tbButtons[btindex] = (FAR NXWidgets::CImage *)0;
return false;
}
}
return true;
}
* Add buttons and title widgets to the tool bar
*
* @param name The name to use for the toolbar title
*/
bool CWindow::createToolbarTitle(FAR const NXWidgets::CNxString &name)
{
if (name.getLength() == 0)
{
return true;
}
struct nxgl_size_s titleSize;
titleSize.h = m_tbHeight;
titleSize.w = m_tbRightX - m_tbLeftX - 2 * CONFIG_TWM4NX_TOOLBAR_HSPACING + 1;
struct nxgl_point_s titlePos;
titlePos.x = m_tbLeftX + CONFIG_TWM4NX_TOOLBAR_HSPACING;
titlePos.y = 0;
FAR NXWidgets:: CWidgetControl *control = m_toolbar->getWidgetControl();
if (control == (FAR NXWidgets:: CWidgetControl *)0)
{
return false;
}
m_tbTitle = new NXWidgets::CLabel(control, titlePos.x, titlePos.y,
titleSize.w, titleSize.h, name, &m_tbStyle);
if (m_tbTitle == (FAR NXWidgets::CLabel *)0)
{
twmerr("ERROR: Failed to construct tool bar title widget\n");
return false;
}
FAR CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *titleFont = fonts->getTitleFont();
m_tbTitle->setFont(titleFont);
m_tbTitle->setBorderless(true);
m_tbTitle->disableDrawing();
m_tbTitle->setTextAlignmentHoriz(NXWidgets::CLabel::TEXT_ALIGNMENT_HORIZ_LEFT);
m_tbTitle->setTextAlignmentVert(NXWidgets::CLabel::TEXT_ALIGNMENT_VERT_CENTER);
m_tbTitle->setRaisesEvents(false);
m_tbTitle->addWidgetEventHandler(this);
return true;
}
* After the toolbar was grabbed, it may be dragged then dropped, or it
* may be simply "un-grabbed". Both cases are handled here.
*
* NOTE: Unlike the other event handlers, this does NOT override any
* virtual event handling methods. It just combines some common event-
* handling logic.
*
* @param x The mouse/touch X position.
* @param y The mouse/touch y position.
*/
void CWindow::handleUngrabEvent(nxgl_coord_t x, nxgl_coord_t y)
{
struct SEventMsg msg;
msg.eventID = EVENT_TOOLBAR_UNGRAB;
msg.obj = (FAR void *)this;
msg.pos.x = x;
msg.pos.y = y;
msg.context = EVENT_CONTEXT_TOOLBAR;
msg.handler = (FAR void *)0;
int ret = mq_send(m_eventq, (FAR const char *)&msg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
twmerr("ERROR: mq_send failed: %d\n", errno);
}
}
* Handle a mouse click event.
*
* @param e The event data.
*/
void CWindow::handleClickEvent(const NXWidgets::CWidgetEventArgs &e)
{
if (!m_dragging && m_tbTitle->isClicked())
{
struct SEventMsg msg;
msg.eventID = EVENT_TOOLBAR_GRAB;
msg.obj = (FAR void *)this;
msg.pos.x = e.getX();
msg.pos.y = e.getY();
msg.context = EVENT_CONTEXT_TOOLBAR;
msg.handler = (FAR void *)0;
int ret = mq_send(m_eventq, (FAR const char *)&msg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
twmerr("ERROR: mq_send failed: %d\n", errno);
}
}
}
* Override the virtual CWidgetEventHandler::handleReleaseEvent. This
* event will fire when the title widget is released. isClicked()
* will return false for the title widget.
*
* @param e The event data.
*/
void CWindow::handleReleaseEvent(const NXWidgets::CWidgetEventArgs &e)
{
if (m_dragging && !m_tbTitle->isClicked())
{
m_nxWin->raise();
handleUngrabEvent(e.getX(), e.getY());
}
}
* Override the virtual CWidgetEventHandler::handleActionEvent. This
* event will fire when the image is released but before it has been
* has been drawn. isClicked() will return true for the appropriate
* images.
*
* @param e The event data.
*/
void CWindow::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
{
for (int btindex = 0; btindex < NTOOLBAR_BUTTONS; btindex++)
{
if (((m_tbFlags | m_tbDisables) & (1 << btindex)) != 0)
{
continue;
}
if (m_tbButtons[btindex] != (FAR NXWidgets::CImage *)0 &&
m_tbButtons[btindex]->isClicked())
{
struct SEventMsg msg;
msg.eventID = GToolBarInfo[btindex].event;
msg.obj = (FAR void *)this;
msg.pos.x = e.getX();
msg.pos.y = e.getY();
msg.context = EVENT_CONTEXT_TOOLBAR;
msg.handler = (FAR void *)0;
int ret = mq_send(m_eventq, (FAR const char *)&msg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
twmerr("ERROR: mq_send failed: %d\n", errno);
}
}
}
}
* 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 in toolbar relative
* coordinates.
* @return True: if the drag event was processed; false it was
* ignored. The event should be ignored if there is not actually
* a drag event in progress
*/
bool CWindow::moveEvent(FAR const struct nxgl_point_s &pos,
uintptr_t arg)
{
twminfo("m_dragging=%u pos=(%d,%d)\n", m_dragging, pos.x, pos.y);
if (m_dragging)
{
nxgl_coord_t yIncr = ((arg == 0) ? 0 : m_tbHeight);
struct SEventMsg msg;
msg.eventID = EVENT_WINDOW_DRAG;
msg.obj = (FAR void *)this;
msg.pos.x = pos.x;
msg.pos.y = pos.y + yIncr;
msg.context = EVENT_CONTEXT_TOOLBAR;
msg.handler = (FAR void *)0;
int ret = mq_send(m_eventq, (FAR const char *)&msg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
twmerr("ERROR: mq_send failed: %d\n", errno);
}
return true;
}
return false;
}
* This function is called if the mouse left button is released or
* if the touchscreen touch is lost. This indicates that the
* dragging sequence is complete.
*
* This function overrides the virtual IEventTap::dropEvent method.
*
* @param pos The last mouse/touch X/Y position in toolbar relative
* coordinates.
* @return True: If the drag event was processed; false it 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,
uintptr_t arg)
{
twminfo("m_dragging=%u pos=(%d,%d)\n", m_dragging, pos.x, pos.y);
if (m_dragging)
{
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::isActive(uintptr_t arg)
{
return m_clicked;
}
* Enable/disable dragging
*
* 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 dragging
* @param arg The user-argument provided that accompanies the callback
*/
void CWindow::enableMovement(FAR const struct nxgl_point_s &pos,
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
*
* @param eventmsg. The received NxWidget event message.
* @return True if the message was properly handled. false is
* return on any failure.
*/
bool CWindow::toolbarGrab(FAR struct SEventMsg *eventmsg)
{
twminfo("GRAB (%d,%d)\n", eventmsg->pos.x, eventmsg->pos.y);
struct SAppEvents events;
events.eventObj = (FAR void *)this;
events.redrawEvent = EVENT_SYSTEM_NOP;
events.resizeEvent = EVENT_SYSTEM_NOP;
events.mouseEvent = EVENT_TOOLBAR_XYINPUT;
events.kbdEvent = EVENT_SYSTEM_NOP;
events.closeEvent = m_appEvents.closeEvent;
events.deleteEvent = m_appEvents.deleteEvent;
bool success = m_windowEvent->configureEvents(events);
if (!success)
{
return false;
}
m_modal = true;
m_nxWin->modal(true);
m_dragging = true;
struct nxgl_point_s framePos;
getFramePosition(&framePos);
twminfo("Position (%d,%d)\n", framePos.x, framePos.y);
m_dragPos.x = eventmsg->pos.x;
m_dragPos.y = eventmsg->pos.y;
#ifdef CONFIG_TWM4NX_MOUSE
m_twm4nx->setCursorImage(&CONFIG_TWM4NX_GBCURSOR_IMAGE);
m_dragCSize.w = CONFIG_TWM4NX_GBCURSOR_IMAGE.size.w;
m_dragCSize.h = CONFIG_TWM4NX_GBCURSOR_IMAGE.size.h;
#else
m_dragCSize.w = 16;
m_dragCSize.h = 16;
#endif
return true;
}
* Handle the WINDOW_DRAG event. That corresponds to a mouse
* movement when the window is in a grabbed state.
*
* @param eventmsg. The received NxWidget event message.
* @return True if the message was properly handled. false is
* return on any failure.
*/
bool CWindow::windowDrag(FAR struct SEventMsg *eventmsg)
{
twminfo("DRAG (%d,%d)\n", eventmsg->pos.x, eventmsg->pos.y);
if (m_dragging)
{
struct nxgl_point_s oldPos;
if (!getFramePosition(&oldPos))
{
twmerr("ERROR: getFramePosition() failed\n") ;
return false;
}
struct nxgl_point_s newPos;
newPos.x = oldPos.x + eventmsg->pos.x - m_dragPos.x;
newPos.y = oldPos.y + eventmsg->pos.y - m_dragPos.y;
m_dragPos.x = eventmsg->pos.x;
m_dragPos.y = eventmsg->pos.y;
struct nxgl_size_s displaySize;
m_twm4nx->getDisplaySize(&displaySize);
if (newPos.x < 0)
{
newPos.x = 0;
}
else if (newPos.x + m_dragCSize.w > displaySize.w)
{
newPos.x = displaySize.w - m_dragCSize.w;
}
if (newPos.y < 0)
{
newPos.y = 0;
}
else if (newPos.y + m_dragCSize.h > displaySize.h)
{
newPos.y = displaySize.h - m_dragCSize.h;
}
twminfo("Position (%d,%d)->(%d,%d)\n",
oldPos.x, oldPos.y, newPos.x, newPos.y);
if (newPos.x != oldPos.x || newPos.y != oldPos.y)
{
if (!setFramePosition(&newPos))
{
twmerr("ERROR: setFramePosition failed\n");
return false;
}
m_nxWin->synchronize();
}
return true;
}
return false;
}
* Handle the TOOLBAR_UNGRAB event. The corresponds to a mouse
* left button release while in the grabbed state
*
* @param eventmsg. The received NxWidget event message in window relative
* coordinates.
* @return True if the message was properly handled. false is
* return on any failure.
*/
bool CWindow::toolbarUngrab(FAR struct SEventMsg *eventmsg)
{
twminfo("UNGRAB (%d,%d)\n", eventmsg->pos.x, eventmsg->pos.y);
if (!windowDrag(eventmsg))
{
return false;
}
m_dragging = false;
m_modal = false;
m_nxWin->modal(false);
#ifdef CONFIG_TWM4NX_MOUSE
m_twm4nx->setCursorImage(&CONFIG_TWM4NX_CURSOR_IMAGE);
#endif
return m_windowEvent->configureEvents(m_appEvents);
}
* Free windows from Twm4Nx window structure.
*/
void CWindow::cleanup(void)
{
if (m_eventq != (mqd_t)-1)
{
mq_close(m_eventq);
m_eventq = (mqd_t)-1;
}
for (int btindex = 0; btindex < NTOOLBAR_BUTTONS; btindex++)
{
FAR NXWidgets::CImage *cimage = m_tbButtons[btindex];
if (cimage != (NXWidgets::CImage *)0)
{
delete m_tbButtons[btindex];
m_tbButtons[btindex] = (NXWidgets::CImage *)0;
}
}
if (m_tbTitle != (FAR NXWidgets::CLabel *)0)
{
delete m_tbTitle;
m_tbTitle = (FAR NXWidgets::CLabel *)0;
}
if (m_toolbar != (FAR NXWidgets::CNxToolbar *)0)
{
delete m_toolbar;
m_toolbar = (FAR NXWidgets::CNxToolbar *)0;
}
if (m_nxWin != (FAR NXWidgets::CNxTkWindow *)0)
{
delete m_nxWin;
m_nxWin = (FAR NXWidgets::CNxTkWindow *)0;
}
if (m_iconWidget != (FAR CIconWidget *)0)
{
delete m_iconWidget;
m_iconWidget = (FAR CIconWidget *)0;
}
if (m_iconBitMap != (FAR NXWidgets::CRlePaletteBitmap *)0)
{
delete m_iconBitMap;
m_iconBitMap = (FAR NXWidgets::CRlePaletteBitmap *)0;
}
}
namespace Twm4Nx
{
* Return the minimum width of a toolbar window. If the window is
* resized smaller than this width, then the items in the toolbar will
* overlap.
*
* @param twm4nx The Twm4Nx session object
* @param title The window title string
* @param flags Window toolbar properties
* @return The minimum recommended window width.
*/
nxgl_coord_t minimumToolbarWidth(FAR CTwm4Nx *twm4nx,
FAR const NXWidgets::CNxString &title,
uint8_t flags)
{
FAR CFonts *fonts = twm4nx->getFonts();
FAR NXWidgets::CNxFont *titleFont = fonts->getTitleFont();
nxgl_coord_t tbWidth = titleFont->getStringWidth(title) +
CONFIG_TWM4NX_TOOLBAR_HSPACING;
for (int btindex = 0; btindex < NTOOLBAR_BUTTONS; btindex++)
{
if ((flags & (1 << btindex)) == 0)
{
tbWidth += GToolBarInfo[btindex].bitmap->width +
CONFIG_TWM4NX_TOOLBAR_HSPACING;
}
}
return tbWidth;
}
}