#include <nuttx/config.h>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include "graphics/nxwidgets/cnxwindow.hxx"
#include "graphics/nxwidgets/cnxfont.hxx"
#include "graphics/nxwidgets/cnxstring.hxx"
#include "graphics/nxwidgets/cbuttonarray.hxx"
#include <nuttx/nx/nx.h>
#include <nuttx/nx/nxglib.h>
#include "graphics/nxglyphs.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/cmenus.hxx"
#include "graphics/twm4nx/cmainmenu.hxx"
#include "graphics/twm4nx/cwindow.hxx"
#include "graphics/twm4nx/cwindowevent.hxx"
#include "graphics/twm4nx/cwindowfactory.hxx"
#include "graphics/twm4nx/ctwm4nxevent.hxx"
#include "graphics/twm4nx/twm4nx_events.hxx"
#include "graphics/twm4nx/ciconmgr.hxx"
using namespace Twm4Nx;
* CIconMgr Constructor
*
* @param twm4nx The Twm4Nx session
* @param ncolumns The number of columns this icon manager has
*/
CIconMgr::CIconMgr(CTwm4Nx *twm4nx, uint8_t ncolumns)
{
m_twm4nx = twm4nx;
m_eventq = (mqd_t)-1;
m_head = (FAR struct SWindowEntry *)0;
m_tail = (FAR struct SWindowEntry *)0;
m_window = (FAR CWindow *)0;
m_buttons = (FAR NXWidgets::CButtonArray *)0;
m_nColumns = ncolumns;
m_nrows = 0;
m_nWindows = 0;
}
* CIconMgr Destructor
*/
CIconMgr::~CIconMgr(void)
{
if (m_eventq != (mqd_t)-1)
{
mq_close(m_eventq);
}
if (m_window != (FAR CWindow *)0)
{
delete m_window;
}
if (m_buttons != (FAR NXWidgets::CButtonArray *)0)
{
delete m_buttons;
}
}
* Create and initialize the icon manager window
*
* @param name The prefix for this icon manager name
*/
bool CIconMgr::initialize(FAR const char *prefix)
{
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 (!createIconManagerWindow(prefix))
{
twmerr("ERROR: Failed to create window\n");
return false;
}
if (!createButtonArray())
{
twmerr("ERROR: Failed to create button array\n");
CWindowFactory *factory = m_twm4nx->getWindowFactory();
factory->destroyWindow(m_window);
m_window = (FAR CWindow *)0;
return false;
}
return true;
}
* Add Icon Manager menu items to the Main menu. This is really a
* part of the logic that belongs in initialize() but cannot be
* executed in that context because it assumes that the Main Menu
* logic is ready.
*
* @return True on success
*/
bool CIconMgr::addMenuItems(void)
{
FAR CMainMenu *cmain = m_twm4nx->getMainMenu();
if (!cmain->addApplication(this))
{
twmerr("ERROR: Failed to add to the Main Menu\n");
return false;
}
return true;
}
* Add a window to an icon manager
*
* @param win the TWM window structure
*/
bool CIconMgr::addWindow(FAR CWindow *cwin)
{
if (cwin->isIconMgr())
{
return false;
}
FAR struct SWindowEntry *wentry =
(FAR struct SWindowEntry *)std::malloc(sizeof(struct SWindowEntry));
if (wentry == (FAR struct SWindowEntry *)0)
{
return false;
}
wentry->flink = NULL;
wentry->cwin = cwin;
wentry->row = -1;
wentry->column = -1;
insertEntry(wentry, cwin);
m_nWindows++;
uint8_t oldrows = m_nrows == 0 ? 1 : m_nrows;
m_nrows = (m_nWindows + m_nColumns - 1) / m_nColumns;
if (oldrows != m_nrows)
{
if (!resizeIconManager())
{
twmerr("ERROR: resizeIconManager failed\n");
removeWindow(cwin);
return false;
}
}
else
{
labelButtons();
}
return true;
}
* Remove a window from the icon manager
*
* @param win the TWM window structure
*/
void CIconMgr::removeWindow(FAR CWindow *cwin)
{
if (cwin != (FAR CWindow *)0)
{
FAR struct SWindowEntry *wentry = findEntry(cwin);
if (wentry != (FAR struct SWindowEntry *)0)
{
removeEntry(wentry);
m_nWindows--;
std::free(wentry);
uint8_t oldrows = m_nrows == 0 ? 1 : m_nrows;
m_nrows = (m_nWindows + m_nColumns - 1) / m_nColumns;
uint8_t newrows = m_nrows == 0 ? 1 : m_nrows;
if (oldrows != newrows)
{
if (!resizeIconManager())
{
twmerr("ERROR: resizeIconManager failed\n");
}
}
else
{
labelButtons();
}
}
}
}
* Resize the button array and containing window
*
* @return True if the button array was resized successfully
*/
bool CIconMgr::resizeIconManager(void)
{
uint8_t newrows = m_nrows == 0 ? 1 : m_nrows;
struct nxgl_size_s windowSize;
if (!m_window->getWindowSize(&windowSize))
{
twmerr("ERROR: Failed to get old window size\n");
return false;
}
nxgl_coord_t rowHeight = getButtonHeight();
windowSize.h = newrows * rowHeight;
if (!m_window->setWindowSize(&windowSize))
{
twmerr("ERROR: Failed to set new window size\n");
return false;
}
m_window->synchronize();
nxgl_coord_t buttonWidth = windowSize.w / m_nColumns;
if (!m_buttons->resizeArray(m_nColumns, newrows, buttonWidth,
rowHeight))
{
twmerr("ERROR: CButtonArray::resizeArray failed\n");
return false;
}
labelButtons();
return true;
}
* Sort the windows
*/
void CIconMgr::sort(void)
{
FAR struct SWindowEntry *tmpwin1;
FAR struct SWindowEntry *tmpwin2;
bool done;
done = false;
do
{
for (tmpwin1 = m_head; tmpwin1 != NULL; tmpwin1 = tmpwin1->flink)
{
if ((tmpwin2 = tmpwin1->flink) == NULL)
{
done = true;
break;
}
NXWidgets::CNxString windowName = tmpwin1->cwin->getWindowName();
if (windowName.compareTo(tmpwin2->cwin->getWindowName()) > 0)
{
removeEntry(tmpwin2);
insertEntry(tmpwin2, tmpwin2->cwin);
break;
}
}
}
while (!done);
labelButtons();
}
* Handle ICONMGR events.
*
* @param msg. The received NxWidget ICONMGR event message.
* @return True if the message was properly handled. false is
* return on any failure.
*/
bool CIconMgr::event(FAR struct SEventMsg *eventmsg)
{
bool success = true;
switch (eventmsg->eventID)
{
case EVENT_ICONMGR_XYINPUT:
{
NXWidgets::CWidgetControl *control = m_window->getWidgetControl();
control->pollEvents();
}
break;
case EVENT_ICONMGR_DEICONIFY:
{
if (m_window->isIconified())
{
if (!m_window->deIconify())
{
twmerr("ERROR: Failed to de-iconify\n");
success = false;
}
}
else
{
if (!m_window->raiseWindow())
{
twmerr("ERROR: Failed to raise window\n");
success = false;
}
}
}
break;
default:
success = false;
break;
}
return success;
}
* Return the width of one button
*
* @return The width of one button
*/
nxgl_coord_t CIconMgr::getButtonWidth(void)
{
FAR CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *iconManagerFont = fonts->getIconManagerFont();
return 8 * iconManagerFont->getCharWidth('M') + 4;
}
* Return the height of one row
*
* @return The height of one row
*/
nxgl_coord_t CIconMgr::getButtonHeight(void)
{
FAR CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *iconManagerFont = fonts->getIconManagerFont();
return iconManagerFont->getHeight() + 6;
}
* Create and initialize the icon manager window
*
* @param name The prefix for this icon manager name
*/
bool CIconMgr::createIconManagerWindow(FAR const char *prefix)
{
if (prefix != (FAR const char *)0)
{
m_name.setText(prefix);
m_name.append(" Icon Manager");
}
else
{
m_name.setText("Icon Manager");
}
CWindowFactory *factory = m_twm4nx->getWindowFactory();
uint8_t wflags = (WFLAGS_NO_MENU_BUTTON | WFLAGS_NO_DELETE_BUTTON |
WFLAGS_NO_RESIZE_BUTTON | WFLAGS_ICONMGR |
WFLAGS_HIDDEN);
m_window = factory->createWindow(m_name, &CONFIG_TWM4NX_ICONMGR_IMAGE,
this, wflags);
if (m_window == (FAR CWindow *)0)
{
twmerr("ERROR: Failed to create icon manager window");
return false;
}
struct SAppEvents events;
events.eventObj = (FAR void *)this;
events.redrawEvent = EVENT_SYSTEM_NOP;
events.resizeEvent = EVENT_SYSTEM_NOP;
events.mouseEvent = EVENT_ICONMGR_XYINPUT;
events.kbdEvent = EVENT_SYSTEM_NOP;
events.closeEvent = EVENT_SYSTEM_NOP;
events.deleteEvent = EVENT_WINDOW_DELETE;
bool success = m_window->configureEvents(events);
if (!success)
{
delete m_window;
m_window = (FAR CWindow *)0;
return false;
}
struct nxgl_size_s windowSize;
windowSize.w = m_nColumns * getButtonWidth();
windowSize.h = getButtonHeight();
struct nxgl_size_s frameSize;
m_window->windowToFrameSize(&windowSize, &frameSize);
struct nxgl_size_s displaySize;
m_twm4nx->getDisplaySize(&displaySize);
struct nxgl_point_s framePos;
framePos.x = displaySize.w - frameSize.w - 1;
framePos.y = 0;
if (!m_window->resizeFrame(&frameSize, &framePos))
{
twmerr("ERROR: Failed to set window size/position\n");
delete m_window;
m_window = (FAR CWindow *)0;
return false;
}
m_window->showWindow();
m_window->synchronize();
return true;
}
* Create the button array widget
*/
bool CIconMgr::createButtonArray(void)
{
struct nxgl_size_s windowSize;
if (!m_window->getWindowSize(&windowSize))
{
twmerr("ERROR: Failed to get window size\n");
return false;
}
uint8_t nrows = m_nrows > 0 ? m_nrows : 1;
nxgl_coord_t buttonWidth = windowSize.w / m_nColumns;
nxgl_coord_t buttonHeight = windowSize.h / nrows;
FAR NXWidgets:: CWidgetControl *control = m_window->getWidgetControl();
if (control == (FAR NXWidgets:: CWidgetControl *)0)
{
return false;
}
m_buttons = new NXWidgets::CButtonArray(control, 0, 0,
m_nColumns, nrows,
buttonWidth, buttonHeight);
if (m_buttons == (FAR NXWidgets::CButtonArray *)0)
{
twmerr("ERROR: Failed to create the button array\n");
return false;
}
FAR CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *iconManagerFont = fonts->getIconManagerFont();
m_buttons->setFont(iconManagerFont);
m_buttons->setBorderless(true);
m_buttons->setRaisesEvents(true);
m_buttons->enableDrawing();
m_buttons->redraw();
m_buttons->addWidgetEventHandler(this);
return true;
}
* Label each button with the window name
*/
void CIconMgr::labelButtons(void)
{
FAR struct SWindowEntry *swin = m_head;
uint8_t nrows = (m_nrows == 0) ? 1 : m_nrows;
for (int rowndx = 0; rowndx < nrows; rowndx++)
{
for (int colndx = 0; colndx < m_nColumns; colndx++)
{
if (swin != (FAR struct SWindowEntry *)0)
{
NXWidgets::CNxString string = swin->cwin->getWindowName();
m_buttons->setText(colndx, rowndx, string);
swin->row = rowndx;
swin->column = colndx;
swin = swin->flink;
}
else
{
m_buttons->setText(colndx, rowndx, "");
}
}
}
}
* Put an allocated entry into an icon manager
*
* @param wentry the entry to insert
*/
void CIconMgr::insertEntry(FAR struct SWindowEntry *wentry,
FAR CWindow *cwin)
{
FAR struct SWindowEntry *tmpwin;
if (m_head == NULL)
{
m_head = wentry;
wentry->blink = NULL;
m_tail = wentry;
return;
}
for (tmpwin = m_head;
tmpwin != (FAR struct SWindowEntry *)0;
tmpwin = tmpwin->flink)
{
NXWidgets::CNxString windowName = cwin->getWindowName();
if (windowName.compareTo(tmpwin->cwin->getWindowName()) > 0)
{
wentry->flink = tmpwin;
wentry->blink = tmpwin->blink;
tmpwin->blink = wentry;
if (wentry->blink == NULL)
{
m_head = wentry;
}
else
{
wentry->blink->flink = wentry;
}
return;
}
}
m_tail->flink = wentry;
wentry->blink = m_tail;
m_tail = wentry;
}
* Remove an entry from an icon manager
*
* @param wentry the entry to remove
*/
void CIconMgr::removeEntry(FAR struct SWindowEntry *wentry)
{
if (wentry->blink == NULL)
{
m_head = wentry->flink;
}
else
{
wentry->blink->flink = wentry->flink;
}
if (wentry->flink == NULL)
{
m_tail = wentry->blink;
}
else
{
wentry->flink->blink = wentry->blink;
}
}
* Find an entry in the icon manager
*
* @param cwin The window to find
* @return The incon manager entry (unless an error occurred)
*/
FAR struct SWindowEntry *CIconMgr::findEntry(FAR CWindow *cwin)
{
FAR struct SWindowEntry *wentry;
for (wentry = m_head;
wentry != (FAR struct SWindowEntry *)0;
wentry = wentry->flink)
{
if (wentry->cwin == cwin)
{
return wentry;
}
}
return wentry;
}
* Free window list entry.
*/
void CIconMgr::freeWEntry(FAR struct SWindowEntry *wentry)
{
if (wentry->cwin != (FAR CWindow *)0)
{
delete wentry->cwin;
wentry->cwin = (FAR CWindow *)0;
}
free(wentry);
}
* Handle a widget action event. This will be a button pre-release event.
*
* @param e The event data.
*/
void CIconMgr::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
{
int column;
int row;
if (m_buttons->isButtonClicked(column, row))
{
for (FAR struct SWindowEntry *swin = m_head;
swin != (FAR struct SWindowEntry *)0;
swin = swin->flink)
{
if (row == swin->row && column == swin->column)
{
struct SEventMsg msg;
msg.obj = swin->cwin;
msg.pos.x = e.getX();
msg.pos.y = e.getY();
msg.context = EVENT_CONTEXT_ICONMGR;
msg.handler = (FAR void *)0;
if (swin->cwin->isIconified())
{
msg.eventID = EVENT_WINDOW_DEICONIFY;
}
else
{
msg.eventID = EVENT_WINDOW_RAISE;
}
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);
}
break;
}
}
twmwarn("WARNING: No matching window name\n");
}
}