wm4Nx is a port of twm, Tab Window Manager (or Tom's Window Manager)
version 1.0.10 to NuttX NX windows server. No, a port is not the right
word. It is a re-design of TWM from the inside out to work with the NuttX
NX server. The name Twm4Nx reflects this legacy. But Twm4Nx is more a
homage to TWM than a port of TWM.
The original TWM was based on X11 which provides a rich set of features.
TWM provided titlebars, shaped windows, several forms of icon management,
user-defined macro functions, click-to-type and pointer-driven keyboard
focus, graphic contexts, and user-specified key and pointer button bindings,
etc.
Twm4Nx, on the other hand is based on the NuttX NX server which provides
comparatively minimal support. Additional drawing support comes from
the NuttX NxWidgets library (which necessitated the change to C++).
Twm4Nx is greatly stripped down and targeted on small embedded systems
with minimal resources. For example, no assumption is made about the
availability of a file system; no .twmrc file is used. Bitmaps are not
used (other than for fonts).
The TWM license is, I believe compatible with the BSD license used by NuttX.
The origin TWM license required notice of copyrights within each file and
a full copy of the original license which you can find in the COPYING file.
within this directory.
STATUS:
This port was brutal. Much TWM logic was removed because it depending on X11 features (or just because I could not understand how to use it). The logic is partial. A lot more needs to be done to have a complete system (hence, it is marked EXPERIMENTAL). The kinds of things that need to done are:
1. Update some logic that is only fragmentary for how like resizing, and menus.
2. Integrate NxWidgets into the windows: The resize menu needs a CLabel, the menus are CListBox'es, but not completely integrated, the Icon Manager needs to be a button array.
3. Resit Icons. They are windows now, but need to be compound widgets lying on the background.
4. Widget events are only partially integrated. A lot more needs to be done. A partial change to thoe event system that hints at the redesign is in place but it is far from complete.
2019-04-25 16:54:17 -06:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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;
|
2019-04-26 12:50:35 -06:00
|
|
|
newmsg.delta.x = 0;
|
|
|
|
newmsg.delta.y = 0;
|
wm4Nx is a port of twm, Tab Window Manager (or Tom's Window Manager)
version 1.0.10 to NuttX NX windows server. No, a port is not the right
word. It is a re-design of TWM from the inside out to work with the NuttX
NX server. The name Twm4Nx reflects this legacy. But Twm4Nx is more a
homage to TWM than a port of TWM.
The original TWM was based on X11 which provides a rich set of features.
TWM provided titlebars, shaped windows, several forms of icon management,
user-defined macro functions, click-to-type and pointer-driven keyboard
focus, graphic contexts, and user-specified key and pointer button bindings,
etc.
Twm4Nx, on the other hand is based on the NuttX NX server which provides
comparatively minimal support. Additional drawing support comes from
the NuttX NxWidgets library (which necessitated the change to C++).
Twm4Nx is greatly stripped down and targeted on small embedded systems
with minimal resources. For example, no assumption is made about the
availability of a file system; no .twmrc file is used. Bitmaps are not
used (other than for fonts).
The TWM license is, I believe compatible with the BSD license used by NuttX.
The origin TWM license required notice of copyrights within each file and
a full copy of the original license which you can find in the COPYING file.
within this directory.
STATUS:
This port was brutal. Much TWM logic was removed because it depending on X11 features (or just because I could not understand how to use it). The logic is partial. A lot more needs to be done to have a complete system (hence, it is marked EXPERIMENTAL). The kinds of things that need to done are:
1. Update some logic that is only fragmentary for how like resizing, and menus.
2. Integrate NxWidgets into the windows: The resize menu needs a CLabel, the menus are CListBox'es, but not completely integrated, the Icon Manager needs to be a button array.
3. Resit Icons. They are windows now, but need to be compound widgets lying on the background.
4. Widget events are only partially integrated. A lot more needs to be done. A partial change to thoe event system that hints at the redesign is in place but it is far from complete.
2019-04-25 16:54:17 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|