diff --git a/graphics/twm4nx/Kconfig b/graphics/twm4nx/Kconfig index 42e2b0efa..40251d72e 100644 --- a/graphics/twm4nx/Kconfig +++ b/graphics/twm4nx/Kconfig @@ -17,6 +17,8 @@ menuconfig GRAPHICS_TWM4NX if GRAPHICS_TWM4NX +comment "Twm4Nx Core Configuration" + config TWM4NX_PROGNAME string "Twm4Nx program name" default "twm4nx" @@ -123,6 +125,15 @@ config TWM4NX_DEBUG and CONFIG_DEBUG_ERROR (but not the corresponding CONFIG_DEBUG_GRAPHICS_* settings) +comment "Twm4Nx Applications" + +config TWM4NX_CALIBRATION + bool "Touchscreen" + default y + depends on TWM4NX_TOUCHSCREEN + ---help--- + Enable support for the touchscreen calibration display. + config TWM4NX_NXTERM bool "NxTerm Window" default y diff --git a/graphics/twm4nx/Makefile b/graphics/twm4nx/Makefile index f9e728ad5..e19f71859 100644 --- a/graphics/twm4nx/Makefile +++ b/graphics/twm4nx/Makefile @@ -64,13 +64,17 @@ ifeq ($(CONFIG_TWM4NX_MOUSE),y) CXXSRCS += twm4nx_cursor.cxx endif +ifeq ($(CONFIG_TWM4NX_CALIBRATION),y) +CXXSRCS += ccalibration.cxx +endif + ifeq ($(CONFIG_TWM4NX_NXTERM),y) CXXSRCS += cnxterm.cxx endif MAINSRC = ctwm4nx.cxx -VPATH = src +VPATH = src:apps CONFIG_TWM4NX_PROGNAME ?= hello$(EXEEXT) PROGNAME = $(CONFIG_TWM4NX_PROGNAME) diff --git a/graphics/twm4nx/apps/ccalibration.cxx b/graphics/twm4nx/apps/ccalibration.cxx new file mode 100644 index 000000000..25eaa9d65 --- /dev/null +++ b/graphics/twm4nx/apps/ccalibration.cxx @@ -0,0 +1,1390 @@ +///////////////////////////////////////////////////////////////////////////// +// apps/graphics/twm4nx/src/ccalibration.cxx +// Perform Touchscreen Calibration +// +// Copyright (C) 2019 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt +// +// 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 + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#ifdef CONFIG_TWM4NX_TOUCHSCREEN_CONFIGDATA +# include "platform/configdata.h" +#endif + +#include "graphics/twm4nx/twm4nx_config.hxx" +#include "graphics/twm4nx/ctwm4nx.hxx" +#include "graphics/twm4nx/cinput.hxx" +#include "graphics/twm4nx/cmainmenu.hxx" + +#include "graphics/twm4nx/apps/calib_config.hxx" +#include "graphics/twm4nx/apps/ccalibration.hxx" + +///////////////////////////////////////////////////////////////////////////// +// Pre-processor Definitions +///////////////////////////////////////////////////////////////////////////// + +// Configuration + +#ifndef CONFIG_NX +# error "NX is not enabled (CONFIG_NX)" +#endif + +// Positional/size data for the calibration lines and circles + +#define CALIBRATION_LEFTX CONFIG_TWM4NX_CALIBRATION_MARGIN +#define CALIBRATION_RIGHTX (windowSize.w - CONFIG_TWM4NX_CALIBRATION_MARGIN + 1) +#define CALIBRATION_TOPY CONFIG_TWM4NX_CALIBRATION_MARGIN +#define CALIBRATION_BOTTOMY (windowSize.h - CONFIG_TWM4NX_CALIBRATION_MARGIN + 1) + +#define CALIBRATION_CIRCLE_RADIUS 16 +#define CALIBRATION_LINE_THICKNESS 2 + +///////////////////////////////////////////////////////////////////////////// +// Private Data +///////////////////////////////////////////////////////////////////////////// + +using namespace Twm4Nx; + +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES +static const char GTouchMsg[] = "Touch"; +static const char GAgainMsg[] = "Again"; +static const char GOkMsg[] = "OK"; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CCalibration Method Implementations +///////////////////////////////////////////////////////////////////////////// + +/** + * CCalibration Constructor + * + * @param twm4nx. The Twm4Nx session instance. + */ + +CCalibration::CCalibration(FAR CTwm4Nx *twm4nx) +{ + // Initialize state data + + m_twm4nx = twm4nx; + m_nxWin = (FAR NXWidgets::CNxWindow *)0; + m_thread = (pthread_t)0; + m_calthread = CALTHREAD_NOTRUNNING; + m_calphase = CALPHASE_NOT_STARTED; + m_touched = false; + +#ifdef CONFIG_TWM4NX_CALIBRATION_AVERAGE + m_nsamples = 0; +#endif + + // Initialize touch sample. + + m_sample.valid = false; + m_sample.pos.x = 0; + m_sample.pos.y = 0; + m_sample.buttons = 0; + +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + // Nullify widgets that will be instantiated when the calibration thread + // is started + + m_text = (NXWidgets::CLabel *)0; + m_font = (NXWidgets::CNxFont *)0; +#endif + + // Set up the semaphores that are used to synchronize the calibration + // thread with Twm4Nx events + + (void)sem_init(&m_exclSem, 0, 1); + (void)sem_init(&m_synchSem, 0, 0); + (void)sem_setprotocol(&m_synchSem, SEM_PRIO_NONE); +} + +/** + * CCalibration Destructor + */ + +CCalibration::~CCalibration(void) +{ + // Make sure that the application is not running (it should already + // have been stopped) + + stop(); + + if (m_nxWin != (FAR NXWidgets::CNxWindow *)0) + { + delete m_nxWin; + } +} + +/** + * CCalibration Initializer. Performs parts of the instance + * construction that may fail. This function creates the + * initial calibration display. + */ + +bool CCalibration::initialize(void) +{ + // Create the calibration 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. + + struct SAppEvents events; + events.eventObj = (FAR void *)this; + events.redrawEvent = EVENT_CALIB_REDRAW; + events.mouseEvent = EVENT_CALIB_XYINPUT; + events.kbdEvent = EVENT_CALIB_KBDINPUT; + events.closeEvent = EVENT_CALIB_CLOSE; + events.deleteEvent = EVENT_CALIB_DELETE; + + FAR CWindowEvent *control = + new CWindowEvent(m_twm4nx, (FAR CWindow *)0, events); + + // 4. Create the calibration window + + uint8_t wflags = NXBE_WINDOW_HIDDEN; + + m_nxWin = m_twm4nx->createRawWindow(control, wflags); + if (m_nxWin == (FAR NXWidgets::CNxWindow *)0) + { + gerr("ERROR: Failed open raw window\n"); + delete control; + return false; + } + + // 5. Open and initialize the main window + + bool success = m_nxWin->open(); + if (!success) + { + delete m_nxWin; + m_nxWin = (FAR NXWidgets::CNxWindow *)0; + return false; + } + + // 6. Set the window position to the display origin + + struct nxgl_point_s pos = + { + .x = 0, + .y = 0 + }; + + if (!m_nxWin->setPosition(&pos)) + { + delete m_nxWin; + m_nxWin = (FAR NXWidgets::CNxWindow *)0; + return false; + } + + // 7. Set the window size to fill the whole display + + struct nxgl_size_s displaySize; + m_twm4nx->getDisplaySize(&displaySize); + + if (!m_nxWin->setSize(&displaySize)) + { + delete m_nxWin; + m_nxWin = (FAR NXWidgets::CNxWindow *)0; + return false; + } + +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + // Create widgets that will be used in the calibration display + + if (!createWidgets()) + { + gerr("ERROR: failed to create widgets\n"); + return (FAR void *)0; + } +#endif + + // Disable touchscreen processing so that we receive raw, un-calibrated + // touchscreen input + + FAR CInput *cinput = m_twm4nx->getInput(); + + cinput->enableCalibration(false); + return true; +} + +/** + * Start the application (perhaps in the minimized state). + * + * @return True if the application was successfully started. + */ + +bool CCalibration::run(void) +{ + // Verify that the thread is not already running + + if (m_calthread == CALTHREAD_RUNNING) + { + gwarn("WARNING: The calibration thread is already running\n"); + return false; + } + + // Configure the calibration thread + + pthread_attr_t attr; + (void)pthread_attr_init(&attr); + + struct sched_param param; + param.sched_priority = CONFIG_TWM4NX_CALIBRATION_LISTENERPRIO; + (void)pthread_attr_setschedparam(&attr, ¶m); + + (void)pthread_attr_setstacksize(&attr, CONFIG_TWM4NX_CALIBRATION_LISTENERSTACK); + + // Set the initial state of the thread + + m_calthread = CALTHREAD_STARTED; + + // Start the thread that will perform the calibration process + + int ret = pthread_create(&m_thread, &attr, calibration, (FAR void *)this); + if (ret != 0) + { + gerr("ERROR: pthread_create failed: %d\n", ret); + return false; + } + + ginfo("Calibration thread m_calthread=%d\n", (int)m_calthread); + return true; +} + +/** + * Handle CCalibration events. This overrides a method from + * CTwm4NXEvent. + * + * @param eventmsg. The received NxWidget WINDOW event message. + * @return True if the message was properly handled. false is + * return on any failure. + */ + +bool CCalibration::event(FAR struct SEventMsg *eventmsg) +{ + bool success = true; + + switch (eventmsg->eventID) + { + case EVENT_CALIB_XYINPUT: // New touchscreen input + { + // Make sure that the thread is still running + + if (m_calthread == CALTHREAD_RUNNING) + { + // Get exclusive access to the data shared between threads + + success = exclusiveAccess(); + if (success) + { + FAR struct SXyInputEventMsg *xymsg = + (FAR struct SXyInputEventMsg *)eventmsg; + + // Save the new sample data + + m_sample.valid = true; + m_sample.pos = xymsg->pos; + m_sample.buttons = xymsg->buttons; + + // And let the let the calibration thread know that new + // data is available + + sem_post(&m_synchSem); + sem_post(&m_exclSem); + } + } + } + break; + + case EVENT_CALIB_DELETE: // Today is a good day to die. + DEBUGASSERT(m_calthread == CALTHREAD_TERMINATED); + delete this; // This is suicide + break; + + default: + success = false; + break; + } + + return success; +} + +/** + * Accept raw touchscreen input. + * + * @param sample Touchscreen input sample + */ + +void CCalibration::touchscreenInput(struct STouchSample &sample) +{ + // Is this a new touch event? + + if ((sample.buttons & MOUSE_BUTTON_1) != 0) + { + // Yes.. save the touch position and wait for the un-touch report + + m_touchPos.x = sample.pos.x; + m_touchPos.y = sample.pos.y; + + twminfo("Touch buttons: %02x x: %d y: %d\n", + sample.buttons, sample.pos.x, sample.pos.y); + + // Show calibration screen again, changing the color of the circle to + // make it clear that the touch has been noticed. + + if (!m_touched) + { + m_screenInfo.circleFillColor = CONFIG_TWM4NX_CALIBRATION_TOUCHEDCOLOR; +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + m_text->setText(GOkMsg); +#endif + showCalibration(); + m_touched = true; + } + } + + // There is no touch. Did we see the pen down event? + + else if (m_touched) + { + // Yes.. invoke the state machine. + + twminfo("State: %d Screen x: %d y: %d Touch x: %d y: %d\n", + m_calphase, m_screenInfo.pos.x, m_screenInfo.pos.y, + m_touchPos.x, m_touchPos.y); + + stateMachine(); + + // The screen is no longer touched + + m_touched = false; + } +} + +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES +/** + * Create widgets need by the calibration thread. + * + * @return True if the widgets were successfully created. + */ + +bool CCalibration::createWidgets(void) +{ + // Select a font for the calculator + + m_font = new NXWidgets:: + CNxFont((nx_fontid_e)CONFIG_TWM4NX_CALIBRATION_FONTID, + CONFIG_TWM4NX_DEFAULT_FONTCOLOR, CONFIG_TWM4NX_TRANSPARENT_COLOR); + if (!m_font) + { + gerr("ERROR failed to create font\n"); + return false; + } + + // Get the size of the window + + struct nxgl_size_s windowSize; + if (!m_nxWin->getSize(&windowSize)) + { + gerr("ERROR: Failed to get window size\n"); + delete m_font; + m_font = (NXWidgets::CNxFont *)0; + return false; + } + + // How big is the biggest string we might display? + + nxgl_coord_t maxStringWidth = m_font->getStringWidth(GTouchMsg); + nxgl_coord_t altStringWidth = m_font->getStringWidth(GAgainMsg); + + if (altStringWidth > maxStringWidth) + { + maxStringWidth = altStringWidth; + } + + // How big can the label be? + + struct nxgl_size_s labelSize; + labelSize.w = maxStringWidth + 2*4; + labelSize.h = m_font->getHeight() + 2*4; + + // Where should the label be? + + struct nxgl_point_s labelPos; + labelPos.x = ((windowSize.w - labelSize.w) / 2); + labelPos.y = ((windowSize.h - labelSize.h) / 2); + + // Get the widget control associated with the application window + + NXWidgets::CWidgetControl *control = m_nxWin->getWidgetControl(); + + // Create a label to show the calibration message. + + m_text = new NXWidgets:: + CLabel(control, labelPos.x, labelPos.y, labelSize.w, labelSize.h, ""); + + if (!m_text) + { + gerr("ERROR: Failed to create CLabel\n"); + delete m_font; + m_font = (NXWidgets::CNxFont *)0; + return false; + } + + // No border + + m_text->setBorderless(true); + + // Center text + + m_text->setTextAlignmentHoriz(NXWidgets::CLabel::TEXT_ALIGNMENT_HORIZ_CENTER); + + // Disable drawing and events until we are asked to redraw the window + + m_text->disableDrawing(); + m_text->setRaisesEvents(false); + + // Select the font + + m_text->setFont(m_font); + return true; +} + +/** + * Destroy widgets created for the calibration thread. + */ + +void CCalibration::destroyWidgets(void) +{ + delete m_text; + m_text = (NXWidgets::CLabel *)0; + + delete m_font; + m_font = (NXWidgets::CNxFont *)0; +} +#endif + +/** + * The calibration thread. This is the entry point of a thread that provides the + * calibration displays, waits for input, and collects calibration data. + * + * @param arg. The CCalibration 'this' pointer cast to a void*. + * @return This function always returns NULL when the thread exits + */ + +FAR void *CCalibration::calibration(FAR void *arg) +{ + CCalibration *This = (CCalibration *)arg; + + // The calibration thread is now running + + This->m_calthread = CALTHREAD_RUNNING; + This->m_calphase = CALPHASE_NOT_STARTED; + + ginfo("Started: m_calthread=%d\n", (int)This->m_calthread); + + // Make the calibration display visible + + This->m_nxWin->show(); + + // Loop until calibration completes or we have been requested to terminate + + while (This->m_calthread != CALTHREAD_STOPREQUESTED && + This->m_calphase != CALPHASE_COMPLETE) + { + // Wait for the next raw touchscreen input (or possibly a signal) + + struct STouchSample sample; + while (!This->waitTouchSample(sample) && + This->m_calthread == CALTHREAD_RUNNING); + + // Then process the raw touchscreen input + + if (This->m_calthread == CALTHREAD_RUNNING) + { + This->touchscreenInput(sample); + } + } + +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + // Hide the message + + This->m_text->setText(""); + This->m_text->enableDrawing(); + This->m_text->redraw(); + This->m_text->disableDrawing(); +#endif + + // Perform the final steps of calibration + + This->finishCalibration(); + + // Then destroy the window and free resources + + This->destroy(); + + ginfo("Terminated: m_calthread=%d\n", (int)This->m_calthread); + return (FAR void *)0; +} + +/** + * Get exclusive access data shared across threads. + * + * @return True is returned if the sample data was obtained without error. + */ + +bool CCalibration::exclusiveAccess(void) +{ + int ret; + + do + { + ret = sem_wait(&m_exclSem); + if (ret < 0) + { + int errcode = errno; + DEBUGASSERT(errcode == EINTR || errcode == ECANCELED); + if (errcode != EINTR) + { + return false; + } + } + } + while (ret < 0); + + return true; +} + +/** + * Wait for touchscreen next sample data to become available. + * + * @param sample Snapshot of last touchscreen sample + * @return True is returned if the sample data was obtained without error. + */ + +bool CCalibration::waitTouchSample(struct STouchSample &sample) +{ + // Loop until we get the sample (or something really bad happens) + + for (; ; ) + { + // Is the sample valid? + + if (!m_sample.valid) + { + // No, wait for new data to be posted + + int ret = sem_wait(&m_synchSem); + if (ret < 0) + { + // EINTR is not an error, it just means that we were + // interrupted by a signal. Everything else is bad news. + + int errcode = errno; + DEBUGASSERT(errcode == EINTR || errcode == ECANCELED); + if (errcode != EINTR) + { + return false; + } + } + } + + // The samples is valid! Get exclusive access and check again + + else if (exclusiveAccess()) + { + if (m_sample.valid) + { + // We have good data. Return it to the caller + + sample = m_sample; + m_sample.valid = false; + + sem_post(&m_exclSem); + return true; + } + else + { + // No.. What happened? + + sem_post(&m_exclSem); + } + } + } + + return true; +} + +/** + * Accumulate and average touch sample data + * + * @param average. When the averaged data is available, return it here + * @return True: Average data is available; False: Need to collect more samples + */ + +#ifdef CONFIG_TWM4NX_CALIBRATION_AVERAGE +bool CCalibration::averageSamples(struct nxgl_point_s &average) +{ + // Have we started collecting sample data? */ + + // Save the sample data + + twminfo("Sample %d: Touch x: %d y: %d\n", + m_nsamples + 1, m_touchPos.x, m_touchPos.y); + + m_sampleData[m_nsamples].x = m_touchPos.x; + m_sampleData[m_nsamples].y = m_touchPos.y; + m_nsamples++; + + // Have all of the samples been collected? + + if (m_nsamples < CONFIG_TWM4NX_CALIBRATION_NSAMPLES) + { + // Not yet... return false + + return false; + } + + // Yes.. we have all of the samples +#ifdef CONFIG_TWM4NX_CALIBRATION_NSAMPLES + // Discard the smallest X and Y values + + int xValue = INT_MAX; + int xIndex = -1; + + int yValue = INT_MAX; + int yIndex = -1; + + for (int i = 0; i < CONFIG_TWM4NX_CALIBRATION_NSAMPLES; i++) + { + if ((int)m_sampleData[i].x < xValue) + { + xValue = (int)m_sampleData[i].x; + xIndex = i; + } + + if ((int)m_sampleData[i].y < yValue) + { + yValue = (int)m_sampleData[i].y; + yIndex = i; + } + } + + m_sampleData[xIndex].x = m_sampleData[CONFIG_TWM4NX_CALIBRATION_NSAMPLES-1].x; + m_sampleData[yIndex].y = m_sampleData[CONFIG_TWM4NX_CALIBRATION_NSAMPLES-1].y; + + // Discard the largest X and Y values + + xValue = -1; + xIndex = -1; + + yValue = -1; + yIndex = -1; + + for (int i = 0; i < CONFIG_TWM4NX_CALIBRATION_NSAMPLES-1; i++) + { + if ((int)m_sampleData[i].x > xValue) + { + xValue = (int)m_sampleData[i].x; + xIndex = i; + } + + if ((int)m_sampleData[i].y > yValue) + { + yValue = (int)m_sampleData[i].y; + yIndex = i; + } + } + + m_sampleData[xIndex].x = m_sampleData[CONFIG_TWM4NX_CALIBRATION_NSAMPLES-2].x; + m_sampleData[yIndex].y = m_sampleData[CONFIG_TWM4NX_CALIBRATION_NSAMPLES-2].y; +#endif + +#if TWM4NX_CALIBRATION_NAVERAGE > 1 + // Calculate the average of the remaining values + + long xaccum = 0; + long yaccum = 0; + + for (int i = 0; i < TWM4NX_CALIBRATION_NAVERAGE; i++) + { + xaccum += m_sampleData[i].x; + yaccum += m_sampleData[i].y; + } + + average.x = xaccum / TWM4NX_CALIBRATION_NAVERAGE; + average.y = yaccum / TWM4NX_CALIBRATION_NAVERAGE; +#else + average.x = m_sampleData[0].x; + average.y = m_sampleData[0].y; +#endif + + twminfo("Average: Touch x: %d y: %d\n", average.x, average.y); + m_nsamples = 0; + return true; +} +#endif + +/** + * This is the calibration state machine. It is called initially and then + * as new touchscreen data is received. + */ + +void CCalibration::stateMachine(void) +{ + ginfo("Old m_calphase=%d\n", m_calphase); + +#ifdef CONFIG_TWM4NX_CALIBRATION_AVERAGE + // Are we collecting samples? + + struct nxgl_point_s average; + + switch (m_calphase) + { + case CALPHASE_UPPER_LEFT: + case CALPHASE_UPPER_RIGHT: + case CALPHASE_LOWER_RIGHT: + case CALPHASE_LOWER_LEFT: + { + // Yes... Have all of the samples been collected? + + if (!averageSamples(average)) + { + // Not yet... Show the calibration screen again with the circle + // in the normal color and an instruction to touch the circle again. + + m_screenInfo.circleFillColor = CONFIG_TWM4NX_CALIBRATION_CIRCLECOLOR; + m_text->setText(GAgainMsg); + showCalibration(); + + // And wait for the next touch + + return; + } + } + break; + + // No... we are not collecting data now + + default: + break; + } +#endif + + // Get the size of the fullscreen window + + struct nxgl_size_s windowSize; + if (!m_nxWin->getSize(&windowSize)) + { + return; + } + + switch (m_calphase) + { + default: + case CALPHASE_NOT_STARTED: + { + // Clear the entire screen + // Get the widget control associated with the full screen window + + NXWidgets::CWidgetControl *control = m_nxWin->getWidgetControl(); + + // Get the CCGraphicsPort instance for this window + + NXWidgets::CGraphicsPort *port = control->getGraphicsPort(); + + // Fill the entire window with the background color + + port->drawFilledRect(0, 0, windowSize.w, windowSize.h, + CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR); + + // Then draw the first calibration screen + + m_screenInfo.pos.x = CALIBRATION_LEFTX; + m_screenInfo.pos.y = CALIBRATION_TOPY; + m_screenInfo.lineColor = CONFIG_TWM4NX_CALIBRATION_LINECOLOR; + m_screenInfo.circleFillColor = CONFIG_TWM4NX_CALIBRATION_CIRCLECOLOR; +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + m_text->setText(GTouchMsg); +#endif + showCalibration(); + + // Then set up the current state + + m_calphase = CALPHASE_UPPER_LEFT; + } + break; + + case CALPHASE_UPPER_LEFT: + { + // A touch has been received while in the CALPHASE_UPPER_LEFT state. + // Save the touch data and set up the next calibration display + +#ifdef CONFIG_TWM4NX_CALIBRATION_AVERAGE + m_calibData[CALIB_UPPER_LEFT_INDEX].x = average.x; + m_calibData[CALIB_UPPER_LEFT_INDEX].y = average.y; +#else + m_calibData[CALIB_UPPER_LEFT_INDEX].x = m_touchPos.x; + m_calibData[CALIB_UPPER_LEFT_INDEX].y = m_touchPos.y; +#endif + + // Clear the previous screen by re-drawing it using the background + // color. That is much faster than clearing the whole display + + m_screenInfo.lineColor = CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR; + m_screenInfo.circleFillColor = CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR; + showCalibration(); + + // Then draw the next calibration screen + + m_screenInfo.pos.x = CALIBRATION_RIGHTX; + m_screenInfo.pos.y = CALIBRATION_TOPY; + m_screenInfo.lineColor = CONFIG_TWM4NX_CALIBRATION_LINECOLOR; + m_screenInfo.circleFillColor = CONFIG_TWM4NX_CALIBRATION_CIRCLECOLOR; +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + m_text->setText(GTouchMsg); +#endif + showCalibration(); + + // Then set up the current state + + m_calphase = CALPHASE_UPPER_RIGHT; + } + break; + + case CALPHASE_UPPER_RIGHT: + { + // A touch has been received while in the CALPHASE_UPPER_RIGHT state. + // Save the touch data and set up the next calibration display + +#ifdef CONFIG_TWM4NX_CALIBRATION_AVERAGE + m_calibData[CALIB_UPPER_RIGHT_INDEX].x = average.x; + m_calibData[CALIB_UPPER_RIGHT_INDEX].y = average.y; +#else + m_calibData[CALIB_UPPER_RIGHT_INDEX].x = m_touchPos.x; + m_calibData[CALIB_UPPER_RIGHT_INDEX].y = m_touchPos.y; +#endif + + // Clear the previous screen by re-drawing it using the backgro9und + // color. That is much faster than clearing the whole display + + m_screenInfo.lineColor = CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR; + m_screenInfo.circleFillColor = CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR; + showCalibration(); + + // Then draw the next calibration screen + + m_screenInfo.pos.x = CALIBRATION_RIGHTX; + m_screenInfo.pos.y = CALIBRATION_BOTTOMY; + m_screenInfo.lineColor = CONFIG_TWM4NX_CALIBRATION_LINECOLOR; + m_screenInfo.circleFillColor = CONFIG_TWM4NX_CALIBRATION_CIRCLECOLOR; +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + m_text->setText(GTouchMsg); +#endif + showCalibration(); + + // Then set up the current state + + m_calphase = CALPHASE_LOWER_RIGHT; + } + break; + + case CALPHASE_LOWER_RIGHT: + { + // A touch has been received while in the CALPHASE_LOWER_RIGHT state. + // Save the touch data and set up the next calibration display + +#ifdef CONFIG_TWM4NX_CALIBRATION_AVERAGE + m_calibData[CALIB_LOWER_RIGHT_INDEX].x = average.x; + m_calibData[CALIB_LOWER_RIGHT_INDEX].y = average.y; +#else + m_calibData[CALIB_LOWER_RIGHT_INDEX].x = m_touchPos.x; + m_calibData[CALIB_LOWER_RIGHT_INDEX].y = m_touchPos.y; +#endif + + // Clear the previous screen by re-drawing it using the backgro9und + // color. That is much faster than clearing the whole display + + m_screenInfo.lineColor = CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR; + m_screenInfo.circleFillColor = CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR; + showCalibration(); + + // Then draw the next calibration screen + + m_screenInfo.pos.x = CALIBRATION_LEFTX; + m_screenInfo.pos.y = CALIBRATION_BOTTOMY; + m_screenInfo.lineColor = CONFIG_TWM4NX_CALIBRATION_LINECOLOR; + m_screenInfo.circleFillColor = CONFIG_TWM4NX_CALIBRATION_CIRCLECOLOR; +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + m_text->setText(GTouchMsg); +#endif + showCalibration(); + + // Then set up the current state + + m_calphase = CALPHASE_LOWER_LEFT; + } + break; + + case CALPHASE_LOWER_LEFT: + { + // A touch has been received while in the CALPHASE_LOWER_LEFT state. + // Save the touch data and set up the next calibration display + +#ifdef CONFIG_TWM4NX_CALIBRATION_AVERAGE + m_calibData[CALIB_LOWER_LEFT_INDEX].x = average.x; + m_calibData[CALIB_LOWER_LEFT_INDEX].y = average.y; +#else + m_calibData[CALIB_LOWER_LEFT_INDEX].x = m_touchPos.x; + m_calibData[CALIB_LOWER_LEFT_INDEX].y = m_touchPos.y; +#endif + + // Clear the previous screen by re-drawing it using the background + // color. That is much faster than clearing the whole display + + m_screenInfo.lineColor = CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR; + m_screenInfo.circleFillColor = CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR; +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + m_text->setText(GTouchMsg); +#endif + showCalibration(); + + // Inform any waiter that calibration is complete + + m_calphase = CALPHASE_COMPLETE; + } + break; + + case CALPHASE_COMPLETE: + // Might happen... do nothing if it does + break; + } + + twminfo("New m_calphase=%d Screen x: %d y: %d\n", + m_calphase, m_screenInfo.pos.x, m_screenInfo.pos.y); +} + +/** + * Presents the next calibration screen + * + * @param screenInfo Describes the next calibration screen + */ + +void CCalibration::showCalibration(void) +{ + // Get the widget control associated with the full screen window + + NXWidgets::CWidgetControl *control = m_nxWin->getWidgetControl(); + + // Get the CCGraphicsPort instance for this window + + NXWidgets::CGraphicsPort *port = control->getGraphicsPort(); + + // Get the size of the fullscreen window + + struct nxgl_size_s windowSize; + if (!m_nxWin->getSize(&windowSize)) + { + return; + } + + // Draw the circle at the center of the touch position + + port->drawFilledCircle(&m_screenInfo.pos, CALIBRATION_CIRCLE_RADIUS, + m_screenInfo.circleFillColor); + + // Draw horizontal line + + port->drawFilledRect(0, m_screenInfo.pos.y, windowSize.w, CALIBRATION_LINE_THICKNESS, + m_screenInfo.lineColor); + + // Draw vertical line + + port->drawFilledRect(m_screenInfo.pos.x, 0, CALIBRATION_LINE_THICKNESS, windowSize.h, + m_screenInfo.lineColor); + + // Show the touchscreen message + +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + m_text->enableDrawing(); + m_text->redraw(); + m_text->disableDrawing(); +#endif +} + +/** + * Finish calibration steps and provide the calibration data to the + * touchscreen driver. + */ + +void CCalibration::finishCalibration(void) +{ + // Hide the window + + m_nxWin->hide(); + + // Did we finish calibration successfully? + + if (m_calphase == CALPHASE_COMPLETE) + { + // Yes... Get the final Calibration data + + struct SCalibrationData caldata; + if (createCalibrationData(caldata)) + { +#ifdef CONFIG_TWM4NX_TOUCHSCREEN_CONFIGDATA + // Save the new calibration data. The saved calibration + // data may be used to avoided recalibrating in the future. + + int ret = platform_setconfig(CONFIGDATA_TSCALIBRATION, 0, + (FAR const uint8_t *)&caldata, + sizeof(struct SCalibrationData)); + if (ret != 0) + { + gerr("ERROR: Failed to save calibration data\n"); + } +#endif + // And provide the calibration data to CInput, enabling + // touchscreen processing + + FAR CInput *cinput = m_twm4nx->getInput(); + + cinput->setCalibrationData(caldata); + cinput->enableCalibration(true); + } + } + + // And set the terminated stated + + m_calthread = CALTHREAD_TERMINATED; +} + +/** + * Stop the application. + */ + +void CCalibration::stop(void) +{ + ginfo("Stopping calibration: m_calthread=%d\n", (int)m_calthread); + + // Was the calibration thread created? + + if (m_thread != 0) + { + // Is the calibration thread running? + + if (m_calthread == CALTHREAD_RUNNING) + { + // The main thread is stuck waiting for the next touchscreen input... + // We can signal that we would like the thread to stop, but we will be + // stuck here until the next touch + + m_calthread = CALTHREAD_STOPREQUESTED; + + // Try to wake up the calibration thread so that it will see our + // termination request + + ginfo("Stopping calibration: m_calthread=%d\n", (int)m_calthread); + (void)pthread_kill(m_thread, CONFIG_TWM4NX_CALIBRATION_SIGNO); + + // Wait for the calibration thread to exit + + FAR pthread_addr_t value; + (void)pthread_join(m_thread, &value); + } + } +} + +/** + * Destroy the application and free all of its resources. This method + * will initiate blocking of messages from the NX server. The server + * will flush the window message queue and reply with the blocked + * message. When the block message is received by CWindowEvent, + * it will send the destroy message to the calibration window task which + * will, finally, safely delete the application. + */ + +void CCalibration::destroy(void) +{ +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + // Destroy widgets + + destroyWidgets(); +#endif + + // Close the calibration window... but not yet. Send the blocked message. + // The actual termination will no occur until the NX server drains all of + // the message events. We will get the EVENT_WINDOW_DELETE event at that + // point + + NXWidgets::CWidgetControl *control = m_nxWin->getWidgetControl(); + nx_block(control->getWindowHandle(), (FAR void *)m_nxWin); +} + +/** + * Given the raw touch data collected by the calibration thread, create the + * massaged calibration data needed by CTouchscreen. + * + * @param data. A reference to the location to save the calibration data + * @return True if the calibration data was successfully created. + */ + +bool CCalibration::createCalibrationData(struct SCalibrationData &data) +{ + // Get the size of the fullscreen window + + struct nxgl_size_s windowSize; + if (!m_nxWin->getSize(&windowSize)) + { + gerr("ERROR: NXWidgets::INxWindow::getSize failed\n"); + return false; + } + +#ifdef CONFIG_TWM4NX_CALIBRATION_ANISOTROPIC + // X lines: + // + // x2 = slope*y1 + offset + // + // slope = (bottomY - topY) / (bottomX - topX) + // offset = (topY - topX * slope) + + float topX = (float)m_calibData[CALIB_UPPER_LEFT_INDEX].x; + float bottomX = (float)m_calibData[CALIB_LOWER_LEFT_INDEX].x; + + float topY = (float)m_calibData[CALIB_UPPER_LEFT_INDEX].y; + float bottomY = (float)m_calibData[CALIB_LOWER_LEFT_INDEX].y; + + data.left.slope = (bottomX - topX) / (bottomY - topY); + data.left.offset = topX - topY * data.left.slope; + + twminfo("Left slope: %6.2f offset: %6.2f\n", data.left.slope, data.left.offset); + + topX = (float)m_calibData[CALIB_UPPER_RIGHT_INDEX].x; + bottomX = (float)m_calibData[CALIB_LOWER_RIGHT_INDEX].x; + + topY = (float)m_calibData[CALIB_UPPER_RIGHT_INDEX].y; + bottomY = (float)m_calibData[CALIB_LOWER_RIGHT_INDEX].y; + + data.right.slope = (bottomX - topX) / (bottomY - topY); + data.right.offset = topX - topY * data.right.slope; + + twminfo("Right slope: %6.2f offset: %6.2f\n", data.right.slope, data.right.offset); + + // Y lines: + // + // y2 = slope*x1 + offset + // + // slope = (rightX - topX) / (rightY - leftY) + // offset = (topX - leftY * slope) + + float leftX = (float)m_calibData[CALIB_UPPER_LEFT_INDEX].x; + float rightX = (float)m_calibData[CALIB_UPPER_RIGHT_INDEX].x; + + float leftY = (float)m_calibData[CALIB_UPPER_LEFT_INDEX].y; + float rightY = (float)m_calibData[CALIB_UPPER_RIGHT_INDEX].y; + + data.top.slope = (rightY - leftY) / (rightX - leftX); + data.top.offset = leftY - leftX * data.top.slope; + + twminfo("Top slope: %6.2f offset: %6.2f\n", data.top.slope, data.top.offset); + + leftX = (float)m_calibData[CALIB_LOWER_LEFT_INDEX].x; + rightX = (float)m_calibData[CALIB_LOWER_RIGHT_INDEX].x; + + leftY = (float)m_calibData[CALIB_LOWER_LEFT_INDEX].y; + rightY = (float)m_calibData[CALIB_LOWER_RIGHT_INDEX].y; + + data.bottom.slope = (rightY - leftY) / (rightX - leftX); + data.bottom.offset = leftY - leftX * data.bottom.slope; + + twminfo("Bottom slope: %6.2f offset: %6.2f\n", data.bottom.slope, data.bottom.offset); + + // Save also the calibration screen positions + + data.leftX = CALIBRATION_LEFTX; + data.rightX = CALIBRATION_RIGHTX; + data.topY = CALIBRATION_TOPY; + data.bottomY = CALIBRATION_BOTTOMY; +#else + // Calculate the calibration parameters + // + // (scaledX - LEFTX) / (rawX - leftX) = (RIGHTX - LEFTX) / (rightX - leftX) + // scaledX = (rawX - leftX) * (RIGHTX - LEFTX) / (rightX - leftX) + LEFTX + // = rawX * xSlope + (LEFTX - leftX * xSlope) + // = rawX * xSlope + xOffset + // + // where: + // xSlope = (RIGHTX - LEFTX) / (rightX - leftX) + // xOffset = (LEFTX - leftX * xSlope) + + b16_t leftX = (m_calibData[CALIB_UPPER_LEFT_INDEX].x + + m_calibData[CALIB_LOWER_LEFT_INDEX].x) << 15; + b16_t rightX = (m_calibData[CALIB_UPPER_RIGHT_INDEX].x + + m_calibData[CALIB_LOWER_RIGHT_INDEX].x) << 15; + + data.xSlope = b16divb16(itob16(CALIBRATION_RIGHTX - CALIBRATION_LEFTX), (rightX - leftX)); + data.xOffset = itob16(CALIBRATION_LEFTX) - b16mulb16(leftX, data.xSlope); + + twminfo("New xSlope: %08x xOffset: %08x\n", data.xSlope, data.xOffset); + + // Similarly for Y + // + // (scaledY - TOPY) / (rawY - topY) = (BOTTOMY - TOPY) / (bottomY - topY) + // scaledY = (rawY - topY) * (BOTTOMY - TOPY) / (bottomY - topY) + TOPY + // = rawY * ySlope + (TOPY - topY * ySlope) + // = rawY * ySlope + yOffset + // + // where: + // ySlope = (BOTTOMY - TOPY) / (bottomY - topY) + // yOffset = (TOPY - topY * ySlope) + + b16_t topY = (m_calibData[CALIB_UPPER_LEFT_INDEX].y + + m_calibData[CALIB_UPPER_RIGHT_INDEX].y) << 15; + b16_t bottomY = (m_calibData[CALIB_LOWER_LEFT_INDEX].y + + m_calibData[CALIB_LOWER_RIGHT_INDEX].y) << 15; + + data.ySlope = b16divb16(itob16(CALIBRATION_BOTTOMY - CALIBRATION_TOPY), (bottomY - topY)); + data.yOffset = itob16(CALIBRATION_TOPY) - b16mulb16(topY, data.ySlope); + + twminfo("New ySlope: %08x yOffset: %08x\n", data.ySlope, data.yOffset); +#endif + + return true; +} + +///////////////////////////////////////////////////////////////////////////// +// CCalibrationFactory Method Implementations +///////////////////////////////////////////////////////////////////////////// + +/** + * CCalibrationFactory Initializer. Performs parts of the instance + * construction that may fail. In this implementation, it will + * initialize the NSH library and register an menu item in the + * Main Menu. + */ + +bool CCalibrationFactory::initialize(FAR CTwm4Nx *twm4nx) +{ + // Save the session instance + + m_twm4nx = twm4nx; + + // Register an entry with the Main menu. When selected, this will + // create a new instance of the touchscreen calibration. + + FAR CMainMenu *cmain = twm4nx->getMainMenu(); + return cmain->addApplication(this); +} + +/** + * Handle CCalibrationFactory events. This overrides a method from + * CTwm4NXEvent + * + * @param eventmsg. The received NxWidget WINDOW event message. + * @return True if the message was properly handled. false is + * return on any failure. + */ + +bool CCalibrationFactory::event(FAR struct SEventMsg *eventmsg) +{ + bool success = true; + + switch (eventmsg->eventID) + { + case EVENT_CALIB_START: // Main menu selection + startFunction(); // Create a new CCalibration instance + break; + + default: + success = false; + break; + } + + return success; +} + +/** + * Create and start a new instance of CCalibration. + */ + +bool CCalibrationFactory::startFunction(void) +{ + // Instantiate the Nxterm application, providing only the session session + // instance to the constructor + + CCalibration *calib = new CCalibration(m_twm4nx); + if (!calib) + { + twmerr("ERROR: Failed to instantiate CCalibration\n"); + return false; + } + + // Initialize the Calibration application + + if (!calib->initialize()) + { + twmerr("ERROR: Failed to initialize CCalibration instance\n"); + delete calib; + return false; + } + + // Start the Calibration application instance + + if (!calib->run()) + { + twmerr("ERROR: Failed to start the Calibration application\n"); + delete calib; + return false; + } + + return true; +} diff --git a/graphics/twm4nx/src/cnxterm.cxx b/graphics/twm4nx/apps/cnxterm.cxx similarity index 98% rename from graphics/twm4nx/src/cnxterm.cxx rename to graphics/twm4nx/apps/cnxterm.cxx index b4aca9cef..0321a7baf 100644 --- a/graphics/twm4nx/src/cnxterm.cxx +++ b/graphics/twm4nx/apps/cnxterm.cxx @@ -57,12 +57,13 @@ #include "graphics/nxglyphs.hxx" #include "graphics/twm4nx/twm4nx_config.hxx" -#include "graphics/twm4nx/nxterm_config.hxx" #include "graphics/twm4nx/ctwm4nx.hxx" #include "graphics/twm4nx/cwindow.hxx" #include "graphics/twm4nx/cwindowfactory.hxx" #include "graphics/twm4nx/cmainmenu.hxx" -#include "graphics/twm4nx/cnxterm.hxx" + +#include "graphics/twm4nx/apps/nxterm_config.hxx" +#include "graphics/twm4nx/apps/cnxterm.hxx" ///////////////////////////////////////////////////////////////////////////// // Pre-Processor Definitions @@ -205,6 +206,7 @@ bool CNxTerm::initialize(void) events.mouseEvent = EVENT_NXTERM_XYINPUT; events.kbdEvent = EVENT_NXTERM_KBDINPUT; events.closeEvent = EVENT_NXTERM_CLOSE; + events.deleteEvent = EVENT_NXTERM_DELETE; bool success = m_nxtermWindow->configureEvents(events); if (!success) @@ -573,7 +575,7 @@ void CNxTerm::resize(void) /** * CNxTermFactory Initializer. Performs parts of the instance - * construction that may fail. In this implemenation, it will + * construction that may fail. In this implementation, it will * initialize the NSH library and register an menu item in the * Main Menu. */ @@ -634,7 +636,7 @@ bool CNxTermFactory::nshlibInitialize(void) } /** - * Handle Twm4Nx factory events. This overrides a method from + * Handle CNxTermFactory events. This overrides a method from * CTwm4NXEvent * * @param eventmsg. The received NxWidget WINDOW event message. @@ -648,7 +650,7 @@ bool CNxTermFactory::event(FAR struct SEventMsg *eventmsg) switch (eventmsg->eventID) { - case EVENT_NXTERM_START: // Redraw event (should not happen) + case EVENT_NXTERM_START: // Main menu selection startFunction(); // Create a new NxTerm instance break; diff --git a/graphics/twm4nx/src/cbackground.cxx b/graphics/twm4nx/src/cbackground.cxx index c14c0fa88..340c951be 100644 --- a/graphics/twm4nx/src/cbackground.cxx +++ b/graphics/twm4nx/src/cbackground.cxx @@ -370,9 +370,10 @@ bool CBackground::createBackgroundWindow(void) events.mouseEvent = EVENT_BACKGROUND_XYINPUT; events.kbdEvent = EVENT_SYSTEM_NOP; events.closeEvent = EVENT_SYSTEM_NOP; + events.deleteEvent = EVENT_WINDOW_DELETE; FAR CWindowEvent *control = - new CWindowEvent(m_twm4nx, (FAR CWindow *)0, events); + new CWindowEvent(m_twm4nx, (FAR void *)0, events); // Create the background window (CTwm4Nx inherits from CNxServer) diff --git a/graphics/twm4nx/src/ciconmgr.cxx b/graphics/twm4nx/src/ciconmgr.cxx index 57cecbc28..ac2e6a25c 100644 --- a/graphics/twm4nx/src/ciconmgr.cxx +++ b/graphics/twm4nx/src/ciconmgr.cxx @@ -540,6 +540,7 @@ bool CIconMgr::createIconManagerWindow(FAR const char *prefix) 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) diff --git a/graphics/twm4nx/src/cinput.cxx b/graphics/twm4nx/src/cinput.cxx index c54f20588..52fedf064 100644 --- a/graphics/twm4nx/src/cinput.cxx +++ b/graphics/twm4nx/src/cinput.cxx @@ -157,29 +157,6 @@ CInput::~CInput(void) #endif } -#ifdef CONFIG_TWM4NX_TOUCHSCREEN -/** - * Provide touchscreen calibration data. If calibration data is received (and - * the touchscreen is enabled), then received touchscreen data will be scaled - * using the calibration data and forward to the NX layer which dispatches the - * touchscreen events in window-relative positions to the correct NX window. - * - * @param caldata. A reference to the touchscreen data. - */ - -void CInput::setCalibrationData(const struct SCalibrationData &caldata) -{ - // Save a copy of the calibration data - - m_calData = caldata; - - // Note that we have calibration data. Data will now be scaled before being - // forwarded to NX - - m_calib = true; -} -#endif - /** * Start the keyboard listener thread. * diff --git a/graphics/twm4nx/src/cmenus.cxx b/graphics/twm4nx/src/cmenus.cxx index 8a285f93a..3bc51cccf 100644 --- a/graphics/twm4nx/src/cmenus.cxx +++ b/graphics/twm4nx/src/cmenus.cxx @@ -572,6 +572,7 @@ bool CMenus::createMenuWindow(void) events.mouseEvent = EVENT_MENU_XYINPUT; events.kbdEvent = EVENT_SYSTEM_NOP; events.closeEvent = EVENT_SYSTEM_NOP; + events.deleteEvent = EVENT_WINDOW_DELETE; bool success = m_menuWindow->configureEvents(events); if (!success) diff --git a/graphics/twm4nx/src/cresize.cxx b/graphics/twm4nx/src/cresize.cxx index 7fab44371..bb8de2400 100644 --- a/graphics/twm4nx/src/cresize.cxx +++ b/graphics/twm4nx/src/cresize.cxx @@ -271,9 +271,10 @@ bool CResize::createSizeWindow(void) events.mouseEvent = EVENT_RESIZE_XYINPUT; events.kbdEvent = EVENT_SYSTEM_NOP; events.closeEvent = EVENT_SYSTEM_NOP; + events.deleteEvent = EVENT_WINDOW_DELETE; FAR CWindowEvent *control = - new CWindowEvent(m_twm4nx, (FAR CWindow *)0, events); + new CWindowEvent(m_twm4nx, (FAR void *)0, events); // 4. Create the main window diff --git a/graphics/twm4nx/src/ctwm4nx.cxx b/graphics/twm4nx/src/ctwm4nx.cxx index 3830e16e3..e918d83cb 100644 --- a/graphics/twm4nx/src/ctwm4nx.cxx +++ b/graphics/twm4nx/src/ctwm4nx.cxx @@ -80,10 +80,6 @@ #include "graphics/twm4nx/cfonts.hxx" #include "graphics/twm4nx/twm4nx_events.hxx" -// Applications - -#include "graphics/twm4nx/cnxterm.hxx" - ///////////////////////////////////////////////////////////////////////////// // Public Data ///////////////////////////////////////////////////////////////////////////// diff --git a/graphics/twm4nx/src/cwindow.cxx b/graphics/twm4nx/src/cwindow.cxx index d0e51cc71..6e13f0ce0 100644 --- a/graphics/twm4nx/src/cwindow.cxx +++ b/graphics/twm4nx/src/cwindow.cxx @@ -152,6 +152,7 @@ CWindow::CWindow(CTwm4Nx *twm4nx) m_appEvents.mouseEvent = EVENT_SYSTEM_NOP; // Mouse/touchscreen event ID m_appEvents.kbdEvent = EVENT_SYSTEM_NOP; // Keyboard event ID m_appEvents.closeEvent = EVENT_SYSTEM_NOP; // Window close event ID + m_appEvents.deleteEvent = EVENT_SYSTEM_NOP; // Window delete event ID // Toolbar @@ -393,7 +394,8 @@ bool CWindow::configureEvents(FAR const struct SAppEvents &events) m_appEvents.resizeEvent = events.resizeEvent; // Resize event ID m_appEvents.mouseEvent = events.mouseEvent; // Mouse/touchscreen event ID m_appEvents.kbdEvent = events.kbdEvent; // Keyboard event ID - m_appEvents.closeEvent = events.closeEvent; // Window event ID + m_appEvents.closeEvent = events.closeEvent; // Window close event ID + m_appEvents.deleteEvent = events.deleteEvent; // Window delete event ID return m_windowEvent->configureEvents(events); } @@ -824,7 +826,7 @@ bool CWindow::createMainWindow(FAR const nxgl_size_s *winsize, // Setup the the CWindowEvent instance to use our inherited drag event // handler - m_windowEvent = new CWindowEvent(m_twm4nx, this, m_appEvents); + m_windowEvent = new CWindowEvent(m_twm4nx, (FAR void *)this, m_appEvents); m_windowEvent->installEventTap(this, (uintptr_t)1); // 4. Create the window. Handling provided flags. NOTE: that menu windows @@ -929,8 +931,10 @@ bool CWindow::createToolbar(void) 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, this, events); + FAR CWindowEvent *control = new CWindowEvent(m_twm4nx, (FAR void *)this, + events); control->installEventTap(this, (uintptr_t)0); // 3. Get the toolbar sub-window from the framed window @@ -1664,6 +1668,7 @@ bool CWindow::toolbarGrab(FAR struct SEventMsg *eventmsg) 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) diff --git a/graphics/twm4nx/src/cwindowevent.cxx b/graphics/twm4nx/src/cwindowevent.cxx index ae4157982..b7cc69300 100644 --- a/graphics/twm4nx/src/cwindowevent.cxx +++ b/graphics/twm4nx/src/cwindowevent.cxx @@ -102,7 +102,7 @@ using namespace Twm4Nx; * values stored in the defaultCWidgetStyle object. */ -CWindowEvent::CWindowEvent(FAR CTwm4Nx *twm4nx, FAR CWindow *client, +CWindowEvent::CWindowEvent(FAR CTwm4Nx *twm4nx, FAR void *client, FAR const struct SAppEvents &events, FAR const NXWidgets::CWidgetStyle *style) : NXWidgets::CWidgetControl(style) @@ -117,6 +117,7 @@ CWindowEvent::CWindowEvent(FAR CTwm4Nx *twm4nx, FAR CWindow *client, m_appEvents.mouseEvent = events.mouseEvent; // Mouse/touchscreen event ID m_appEvents.kbdEvent = events.kbdEvent; // Keyboard event ID m_appEvents.closeEvent = events.closeEvent; // Window close event ID + m_appEvents.deleteEvent = events.deleteEvent; // Window delete event ID // Dragging @@ -175,8 +176,8 @@ void CWindowEvent::handleRedrawEvent(FAR const nxgl_rect_s *nxRect, { struct SRedrawEventMsg msg; msg.eventID = m_appEvents.redrawEvent; - msg.obj = m_appEvents.eventObj; - msg.handler = m_appEvents.eventObj; + msg.obj = m_appEvents.eventObj; // For CWindow events + msg.handler = m_appEvents.eventObj; // For external applications msg.rect.pt1.x = nxRect->pt1.x; msg.rect.pt1.y = nxRect->pt1.y; msg.rect.pt2.x = nxRect->pt2.x; @@ -303,8 +304,8 @@ void CWindowEvent::handleMouseEvent(FAR const struct nxgl_point_s *pos, struct SXyInputEventMsg msg; msg.eventID = m_appEvents.mouseEvent; - msg.obj = m_appEvents.eventObj; - msg.handler = m_appEvents.eventObj; + msg.obj = m_appEvents.eventObj; // For CWindow events + msg.handler = m_appEvents.eventObj; // For external applications msg.pos.x = pos->x; msg.pos.y = pos->y; msg.buttons = buttons; @@ -336,8 +337,8 @@ void CWindowEvent::handleKeyboardEvent(void) struct SNxEventMsg msg; msg.eventID = m_appEvents.kbdEvent; - msg.obj = m_appEvents.eventObj; - msg.handler = m_appEvents.eventObj; + msg.obj = m_appEvents.eventObj; // For CWindow events + msg.handler = m_appEvents.eventObj; // For external applications msg.instance = this; int ret = mq_send(m_eventq, (FAR const char *)&msg, @@ -369,8 +370,9 @@ void CWindowEvent::handleBlockedEvent(FAR void *arg) twminfo("Blocked...\n"); struct SNxEventMsg msg; - msg.eventID = EVENT_WINDOW_DELETE; - msg.obj = m_clientWindow; + msg.eventID = m_appEvents.deleteEvent; + msg.obj = m_clientWindow; // For CWindow events + msg.handler = m_appEvents.eventObj; // For external applications msg.instance = this; int ret = mq_send(m_eventq, (FAR const char *)&msg, diff --git a/graphics/twm4nx/src/twm4nx_main.cxx b/graphics/twm4nx/src/twm4nx_main.cxx index d872a3a41..48860dd41 100644 --- a/graphics/twm4nx/src/twm4nx_main.cxx +++ b/graphics/twm4nx/src/twm4nx_main.cxx @@ -51,7 +51,11 @@ #include "graphics/twm4nx/twm4nx_config.hxx" #include "graphics/twm4nx/ctwm4nx.hxx" -#include "graphics/twm4nx/cnxterm.hxx" + +// Applications + +#include "graphics/twm4nx/apps/ccalibration.hxx" +#include "graphics/twm4nx/apps/cnxterm.hxx" ///////////////////////////////////////////////////////////////////////////// // Public Function Prototypes @@ -169,13 +173,23 @@ int twm4nx_main(int argc, char *argv[]) } // Twm4Nx is fully initialized and we may now register applications - // Revisit. This is currently hardward coded here for testing. There + // Revisit. This is currently hard-coded here for testing. There // needs to be a more flexible method if adding applications at run // time. +#ifdef CONFIG_TWM4NX_CALIBRATION + CCalibrationFactory calibFactory; + success = calibFactory.initialize(twm4nx); + if (!success) + { + twmerr(" ERROR: Failed to initialize CNxTermFactory\n"); + return EXIT_FAILURE; + } +#endif + #ifdef CONFIG_TWM4NX_NXTERM - CNxTermFactory factory; - success = factory.initialize(twm4nx); + CNxTermFactory nxtermFactory; + success = nxtermFactory.initialize(twm4nx); if (!success) { twmerr(" ERROR: Failed to initialize CNxTermFactory\n"); diff --git a/include/graphics/twm4nx/apps/calib_config.hxx b/include/graphics/twm4nx/apps/calib_config.hxx new file mode 100644 index 000000000..031658946 --- /dev/null +++ b/include/graphics/twm4nx/apps/calib_config.hxx @@ -0,0 +1,180 @@ +///////////////////////////////////////////////////////////////////////////// +// apps/include/graphics/twm4nx/apps/calib_config.hxx +// Calibration configuration settings +// +// Copyright (C) 2019 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt +// +// 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. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CALIB_CONFIG_HXX +#define __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CALIB_CONFIG_HXX + +///////////////////////////////////////////////////////////////////////////// +// Included Files +///////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "graphics/nxwidgets/nxconfig.hxx" +#include "graphics/twm4nx/twm4nx_config.hxx" + +#ifdef CONFIG_TWM4NX_CALIBRATION + +///////////////////////////////////////////////////////////////////////////// +// Pre-Processor Definitions +///////////////////////////////////////////////////////////////////////////// + +// General Configuration //////////////////////////////////////////////////// + +/** + * Required settings: + * + * CONFIG_HAVE_CXX : C++ support is required + * CONFIG_NX : NX must enabled + */ + +#ifndef CONFIG_HAVE_CXX +# error C++ support is required (CONFIG_HAVE_CXX) +#endif + +#ifndef CONFIG_NX +# error NX support is required (CONFIG_NX) +#endif + +// Calibration Window /////////////////////////////////////////////////////// + +/** + * Calibration display settings: + * + * CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR - The background color of the + * touchscreen calibration display. Default: Same as + * CONFIG_TWM4NX_DEFAULT_BACKGROUNDCOLOR + * CONFIG_TWM4NX_CALIBRATION_LINECOLOR - The color of the lines used in the + * touchscreen calibration display. Default: MKRGB(0, 0, 128) (dark blue) + * CONFIG_TWM4NX_CALIBRATION_CIRCLECOLOR - The color of the circle in the + * touchscreen calibration display. Default: MKRGB(255, 255, 255) (white) + * CONFIG_TWM4NX_CALIBRATION_TOUCHEDCOLOR - The color of the circle in the + * touchscreen calibration display after the touch is recorder. Default: + * MKRGB(255, 255, 96) (very light yellow) + * CONFIG_TWM4NX_CALIBRATION_FONTID - Use this default NxWidgets font ID + * instead of the system font ID (NXFONT_DEFAULT). + * CONFIG_TWM4NX_CALIBRATION_ICON - The ICON to use for the touchscreen + * calibration application. Default: NXWidgets::g_calibrationBitmap + * CONFIG_TWM4NX_CALIBRATION_SIGNO - The real-time signal used to wake up the + * touchscreen calibration thread. Default: 5 + * CONFIG_TWM4NX_CALIBRATION_LISTENERPRIO - Priority of the calibration + * listener thread. Default: SCHED_PRIORITY_DEFAULT + * CONFIG_TWM4NX_CALIBRATION_LISTENERSTACK - Calibration listener thread + * stack size. Default 2048 + * CONFIG_TWM4NX_CALIBRATION_MARGIN + * The Calibration display consists of a target press offset from the edges + * of the display by this number of pixels (in the horizontal direction) + * or rows (in the vertical). The closer that you can comfortably + * position the press positions to the edge, the more accurate will be the + * linear interpolation (provide that the hardware provides equally good + * measurements near the edges). + */ + +#ifndef CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR +# define CONFIG_TWM4NX_CALIBRATION_BACKGROUNDCOLOR \ + CONFIG_TWM4NX_DEFAULT_BACKGROUNDCOLOR +#endif + +#ifndef CONFIG_TWM4NX_CALIBRATION_LINECOLOR +# define CONFIG_TWM4NX_CALIBRATION_LINECOLOR MKRGB(0, 0, 128) +#endif + +#ifndef CONFIG_TWM4NX_CALIBRATION_CIRCLECOLOR +# define CONFIG_TWM4NX_CALIBRATION_CIRCLECOLOR MKRGB(255, 255, 255) +#endif + +#ifndef CONFIG_TWM4NX_CALIBRATION_TOUCHEDCOLOR +# define CONFIG_TWM4NX_CALIBRATION_TOUCHEDCOLOR MKRGB(255, 255, 96) +#endif + +#ifndef CONFIG_TWM4NX_CALIBRATION_FONTID +# define CONFIG_TWM4NX_CALIBRATION_FONTID NXFONT_DEFAULT +#endif + +#ifndef CONFIG_TWM4NX_CALIBRATION_ICON +# define CONFIG_TWM4NX_CALIBRATION_ICON NXWidgets::g_calibrationBitmap +#endif + +#ifndef CONFIG_TWM4NX_CALIBRATION_SIGNO +# define CONFIG_TWM4NX_CALIBRATION_SIGNO 5 +#endif + +#ifndef CONFIG_TWM4NX_CALIBRATION_LISTENERPRIO +# define CONFIG_TWM4NX_CALIBRATION_LISTENERPRIO SCHED_PRIORITY_DEFAULT +#endif + +#ifndef CONFIG_TWM4NX_CALIBRATION_LISTENERSTACK +# define CONFIG_TWM4NX_CALIBRATION_LISTENERSTACK 2048 +#endif + +#ifndef CONFIG_TWM4NX_CALIBRATION_MARGIN +# define CONFIG_TWM4NX_CALIBRATION_MARGIN 40 +#endif + +// Calibration sample averaging + +#ifndef CONFIG_TWM4NX_CALIBRATION_AVERAGE +# undef CONFIG_TWM4NX_CALIBRATION_AVERAGE +# undef CONFIG_TWM4NX_CALIBRATION_NSAMPLES +# define CONFIG_TWM4NX_CALIBRATION_NSAMPLES 1 +# undef CONFIG_TWM4NX_CALIBRATION_DISCARD_MINMAX +#endif + +#if !defined(CONFIG_TWM4NX_CALIBRATION_NSAMPLES) || \ + CONFIG_TWM4NX_CALIBRATION_NSAMPLES < 2 +# undef CONFIG_TWM4NX_CALIBRATION_AVERAGE +# undef CONFIG_TWM4NX_CALIBRATION_NSAMPLES +# define CONFIG_TWM4NX_CALIBRATION_NSAMPLES 1 +# undef CONFIG_TWM4NX_CALIBRATION_DISCARD_MINMAX +#endif + +#if CONFIG_TWM4NX_CALIBRATION_NSAMPLES < 3 +# undef CONFIG_TWM4NX_CALIBRATION_DISCARD_MINMAX +#endif + +#if CONFIG_TWM4NX_CALIBRATION_NSAMPLES > 255 +# define CONFIG_TWM4NX_CALIBRATION_NSAMPLES 255 +#endif + +#ifdef CONFIG_TWM4NX_CALIBRATION_DISCARD_MINMAX +# define TWM4NX_CALIBRATION_NAVERAGE (CONFIG_TWM4NX_CALIBRATION_NSAMPLES - 2) +#else +# define TWM4NX_CALIBRATION_NAVERAGE CONFIG_TWM4NX_CALIBRATION_NSAMPLES +#endif + +#endif // CONFIG_TWM4NX_CALIBRATION +#endif // __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CALIB_CONFIG_HXX diff --git a/include/graphics/twm4nx/apps/ccalibration.hxx b/include/graphics/twm4nx/apps/ccalibration.hxx new file mode 100644 index 000000000..e48e72435 --- /dev/null +++ b/include/graphics/twm4nx/apps/ccalibration.hxx @@ -0,0 +1,432 @@ +///////////////////////////////////////////////////////////////////////////// +// apps/include/graphics/twm4nx/apps/ccalibration.hxx +// Perform Touchscreen Calibration +// +// Copyright (C) 2019 Gregory Nutt. All rights reserved. +// Author: Gregory Nutt +// +// 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. +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CCALIBRATION_HXX +#define __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CCALIBRATION_HXX + +///////////////////////////////////////////////////////////////////////////// +// Included Files +///////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include +#include + +#include "graphics/nxwidgets/cnxstring.hxx" +#include "graphics/nxwidgets/cwidgeteventhandler.hxx" +#include "graphics/nxwidgets/cwidgetcontrol.hxx" +#include "graphics/nxwidgets/clabel.hxx" +#include "graphics/nxwidgets/cnxfont.hxx" + +#include "graphics/twm4nx/ctwm4nx.hxx" +#include "graphics/twm4nx/ctwm4nxevent.hxx" +#include "graphics/twm4nx/twm4nx_events.hxx" +#include "graphics/twm4nx/iapplication.hxx" +#include "graphics/twm4nx/cinput.hxx" + +///////////////////////////////////////////////////////////////////////////// +// Pre-processor Definitions +///////////////////////////////////////////////////////////////////////////// + +// CNxTerm application events +// Window Events + +#define EVENT_CALIB_REDRAW EVENT_SYSTEM_NOP +#define EVENT_CALIB_RESIZE EVENT_SYSTEM_NOP +#define EVENT_CALIB_XYINPUT (EVENT_RECIPIENT_APP | 0x0000) +#define EVENT_CALIB_KBDINPUT EVENT_SYSTEM_NOP +#define EVENT_CALIB_DELETE (EVENT_RECIPIENT_APP | 0x0001) + +// Button events (there are no buttons) + +#define EVENT_CALIB_CLOSE EVENT_SYSTEM_NOP + +// Menu Events + +#define EVENT_CALIB_START (EVENT_RECIPIENT_APP | 0x0002) + +// Calibration indices + +#define CALIB_UPPER_LEFT_INDEX 0 +#define CALIB_UPPER_RIGHT_INDEX 1 +#define CALIB_LOWER_RIGHT_INDEX 2 +#define CALIB_LOWER_LEFT_INDEX 3 + +#define CALIB_DATA_POINTS 4 + +///////////////////////////////////////////////////////////////////////////// +// Implementation Classes +///////////////////////////////////////////////////////////////////////////// + +namespace Twm4Nx +{ + class CTwm4Nx; // Forward reference + + /** + * The CCalibration class provides the the calibration window and obtains + * calibration data. + */ + + class CCalibration : public CTwm4NxEvent + { + private: + // The state of the calibration thread. + + enum ECalThreadState + { + CALTHREAD_NOTRUNNING = 0, /**< The calibration thread has not yet been started */ + CALTHREAD_STARTED, /**< The calibration thread has been started, but is not yet running */ + CALTHREAD_RUNNING, /**< The calibration thread is running normally */ + CALTHREAD_STOPREQUESTED, /**< The calibration thread has been requested to stop */ + CALTHREAD_TERMINATED /**< The calibration thread terminated normally */ + }; + + // Identifies the current display state + + enum ECalibrationPhase + { + CALPHASE_NOT_STARTED = 0, /**< Constructed, but not yet started */ + CALPHASE_UPPER_LEFT, /**< Touch point is in the upper left corner */ + CALPHASE_UPPER_RIGHT, /**< Touch point is in the upper right corner */ + CALPHASE_LOWER_RIGHT, /**< Touch point is in the lower left corner */ + CALPHASE_LOWER_LEFT, /**< Touch point is in the lower right corner */ + CALPHASE_COMPLETE /**< Calibration is complete */ + }; + + // Describes one touchscreen sample. CInput treats mouse and touchscreen + // input the same so this reflects the mousey nature of the object. + + struct STouchSample + { + bool valid; /**< True: Sample is valid */ + uint8_t buttons; /**< Left button reflects touch state */ + struct nxgl_point_s pos; /**< True: Touch position */ + }; + + // Characterizes one calibration screen + + struct SCalibScreenInfo + { + struct nxgl_point_s pos; /**< The position of the touch point */ + nxgl_mxpixel_t lineColor; /**< The color of the cross-hair lines */ + nxgl_mxpixel_t circleFillColor; /**< The color of the circle */ + }; + + // CCalibration state data + + FAR CTwm4Nx *m_twm4nx; /**< Twm4Nx session instance */ + FAR NXWidgets::CNxWindow *m_nxWin; /**< The window for the calibration display */ +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + FAR NXWidgets::CLabel *m_text; /**< Calibration message */ + FAR NXWidgets::CNxFont *m_font; /**< The font used in the message */ +#endif + pthread_t m_thread; /**< The calibration thread ID */ + sem_t m_synchSem; /**< Synchronize calibration thread with events */ + sem_t m_exclSem; /**< For mutually exclusive access to data */ + struct SCalibScreenInfo m_screenInfo; /**< Describes the current calibration display */ + struct nxgl_point_s m_touchPos; /**< This is the last touch position */ + volatile uint8_t m_calthread; /**< Current calibration display state (See ECalibThreadState)*/ + uint8_t m_calphase; /**< Current calibration display state (See ECalibrationPhase)*/ + bool m_stop; /**< True: We have been asked to stop the calibration */ + bool m_touched; /**< True: The screen is touched */ + struct STouchSample m_sample; /**< Catches new touch samples */ +#ifdef CONFIG_TWM4NX_CALIBRATION_AVERAGE + uint8_t m_nsamples; /**< Number of samples collected so far at this position */ + struct nxgl_point_s m_sampleData[CONFIG_TWM4NX_CALIBRATION_NSAMPLES]; +#endif + struct nxgl_point_s m_calibData[CALIB_DATA_POINTS]; + + /** + * Accept raw touchscreen input. + * + * @param sample Touchscreen input sample + */ + + void touchscreenInput(struct STouchSample &sample); + +#ifdef CONFIG_TWM4NX_CALIBRATION_MESSAGES + /** + * Create widgets need by the calibration thread. + * + * @return True if the widgets were successfully created. + */ + + bool createWidgets(void); + + /** + * Destroy widgets created for the calibration thread. + */ + + void destroyWidgets(void); +#endif + + /** + * The calibration thread. This is the entry point of a thread that provides the + * calibration displays, waits for input, and collects calibration data. + * + * @param arg. The CCalibration 'this' pointer cast to a void*. + * @return This function always returns NULL when the thread exits + */ + + static FAR void *calibration(FAR void *arg); + + /** + * Get exclusive access data shared across threads. + * + * @return True is returned if the sample data was obtained without error. + */ + + bool exclusiveAccess(void); + + /** + * Wait for touchscreen next sample data to become available. + * + * @param sample Snapshot of last touchscreen sample + * @return True is returned if the sample data was obtained without error. + */ + + bool waitTouchSample(FAR struct STouchSample &sample); + +#ifdef CONFIG_TWM4NX_CALIBRATION_AVERAGE + /** + * Accumulate and average touch sample data + * + * @param average. When the averaged data is available, return it here + * @return True: Average data is available; False: Need to collect more samples + */ + + bool averageSamples(struct nxgl_point_s &average); +#endif + + /** + * This is the calibration state machine. It is called initially and then + * as new touchscreen data is received. + */ + + void stateMachine(void); + + /** + * Presents the next calibration screen + */ + + void showCalibration(void); + + /** + * Finish calibration steps and provide the calibration data to the + * touchscreen driver. + */ + + void finishCalibration(void); + + /** + * Stop the calibration thread. + */ + + void stop(void); + + /** + * Destroy the application and free all of its resources. This method + * will initiate blocking of messages from the NX server. The server + * will flush the window message queue and reply with the blocked + * message. When the block message is received by CWindowMessenger, + * it will send the destroy message to the start window task which + * will, finally, safely delete the application. + */ + + void destroy(void); + + /** + * Given the raw touch data collected by the calibration thread, create the + * massaged calibration data needed by CTouchscreen. + * + * @param data. A reference to the location to save the calibration data + * @return True if the calibration data was successfully created. + */ + + bool createCalibrationData(struct SCalibrationData &data); + + public: + + /** + * CCalibration Constructor + * + * @param twm4nx. The Twm4Nx session instance. + */ + + CCalibration(FAR CTwm4Nx *twm4nx); + + /** + * CCalibration Destructor + */ + + ~CCalibration(void); + + /** + * CCalibration Initializer. Performs parts of the instance + * construction that may fail. This function creates the + * initial calibration display. + */ + + bool initialize(void); + + /** + * Start the application (perhaps in the minimized state). + * + * @return True if the application was successfully started. + */ + + bool run(void); + + /** + * Handle CCalibration events. This overrides a method from + * CTwm4NXEvent. + * + * @param eventmsg. The received NxWidget WINDOW event message. + * @return True if the message was properly handled. false is + * return on any failure. + */ + + bool event(FAR struct SEventMsg *eventmsg); + }; + + class CCalibrationFactory : public IApplication, + public IApplicationFactory, + public CTwm4NxEvent + { + private: + FAR CTwm4Nx *m_twm4nx; /**< Twm4Nx session instance */ + + /** + * Handle CCalibrationFactory events. This overrides a method from + * CTwm4NXEvent + * + * @param eventmsg. The received NxWidget WINDOW event message. + * @return True if the message was properly handled. false is + * return on any failure. + */ + + bool event(FAR struct SEventMsg *eventmsg); + + /** + * Create and start a new instance of an CNxTerm. + */ + + bool startFunction(void); + + /** + * Return the Main Menu item string. This overrides the method from + * IApplication + * + * @param name The name of the application. + */ + + inline NXWidgets::CNxString getName(void) + { + return NXWidgets::CNxString("Calibration"); + } + + /** + * There is no sub-menu for this Main Menu item. This overrides + * the method from IApplication. + * + * @return This implementation will always return a null value. + */ + + inline FAR CMenus *getSubMenu(void) + { + return (FAR CMenus *)0; + } + + /** + * There is no custom event handler. We use the common event handler. + * + * @return. null is always returned in this implementation. + */ + + inline FAR CTwm4NxEvent *getEventHandler(void) + { + return (FAR CTwm4NxEvent *)this; + } + + /** + * Return the Twm4Nx event that will be generated when the Main Menu + * item is selected. + * + * @return. This function always returns EVENT_SYSTEM_NOP. + */ + + inline uint16_t getEvent(void) + { + return EVENT_CALIB_START; + } + + public: + /** + * CCalibrationFactory Constructor + */ + + inline CCalibrationFactory(void) + { + m_twm4nx = (FAR CTwm4Nx *)0; + } + + /** + * CCalibrationFactory Destructor + */ + + inline ~CCalibrationFactory(void) + { + // REVISIT: Would need to remove Main Menu item + } + + /** + * CCalibrationFactory Initializer. Performs parts of the instance + * construction that may fail. In this implementation, it registers + * a menu item in the Main Menu and, optionally, bring up a + * CCalibration instance now in order calibrate unconditionally on + * start-up + * + * @param twm4nx The Twm4Nx session instance + * @return True if successfully initialized + */ + + bool initialize(FAR CTwm4Nx *twm4nx); + }; +} + +#endif // __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CCALIBRATION_HXX diff --git a/include/graphics/twm4nx/cnxterm.hxx b/include/graphics/twm4nx/apps/cnxterm.hxx similarity index 95% rename from include/graphics/twm4nx/cnxterm.hxx rename to include/graphics/twm4nx/apps/cnxterm.hxx index 8c4a03597..ce8c1366b 100644 --- a/include/graphics/twm4nx/cnxterm.hxx +++ b/include/graphics/twm4nx/apps/cnxterm.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/src/cwindow.hxx +// apps/include/graphics/twm4nx/apps/cnxterm.hxx // NxTerm window // // Copyright (C) 2019 Gregory Nutt. All rights reserved. @@ -34,8 +34,8 @@ // ///////////////////////////////////////////////////////////////////////////// -#ifndef __APPS_INCLUDE_GRAPHICS_TWM4NX_CNXTERM_HXX -#define __APPS_INCLUDE_GRAPHICS_TWM4NX_CNXTERM_HXX +#ifndef __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CNXTERM_HXX +#define __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CNXTERM_HXX ///////////////////////////////////////////////////////////////////////////// // Included Files @@ -63,6 +63,7 @@ #define EVENT_NXTERM_RESIZE (EVENT_RECIPIENT_APP | 0x0001) #define EVENT_NXTERM_XYINPUT EVENT_SYSTEM_NOP #define EVENT_NXTERM_KBDINPUT EVENT_SYSTEM_NOP +#define EVENT_NXTERM_DELETE EVENT_WINDOW_DELETE // Button Events @@ -180,7 +181,7 @@ namespace Twm4Nx bool nshlibInitialize(void); /** - * Handle Twm4Nx factory events. This overrides a method from + * Handle CNxTermFactory events. This overrides a method from * CTwm4NXEvent * * @param eventmsg. The received NxWidget WINDOW event message. @@ -276,4 +277,4 @@ namespace Twm4Nx }; } -#endif // __APPS_INCLUDE_GRAPHICS_TWM4NX_CNXTERM_HXX +#endif // __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_CNXTERM_HXX diff --git a/include/graphics/twm4nx/nxterm_config.hxx b/include/graphics/twm4nx/apps/nxterm_config.hxx similarity index 95% rename from include/graphics/twm4nx/nxterm_config.hxx rename to include/graphics/twm4nx/apps/nxterm_config.hxx index 3c762705f..91ea7b317 100644 --- a/include/graphics/twm4nx/nxterm_config.hxx +++ b/include/graphics/twm4nx/apps/nxterm_config.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/nxterm_config.hxx +// apps/include/graphics/twm4nx/apps/nxterm_config.hxx // NxTerm configuration settings // // Copyright (C) 2019 Gregory Nutt. All rights reserved. @@ -34,8 +34,8 @@ // ///////////////////////////////////////////////////////////////////////////// -#ifndef __APPS_INCLUDE_GRAPHICS_TWM4NX_NXTERM_CONFIG_HXX -#define __APPS_INCLUDE_GRAPHICS_TWM4NX_NXTERM_CONFIG_HXX +#ifndef __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_NXTERM_CONFIG_HXX +#define __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_NXTERM_CONFIG_HXX ///////////////////////////////////////////////////////////////////////////// // Included Files @@ -148,4 +148,4 @@ #endif #endif // CONFIG_TWM4NX_NXTERM -#endif // __APPS_INCLUDE_GRAPHICS_TWM4NX_NXTERM_CONFIG_HXX +#endif // __APPS_INCLUDE_GRAPHICS_TWM4NX_APPS_NXTERM_CONFIG_HXX diff --git a/include/graphics/twm4nx/cbackground.hxx b/include/graphics/twm4nx/cbackground.hxx index 3722c6cf0..2c308980f 100644 --- a/include/graphics/twm4nx/cbackground.hxx +++ b/include/graphics/twm4nx/cbackground.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/cbackground.hxx +// apps/include/graphics/twm4nx/cbackground.hxx // Manage background image // // Copyright (C) 2019 Gregory Nutt. All rights reserved. diff --git a/include/graphics/twm4nx/cfonts.hxx b/include/graphics/twm4nx/cfonts.hxx index dfbd3f862..e79ebf4d8 100644 --- a/include/graphics/twm4nx/cfonts.hxx +++ b/include/graphics/twm4nx/cfonts.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/cfonts.hxx +// apps/include/graphics/twm4nx/cfonts.hxx // Font support for twm4nx // // Copyright (C) 2019 Gregory Nutt. All rights reserved. diff --git a/include/graphics/twm4nx/ciconmgr.hxx b/include/graphics/twm4nx/ciconmgr.hxx index 1155b0366..4efe59908 100644 --- a/include/graphics/twm4nx/ciconmgr.hxx +++ b/include/graphics/twm4nx/ciconmgr.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/ciconmgr.hxx +// apps/include/graphics/twm4nx/ciconmgr.hxx // Icon Manager includes // // Copyright (C) 2019 Gregory Nutt. All rights reserved. diff --git a/include/graphics/twm4nx/cinput.hxx b/include/graphics/twm4nx/cinput.hxx index 4647edd2e..a94a58d6f 100644 --- a/include/graphics/twm4nx/cinput.hxx +++ b/include/graphics/twm4nx/cinput.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/cinput.hxx +// apps/include/graphics/twm4nx/cinput.hxx // Keyboard injection // // Copyright (C) 2019 Gregory Nutt. All rights reserved. @@ -274,15 +274,34 @@ namespace Twm4Nx #ifdef CONFIG_TWM4NX_TOUCHSCREEN /** - * Provide touchscreen calibration data. If calibration data is received (and - * the touchscreen is enabled), then received touchscreen data will be scaled - * using the calibration data and forward to the NX layer which dispatches the - * touchscreen events in window-relative positions to the correct NX window. + * Before starting re-calibration, we need to disable touchscreen + * calibration and provide raw touchscreen input. Similarly, when + * valid touchscreen calibration has been provided via + * CInput::setCalibrationData(), then touchscreen processing must + * be re-enabled via this method. + * + * @param enable True will enable calibration. + */ + + inline void enableCalibration(bool enable) + { + m_calib = enable; + } + + /** + * Provide touchscreen calibration data. If calibration data is + * received (and the touchscreen is enabled), then received + * touchscreen data will be scaled using the calibration data and + * forward to the NX layer which dispatches the touchscreen events + * in window-relative positions to the correct NX window. * * @param caldata. A reference to the touchscreen data. */ - void setCalibrationData(const struct SCalibrationData &caldata); + inline void setCalibrationData(const struct SCalibrationData &caldata) + { + m_calData = caldata; + } #endif /** diff --git a/include/graphics/twm4nx/cmainmenu.hxx b/include/graphics/twm4nx/cmainmenu.hxx index a0b373df5..558d4d531 100644 --- a/include/graphics/twm4nx/cmainmenu.hxx +++ b/include/graphics/twm4nx/cmainmenu.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/cmainmenu.hxx +// apps/include/graphics/twm4nx/cmainmenu.hxx // Twm4Nx main menu class // // Copyright (C) 2019 Gregory Nutt. All rights reserved. diff --git a/include/graphics/twm4nx/cmenus.hxx b/include/graphics/twm4nx/cmenus.hxx index bbaee1107..ff09faf4d 100644 --- a/include/graphics/twm4nx/cmenus.hxx +++ b/include/graphics/twm4nx/cmenus.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/Cmenus.hxx +// apps/include/graphics/twm4nx/Cmenus.hxx // Twm4Nx menus definitions // // Copyright (C) 2019 Gregory Nutt. All rights reserved. diff --git a/include/graphics/twm4nx/cresize.hxx b/include/graphics/twm4nx/cresize.hxx index 35d462237..1c96e953a 100644 --- a/include/graphics/twm4nx/cresize.hxx +++ b/include/graphics/twm4nx/cresize.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/cresize.hxx +// apps/include/graphics/twm4nx/cresize.hxx // Resize function externs // // Copyright (C) 2019 Gregory Nutt. All rights reserved. diff --git a/include/graphics/twm4nx/ctwm4nx.hxx b/include/graphics/twm4nx/ctwm4nx.hxx index fcacaecc8..ba96cb155 100644 --- a/include/graphics/twm4nx/ctwm4nx.hxx +++ b/include/graphics/twm4nx/ctwm4nx.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/ctwm4nx.hxx +// apps/include/graphics/twm4nx/ctwm4nx.hxx // twm include file // // Copyright (C) 2019 Gregory Nutt. All rights reserved. @@ -313,6 +313,20 @@ namespace Twm4Nx return m_resize; } +#if !defined(CONFIG_TWM4NX_NOKEYBOARD) || !defined(CONFIG_TWM4NX_NOMOUSE) + /** + * Return the session's CInput instance. + * + * @return The contained instance of the CInput instance for this + * session. + */ + + inline FAR CInput *getInput(void) + { + return m_input; + } +#endif + /** * Dispatch NxWidget-related events. Normally used only internally * but there is one use case where messages are injected here from diff --git a/include/graphics/twm4nx/ctwm4nxevent.hxx b/include/graphics/twm4nx/ctwm4nxevent.hxx index c5ddde154..445150fe6 100644 --- a/include/graphics/twm4nx/ctwm4nxevent.hxx +++ b/include/graphics/twm4nx/ctwm4nxevent.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/ctwmnxevent.hxx +// apps/include/graphics/twm4nx/ctwmnxevent.hxx // Twm4Nx Event handler base class // // Copyright (C) 2019 Gregory Nutt. All rights reserved. diff --git a/include/graphics/twm4nx/cwindow.hxx b/include/graphics/twm4nx/cwindow.hxx index f2d0001b9..cb6f2b90a 100644 --- a/include/graphics/twm4nx/cwindow.hxx +++ b/include/graphics/twm4nx/cwindow.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/cwindow.hxx +// apps/include/graphics/twm4nx/cwindow.hxx // Represents one window instance // // Copyright (C) 2019 Gregory Nutt. All rights reserved. diff --git a/include/graphics/twm4nx/cwindowevent.hxx b/include/graphics/twm4nx/cwindowevent.hxx index 347157e8b..07dc362c9 100644 --- a/include/graphics/twm4nx/cwindowevent.hxx +++ b/include/graphics/twm4nx/cwindowevent.hxx @@ -59,8 +59,6 @@ namespace Twm4Nx { - class CWindow; // Forward reference - // This structure provides information to support application events struct SAppEvents @@ -72,6 +70,7 @@ namespace Twm4Nx uint16_t mouseEvent; /**< Mouse/touchscreen event ID */ uint16_t kbdEvent; /**< Keyboard event ID */ uint16_t closeEvent; /**< Window close event ID */ + uint16_t deleteEvent; /**< Window delete event ID */ }; /** @@ -172,7 +171,7 @@ namespace Twm4Nx { private: FAR CTwm4Nx *m_twm4nx; /**< Cached instance of CTwm4Nx */ - FAR CWindow *m_clientWindow; /**< The client window instance */ + FAR void *m_clientWindow; /**< The client window instance */ mqd_t m_eventq; /**< NxWidget event message queue */ struct SAppEvents m_appEvents; /**< Application event information */ @@ -230,7 +229,7 @@ namespace Twm4Nx * values stored in the defaultCWidgetStyle object. */ - CWindowEvent(FAR CTwm4Nx *twm4nx, FAR CWindow *client, + CWindowEvent(FAR CTwm4Nx *twm4nx, FAR void *client, FAR const struct SAppEvents &events, FAR const NXWidgets::CWidgetStyle *style = (const NXWidgets::CWidgetStyle *)NULL); @@ -288,6 +287,7 @@ namespace Twm4Nx m_appEvents.mouseEvent = events.mouseEvent; // Mouse/touchscreen event ID m_appEvents.kbdEvent = events.kbdEvent; // Keyboard event ID m_appEvents.closeEvent = events.closeEvent; // Window close event ID + m_appEvents.deleteEvent = events.deleteEvent; // Window delete event ID return true; } }; diff --git a/include/graphics/twm4nx/cwindowfactory.hxx b/include/graphics/twm4nx/cwindowfactory.hxx index ddf9e037d..34aad61a4 100644 --- a/include/graphics/twm4nx/cwindowfactory.hxx +++ b/include/graphics/twm4nx/cwindowfactory.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/cwindowfactory.hxx +// apps/include/graphics/twm4nx/cwindowfactory.hxx // A collection of Window Helpers: Add a new window, put the titlebar and // other stuff around the window // diff --git a/include/graphics/twm4nx/twm4nx_config.hxx b/include/graphics/twm4nx/twm4nx_config.hxx index 21dbac736..cb2560354 100644 --- a/include/graphics/twm4nx/twm4nx_config.hxx +++ b/include/graphics/twm4nx/twm4nx_config.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/twm4nx_config.hxx +// apps/include/graphics/twm4nx/twm4nx_config.hxx // Twm4Nx configuration settings // // Copyright (C) 2019 Gregory Nutt. All rights reserved. diff --git a/include/graphics/twm4nx/twm4nx_cursor.hxx b/include/graphics/twm4nx/twm4nx_cursor.hxx index e2367be76..7795dd286 100644 --- a/include/graphics/twm4nx/twm4nx_cursor.hxx +++ b/include/graphics/twm4nx/twm4nx_cursor.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/twm4nx_cursor.hxx +// apps/include/graphics/twm4nx/twm4nx_cursor.hxx // Cursor-related definitions // // Copyright (C) 2019 Gregory Nutt. All rights reserved. @@ -34,8 +34,8 @@ // ///////////////////////////////////////////////////////////////////////////// -#ifndef __APPS_GRAPHICS_TWM4NX_INCLUDE_TWM4NX_CURSOR_HXX -#define __APPS_GRAPHICS_TWM4NX_INCLUDE_TWM4NX_CURSOR_HXX +#ifndef __APPS_INCLUDE_GRAPHICS_TWM4NX_TWM4NX_CURSOR_HXX +#define __APPS_INCLUDE_GRAPHICS_TWM4NX_TWM4NX_CURSOR_HXX ///////////////////////////////////////////////////////////////////////////// // Included Files @@ -69,4 +69,4 @@ namespace Twm4Nx ///////////////////////////////////////////////////////////////////////////// #endif // CONFIG_NX_SWCURSOR -#endif // __APPS_GRAPHICS_TWM4NX_INCLUDE_TWM4NX_CURSOR_HXX +#endif // __APPS_INCLUDE_GRAPHICS_TWM4NX_TWM4NX_CURSOR_HXX diff --git a/include/graphics/twm4nx/twm4nx_events.hxx b/include/graphics/twm4nx/twm4nx_events.hxx index c6c329a1a..30cee2bd2 100644 --- a/include/graphics/twm4nx/twm4nx_events.hxx +++ b/include/graphics/twm4nx/twm4nx_events.hxx @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// apps/graphics/twm4nx/include/twm4nx_events.hxx +// apps/include/graphics/twm4nx/twm4nx_events.hxx // Twm4Nx Widget Event Handling // // Copyright (C) 2019 Gregory Nutt. All rights reserved.