graphics/twm4nx/src/ciconmgr.cxx: Integrate use of CButtonArray; implement first cut at event handling. graphics/nxwidgets/src/cbuttonarray.cxx: Add a method to CButtonArray that will allow us to dynamically resize the array (at the cost of losing all button labels). graphics/twm4nx/src/ciconmgr.cxx: Add some fragments of CButtonArray logic. graphics/twm4nx/src/cwindow.cxx: Finishes first cut at window event management.
882 lines
21 KiB
C++
882 lines
21 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// apps/graphics/twm4nx/src/cmenus.cxx
|
|
// twm menu code
|
|
//
|
|
// 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.
|
|
//
|
|
// 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 <cstdio>
|
|
#include <cstring>
|
|
#include <cassert>
|
|
#include <cerrno>
|
|
#include <fcntl.h>
|
|
#include <debug.h>
|
|
|
|
#include <nuttx/version.h>
|
|
|
|
#include "graphics/nxwidgets/cnxfont.hxx"
|
|
#include "graphics/nxwidgets/clistbox.hxx"
|
|
|
|
#include "graphics/twm4nx/ctwm4nx.hxx"
|
|
#include "graphics/twm4nx/cmenus.hxx"
|
|
#include "graphics/twm4nx/cresize.hxx"
|
|
#include "graphics/twm4nx/cfonts.hxx"
|
|
#include "graphics/twm4nx/cicon.hxx"
|
|
#include "graphics/twm4nx/ciconmgr.hxx"
|
|
#include "graphics/twm4nx/cwindow.hxx"
|
|
#include "graphics/twm4nx/cwindowfactory.hxx"
|
|
#include "graphics/twm4nx/cwindowevent.hxx"
|
|
#include "graphics/twm4nx/twm4nx_widgetevents.hxx"
|
|
#include "graphics/twm4nx/cmenus.hxx"
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Class Implementations
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
using namespace Twm4Nx;
|
|
|
|
/**
|
|
* CMenus Constructor
|
|
*/
|
|
|
|
CMenus::CMenus(CTwm4Nx *twm4nx)
|
|
{
|
|
// Save the Twm4Nx session
|
|
|
|
m_twm4nx = twm4nx; // Save the Twm4Nx session
|
|
|
|
// Menus
|
|
|
|
m_popUpMenu = (FAR CMenus *)0; // No pop-up menu
|
|
m_activeItem = (FAR struct SMenuItem *)0; // No active menu item
|
|
m_nMenuItems = 0; // No menu items yet
|
|
m_menuDepth = 0; // No menus up
|
|
m_entryHeight = 0; // Menu entry height
|
|
m_menuPull = false; // No pull right entry
|
|
|
|
// Windows
|
|
|
|
m_menuWindow = (FAR NXWidgets::CNxTkWindow *)0; // The menu window
|
|
|
|
// Widgets
|
|
|
|
m_menuListBox = (FAR NXWidgets::CListBox *)0; //The menu list box
|
|
|
|
// Functions
|
|
|
|
m_funcKeyHead = (FAR struct SFuncKey *)0;
|
|
}
|
|
|
|
/**
|
|
* CMenus Destructor
|
|
*/
|
|
|
|
CMenus::~CMenus(void)
|
|
{
|
|
cleanup();
|
|
}
|
|
|
|
/**
|
|
* CMenus Initializer. Performs the parts of the CMenus construction
|
|
* that may fail.
|
|
*
|
|
* @result True is returned on success
|
|
*/
|
|
|
|
bool CMenus::initialize(FAR const char *name)
|
|
{
|
|
// 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)
|
|
{
|
|
gerr("ERROR: Failed open message queue '%s': %d\n",
|
|
mqname, errno);
|
|
}
|
|
|
|
// Save the menu name
|
|
|
|
m_menuName = strdup(name);
|
|
if (m_menuName == (FAR char *)0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Create the menu window
|
|
|
|
if (!createMenuWindow())
|
|
{
|
|
gerr("ERROR: Failed to create menu window\n");
|
|
cleanup();
|
|
return false;
|
|
}
|
|
|
|
// Create the menu list box
|
|
|
|
if (!createMenuListBox())
|
|
{
|
|
gerr("ERROR: Failed to create menu list box\n");
|
|
cleanup();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Add an item to a menu
|
|
*
|
|
* \param text The text to appear in the menu
|
|
* \param action The string to possibly execute
|
|
* \param subMenu The menu if it is a pull-right entry
|
|
* \param func The numeric function
|
|
*/
|
|
|
|
// REVISIT: Only used internally. Was used in .twmrc parsing.
|
|
|
|
bool CMenus::addMenuItem(FAR const char *text,
|
|
FAR const char *action, FAR CMenus *subMenu,
|
|
int func)
|
|
{
|
|
ginfo("Adding menu text=\"%s\", action=%s, subMenu=%d, f=%d\n",
|
|
text, action, subMenu, func);
|
|
|
|
// Allocate a new menu item entry
|
|
|
|
FAR struct SMenuItem *item = new SMenuItem;
|
|
|
|
if (item == (FAR struct SMenuItem *)0)
|
|
{
|
|
gerr("ERROR: Failed to allocate menu item\n");
|
|
return false;
|
|
}
|
|
|
|
// Clone the item name so that we have control over its lifespan
|
|
|
|
item->text = std::strdup(text);
|
|
if (item->text == (FAR char *)0)
|
|
{
|
|
gerr("ERROR: strdup of item text failed\n");
|
|
std::free(item);
|
|
return false;
|
|
}
|
|
|
|
// Save information about the menu item
|
|
|
|
item->action = action;
|
|
item->flink = NULL;
|
|
item->subMenu = NULL;
|
|
item->func = func;
|
|
|
|
CFonts *fonts = m_twm4nx->getFonts();
|
|
FAR NXWidgets::CNxFont *menuFont = fonts->getMenuFont();
|
|
int width = menuFont->getStringWidth(text);
|
|
|
|
if (width <= 0)
|
|
{
|
|
width = 1;
|
|
}
|
|
|
|
struct nxgl_size_s menuSize;
|
|
m_menuWindow->getSize(&menuSize);
|
|
|
|
if (width > menuSize.w)
|
|
{
|
|
menuSize.w = width;
|
|
m_menuWindow->setSize(&menuSize);
|
|
}
|
|
|
|
if (subMenu != NULL)
|
|
{
|
|
item->subMenu = subMenu;
|
|
m_menuPull = true;
|
|
}
|
|
|
|
// Save the index to this item and increment the total number of menu
|
|
// items
|
|
|
|
item->index = m_nMenuItems++;
|
|
|
|
// Add the menu item to the tail of the item list
|
|
|
|
if (m_menuHead == NULL)
|
|
{
|
|
m_menuHead = item;
|
|
item->blink = (FAR struct SMenuItem *)0;
|
|
}
|
|
else
|
|
{
|
|
m_menuTail->flink = item;
|
|
item->blink = m_menuTail;
|
|
}
|
|
|
|
m_menuTail = item;
|
|
item->flink = (FAR struct SMenuItem *)0;
|
|
|
|
// Add the item text to the list box
|
|
|
|
m_menuListBox->addOption(item->text, item->index);
|
|
|
|
// Update the menu window size
|
|
|
|
setMenuWindowSize();
|
|
|
|
// Redraw the list box
|
|
|
|
m_menuListBox->enableDrawing();
|
|
m_menuListBox->setRaisesEvents(true);
|
|
m_menuListBox->redraw();
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Handle MENU events.
|
|
*
|
|
* @param eventmsg. The received NxWidget MENU event message.
|
|
* @return True if the message was properly handled. false is
|
|
* return on any failure.
|
|
*/
|
|
|
|
bool CMenus::event(FAR struct SEventMsg *eventmsg)
|
|
{
|
|
bool success = true;
|
|
|
|
switch (eventmsg->eventID)
|
|
{
|
|
case EVENT_MENU_IDENTIFY: // Describe the window
|
|
{
|
|
identify((FAR CWindow *)eventmsg->obj);
|
|
}
|
|
break;
|
|
|
|
case EVENT_MENU_VERSION: // Show the Twm4Nx version
|
|
identify((FAR CWindow *) NULL);
|
|
break;
|
|
|
|
case EVENT_MENU_DEICONIFY: // Window icon pressed
|
|
case EVENT_MENU_ICONIFY: // Tool bar minimize button pressed
|
|
{
|
|
FAR CWindow *cwin = (FAR CWindow *)eventmsg->obj;
|
|
if (cwin->isIconified())
|
|
{
|
|
cwin->deIconify();
|
|
}
|
|
else if (eventmsg->eventID == EVENT_MENU_ICONIFY)
|
|
{
|
|
cwin->iconify();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EVENT_MENU_FUNCTION: // Perform function on unknown menu
|
|
{
|
|
FAR struct SMenuItem *item;
|
|
|
|
for (item = m_menuHead; item != NULL; item = item->flink)
|
|
{
|
|
// Send another event message to the session manager
|
|
|
|
struct SEventMsg newmsg;
|
|
newmsg.eventID = item->func;
|
|
newmsg.pos.x = eventmsg->pos.x;
|
|
newmsg.pos.y = eventmsg->pos.y;
|
|
newmsg.delta.x = 0;
|
|
newmsg.delta.y = 0;
|
|
newmsg.context = eventmsg->context;
|
|
newmsg.obj = eventmsg->obj;
|
|
|
|
// NOTE that we cannot block because we are on the same thread
|
|
// as the message reader. If the event queue becomes full then
|
|
// we have no other option but to lose events.
|
|
//
|
|
// I suppose we could recurse and call Twm4Nx::dispatchEvent at
|
|
// the risk of runawy stack usage.
|
|
|
|
int ret = mq_send(m_eventq, (FAR const char *)&newmsg,
|
|
sizeof(struct SEventMsg), 100);
|
|
if (ret < 0)
|
|
{
|
|
gerr("ERROR: mq_send failed: %d\n", ret);
|
|
success = false;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EVENT_MENU_TITLE: // Really an action not an event
|
|
case EVENT_MENU_ROOT: // Popup root menu, really an action not an event
|
|
default:
|
|
success = false;
|
|
break;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
void CMenus::identify(FAR CWindow *cwin)
|
|
{
|
|
int n = 0;
|
|
#if CONFIG_VERSION_MAJOR != 0 || CONFIG_VERSION_MINOR != 0
|
|
std::snprintf(m_info[n], INFO_SIZE, "Twm4Nx: NuttX-" CONFIG_VERSION_STRING);
|
|
#else
|
|
std::snprintf(m_info[n], INFO_SIZE, "Twm4Nx:");
|
|
#endif
|
|
m_info[n++][0] = '\0';
|
|
|
|
if (cwin != (FAR CWindow *)0)
|
|
{
|
|
// Get the size of the window
|
|
|
|
struct nxgl_size_s windowSize;
|
|
if (!cwin->getFrameSize(&windowSize))
|
|
{
|
|
return;
|
|
}
|
|
|
|
struct nxgl_point_s windowPos;
|
|
if (!cwin->getFramePosition(&windowPos))
|
|
{
|
|
return;
|
|
}
|
|
|
|
std::snprintf(m_info[n++], INFO_SIZE, "Name = \"%s\"",
|
|
cwin->getWindowName());
|
|
m_info[n++][0] = '\0';
|
|
std::snprintf(m_info[n++], INFO_SIZE, "Geometry/root = %dx%d+%d+%d",
|
|
windowSize.w, windowSize.h, windowPos.x, windowPos.y);
|
|
}
|
|
|
|
m_info[n++][0] = '\0';
|
|
std::snprintf(m_info[n++], INFO_SIZE, "Click to dismiss....");
|
|
|
|
// Figure out the width and height of the info window
|
|
|
|
FAR CFonts *fonts = m_twm4nx->getFonts();
|
|
FAR NXWidgets::CNxFont *defaultFont = fonts->getDefaultFont();
|
|
|
|
struct nxgl_size_s menuSize;
|
|
menuSize.h = n * (defaultFont->getHeight() + 2);
|
|
menuSize.w = 1;
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
int twidth = defaultFont->getStringWidth(m_info[i]);
|
|
if (twidth > menuSize.w)
|
|
{
|
|
menuSize.w = twidth;
|
|
}
|
|
}
|
|
|
|
menuSize.w += 10; // some padding
|
|
|
|
// Make sure that the window is on the display
|
|
|
|
struct nxgl_point_s menuPos;
|
|
if (m_menuWindow->getPosition(&menuPos))
|
|
{
|
|
menuPos.x -= (menuSize.w / 2);
|
|
menuPos.y -= (menuSize.h / 3);
|
|
|
|
struct nxgl_size_s displaySize;
|
|
m_twm4nx->getDisplaySize(&displaySize);
|
|
|
|
struct nxgl_size_s frameSize;
|
|
menuToFrameSize(&menuSize, &frameSize);
|
|
|
|
if (menuPos.x + frameSize.w >= displaySize.w)
|
|
{
|
|
menuPos.x = displaySize.w - frameSize.w;
|
|
}
|
|
|
|
if (menuPos.y + frameSize.h >= displaySize.h)
|
|
{
|
|
menuPos.y = displaySize.h - frameSize.h;
|
|
}
|
|
|
|
if (menuPos.x < 0)
|
|
{
|
|
menuPos.x = 0;
|
|
}
|
|
|
|
if (menuPos.y < 0)
|
|
{
|
|
menuPos.y = 0;
|
|
}
|
|
|
|
frameToMenuSize(&frameSize, &menuSize);
|
|
}
|
|
else
|
|
{
|
|
menuPos.x = 0;
|
|
menuPos.y = 0;
|
|
}
|
|
|
|
// Set the new window size and position
|
|
|
|
if (!m_menuWindow->setPosition(&menuPos) ||
|
|
!m_menuWindow->setSize(&menuSize))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Raise it to the top of the hiearchy
|
|
|
|
m_menuWindow->raise();
|
|
}
|
|
|
|
/**
|
|
* Create the menu window
|
|
*
|
|
* @result True is returned on success
|
|
*/
|
|
|
|
bool CMenus::createMenuWindow(void)
|
|
{
|
|
// Create the menu 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.
|
|
|
|
FAR CWindowEvent *control = new CWindowEvent(m_twm4nx);
|
|
|
|
// 4. Create the menu window
|
|
|
|
m_menuWindow = m_twm4nx->createFramedWindow(control);
|
|
if (m_menuWindow == (FAR NXWidgets::CNxTkWindow *)0)
|
|
{
|
|
delete control;
|
|
return false;
|
|
}
|
|
|
|
// 5. Open and initialize the menu window
|
|
|
|
bool success = m_menuWindow->open();
|
|
if (!success)
|
|
{
|
|
delete m_menuWindow;
|
|
m_menuWindow = (FAR NXWidgets::CNxTkWindow *)0;
|
|
return false;
|
|
}
|
|
|
|
// 6. Set the initial window size
|
|
|
|
if (!setMenuWindowSize())
|
|
{
|
|
delete m_menuWindow;
|
|
m_menuWindow = (FAR NXWidgets::CNxTkWindow *)0;
|
|
return false;
|
|
}
|
|
|
|
// 7. Set the initial window position
|
|
|
|
struct nxgl_point_s pos =
|
|
{
|
|
.x = 0,
|
|
.y = 0
|
|
};
|
|
|
|
if (!m_menuWindow->setPosition(&pos))
|
|
{
|
|
delete m_menuWindow;
|
|
m_menuWindow = (FAR NXWidgets::CNxTkWindow *)0;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Update the menu window size
|
|
*
|
|
* @result True is returned on success
|
|
*/
|
|
|
|
bool CMenus::setMenuWindowSize(void)
|
|
{
|
|
CFonts *fonts = m_twm4nx->getFonts();
|
|
FAR NXWidgets::CNxFont *menuFont = fonts->getMenuFont();
|
|
|
|
m_entryHeight = menuFont->getHeight() + 4;
|
|
|
|
// Get the length of the longest item string in in the menu
|
|
|
|
nxgl_coord_t maxstring = 0;
|
|
for (FAR struct SMenuItem *curr = m_menuHead;
|
|
curr != NULL;
|
|
curr = curr->flink)
|
|
{
|
|
if (curr->text != (FAR char *)0)
|
|
{
|
|
nxgl_coord_t stringlen = menuFont->getStringWidth(curr->text);
|
|
if (stringlen > maxstring)
|
|
{
|
|
maxstring = stringlen;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Lets first size the window accordingly
|
|
|
|
struct nxgl_size_s menuSize;
|
|
menuSize.w = maxstring + 10;
|
|
|
|
unsigned int nMenuItems = m_nMenuItems > 0 ? m_nMenuItems : 1;
|
|
menuSize.h = nMenuItems * m_entryHeight;
|
|
|
|
if (m_menuPull == true)
|
|
{
|
|
menuSize.w += 16;
|
|
}
|
|
|
|
// Clip to the size of the display
|
|
|
|
struct nxgl_size_s displaySize;
|
|
m_twm4nx->getDisplaySize(&displaySize);
|
|
|
|
struct nxgl_size_s frameSize;
|
|
menuToFrameSize(&menuSize, &frameSize);
|
|
|
|
if (frameSize.w > displaySize.w)
|
|
{
|
|
frameSize.w = displaySize.w;
|
|
}
|
|
|
|
if (frameSize.h > displaySize.h)
|
|
{
|
|
frameSize.h = displaySize.h;
|
|
}
|
|
|
|
// Set the new menu window size
|
|
|
|
frameToMenuSize(&frameSize, &menuSize);
|
|
|
|
if (!m_menuWindow->setSize(&menuSize))
|
|
{
|
|
gerr("ERROR: Failed to set window size\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Set the position of the menu window. Supports positioning of a
|
|
* pop-up window.
|
|
*
|
|
* @param framePos The position of the menu window frame
|
|
* @result True is returned on success
|
|
*/
|
|
|
|
bool CMenus::setMenuWindowPosition(FAR struct nxgl_point_s *framePos)
|
|
{
|
|
struct nxgl_point_s menuPos;
|
|
frameToMenuPos(framePos, &menuPos);
|
|
return m_menuWindow->setPosition(&menuPos);
|
|
}
|
|
|
|
/**
|
|
* Create the menu list box
|
|
*
|
|
* @result True is returned on success
|
|
*/
|
|
|
|
bool CMenus::createMenuListBox(void)
|
|
{
|
|
// Create the menu list box
|
|
// 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.
|
|
|
|
FAR CWindowEvent *control = new CWindowEvent(m_twm4nx);
|
|
|
|
// 4. Create the menu list box
|
|
|
|
struct nxgl_point_s pos;
|
|
pos.x = 0;
|
|
pos.y = 0;
|
|
|
|
struct nxgl_size_s size;
|
|
pos.x = 0;
|
|
pos.y = 0;
|
|
|
|
m_menuListBox = new NXWidgets::CListBox(control, pos.x, pos.y,
|
|
size.w, size.h);
|
|
if (m_menuListBox == (FAR NXWidgets::CListBox *)0)
|
|
{
|
|
gerr("ERROR: Failed to instantiate list box\n");
|
|
delete control;
|
|
return false;
|
|
}
|
|
|
|
// Configure the list box
|
|
|
|
m_menuListBox->disable();
|
|
m_menuListBox->disableDrawing();
|
|
m_menuListBox->disableDrawing();
|
|
|
|
// Register to get events from the mouse clicks on the image
|
|
|
|
m_menuListBox->addWidgetEventHandler(this);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Pop up a pull down menu.
|
|
*
|
|
* @param pos Location of upper left of menu frame
|
|
*/
|
|
|
|
bool CMenus::popUpMenu(FAR struct nxgl_point_s *pos)
|
|
{
|
|
// If there is already a popup menu, then delete it. We only permit
|
|
// one popup at this level.
|
|
|
|
if (m_popUpMenu != (FAR CMenus *)0)
|
|
{
|
|
delete m_popUpMenu;
|
|
}
|
|
|
|
// Create and initialize a new menu
|
|
|
|
m_popUpMenu = new CMenus(m_twm4nx);
|
|
if (m_popUpMenu == (FAR CMenus *)0)
|
|
{
|
|
gerr("ERROR: Failed to create popup menu.\n");
|
|
return false;
|
|
}
|
|
|
|
if (!m_popUpMenu->initialize(m_activeItem->text))
|
|
{
|
|
gerr("ERROR: Failed to intialize popup menu.\n");
|
|
delete m_popUpMenu;
|
|
m_popUpMenu = (FAR CMenus *)0;
|
|
return false;
|
|
}
|
|
|
|
m_popUpMenu->addMenuItem("TWM Windows", (FAR const char *)0,
|
|
(FAR CMenus *)0, 0);
|
|
|
|
FAR CWindowFactory *factory = m_twm4nx->getWindowFactory();
|
|
int nWindowNames;
|
|
|
|
FAR struct SWindow *swin;
|
|
for (swin = factory->windowHead(), nWindowNames = 0;
|
|
swin != NULL; swin = swin->flink)
|
|
{
|
|
nWindowNames++;
|
|
}
|
|
|
|
if (nWindowNames != 0)
|
|
{
|
|
FAR CWindow **windowNames =
|
|
(FAR CWindow **)std::malloc(sizeof(FAR CWindow *) * nWindowNames);
|
|
|
|
if (windowNames == (FAR CWindow **)0)
|
|
{
|
|
gerr("ERROR: Failed to allocat window name\n");
|
|
return false;
|
|
}
|
|
|
|
swin = factory->windowHead();
|
|
windowNames[0] = swin->cwin;
|
|
|
|
for (nWindowNames = 1;
|
|
swin != NULL;
|
|
swin = swin->flink, nWindowNames++)
|
|
{
|
|
FAR CWindow *tmpcwin1 = swin->cwin;
|
|
for (int i = 0; i < nWindowNames; i++)
|
|
{
|
|
FAR const char *windowName1 = tmpcwin1->getWindowName();
|
|
FAR const char *windowName2 = windowNames[i]->getWindowName();
|
|
|
|
if (std::strcmp(windowName1, windowName2) < 0)
|
|
{
|
|
FAR CWindow *tmpcwin2;
|
|
tmpcwin2 = tmpcwin1;
|
|
tmpcwin1 = windowNames[i];
|
|
windowNames[i] = tmpcwin2;
|
|
}
|
|
}
|
|
|
|
windowNames[nWindowNames] = tmpcwin1;
|
|
}
|
|
|
|
for (int i = 0; i < nWindowNames; i++)
|
|
{
|
|
m_popUpMenu->addMenuItem(windowNames[i]->getWindowName(),
|
|
(FAR const char *)0, (FAR CMenus *)0,
|
|
EVENT_WINDOW_POPUP);
|
|
}
|
|
|
|
std::free(windowNames);
|
|
}
|
|
|
|
if (m_nMenuItems == 0)
|
|
{
|
|
delete m_popUpMenu;
|
|
m_popUpMenu = (FAR CMenus *)0;
|
|
return false;
|
|
}
|
|
|
|
// Clip to screen
|
|
|
|
struct nxgl_size_s displaySize;
|
|
m_twm4nx->getDisplaySize(&displaySize);
|
|
|
|
struct nxgl_size_s menuSize;
|
|
m_menuWindow->getSize(&menuSize);
|
|
|
|
struct nxgl_size_s frameSize;
|
|
menuToFrameSize(&menuSize, &frameSize);
|
|
|
|
if (pos->x + frameSize.w > displaySize.w)
|
|
{
|
|
pos->x = displaySize.w - frameSize.w;
|
|
}
|
|
|
|
if (pos->x < 0)
|
|
{
|
|
pos->x = 0;
|
|
}
|
|
|
|
if (pos->y + frameSize.h > displaySize.h)
|
|
{
|
|
pos->y = displaySize.h - frameSize.h;
|
|
}
|
|
|
|
if (pos->y < 0)
|
|
{
|
|
pos->y = 0;
|
|
}
|
|
|
|
DEBUGASSERT(m_menuDepth < UINT8_MAX);
|
|
m_menuDepth++;
|
|
|
|
if (!m_popUpMenu->setMenuWindowPosition(pos))
|
|
{
|
|
delete m_popUpMenu;
|
|
m_popUpMenu = (FAR CMenus *)0;
|
|
return false;
|
|
}
|
|
|
|
m_popUpMenu->raiseMenuWindow();
|
|
m_menuWindow->synchronize();
|
|
return m_popUpMenu;
|
|
}
|
|
|
|
/**
|
|
* Cleanup or initialization error or on deconstruction.
|
|
*/
|
|
|
|
void CMenus::cleanup(void)
|
|
{
|
|
// Close the NxWidget event message queue
|
|
|
|
if (m_eventq != (mqd_t)-1)
|
|
{
|
|
(void)mq_close(m_eventq);
|
|
m_eventq = (mqd_t)-1;
|
|
}
|
|
|
|
// Free any popup menus
|
|
|
|
if (m_popUpMenu != (FAR CMenus *)0)
|
|
{
|
|
delete m_popUpMenu;
|
|
}
|
|
|
|
// Free the menu window
|
|
|
|
if (m_menuWindow != (FAR NXWidgets::CNxTkWindow *)0)
|
|
{
|
|
delete m_menuWindow;
|
|
m_menuWindow = (FAR NXWidgets::CNxTkWindow *)0;
|
|
}
|
|
|
|
// Free each menu item
|
|
|
|
FAR struct SMenuItem *curr;
|
|
FAR struct SMenuItem *next;
|
|
|
|
for (curr = m_menuHead; curr != (FAR struct SMenuItem *)0; curr = next)
|
|
{
|
|
next = curr->flink;
|
|
|
|
// Free the menu item text
|
|
|
|
if (curr->text != (FAR char *)0)
|
|
{
|
|
std::free(curr->text);
|
|
}
|
|
|
|
// Free any subMenu
|
|
|
|
if (curr->subMenu != (FAR CMenus *)0)
|
|
{
|
|
delete curr->subMenu;
|
|
}
|
|
|
|
// Free the menu item
|
|
|
|
delete curr;
|
|
}
|
|
|
|
// Free allocated memory
|
|
|
|
if (m_menuName != (FAR char *)0)
|
|
{
|
|
std::free(m_menuName);
|
|
m_menuName = (FAR char *)0;
|
|
}
|
|
}
|