Merge pull request #717 from EdgeTX/simu-mouse
Add touch support to simulation
This commit is contained in:
@@ -515,7 +515,7 @@ class StructField: public DataField {
|
||||
return result;
|
||||
}
|
||||
|
||||
virtual int dump(int level=0, int offset=0)
|
||||
int dump(int level=0, int offset=0) override
|
||||
{
|
||||
for (int i=0; i<level; i++) printf(" ");
|
||||
printf("%s (%d bytes)\n", getName().toLatin1().constData(), size()/8);
|
||||
|
||||
@@ -443,7 +443,7 @@ class SwitchField: public ConversionField< SignedField<N> > {
|
||||
{
|
||||
}
|
||||
|
||||
virtual void beforeExport()
|
||||
void beforeExport() override
|
||||
{
|
||||
_switch = sw.toValue();
|
||||
ConversionField< SignedField<N> >::beforeExport();
|
||||
@@ -477,7 +477,7 @@ class SourceField: public ConversionField< UnsignedField<N> > {
|
||||
{
|
||||
}
|
||||
|
||||
virtual void beforeExport()
|
||||
void beforeExport() override
|
||||
{
|
||||
_source = source.toValue();
|
||||
ConversionField< UnsignedField<N> >::beforeExport();
|
||||
@@ -603,7 +603,7 @@ class CurveReferenceField: public TransformedField {
|
||||
internalField.Append(new SignedField<8>(this, _curve_value));
|
||||
}
|
||||
|
||||
virtual void beforeExport()
|
||||
void beforeExport() override
|
||||
{
|
||||
if (curve.value != 0) {
|
||||
_curve_type = (unsigned int)curve.type;
|
||||
@@ -729,7 +729,7 @@ class FlightModeField: public TransformedField {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void beforeExport()
|
||||
void beforeExport() override
|
||||
{
|
||||
for (int i=0; i<CPN_MAX_STICKS+MAX_AUX_TRIMS(board); i++) {
|
||||
if (IS_HORUS_OR_TARANIS(board) || version >= 218) {
|
||||
|
||||
@@ -28,6 +28,7 @@ set(simulation_SRCS
|
||||
trainersimu.cpp
|
||||
widgets/radiowidget.cpp
|
||||
widgets/virtualjoystickwidget.cpp
|
||||
widgets/lcdwidget.cpp
|
||||
)
|
||||
|
||||
set(simulation_UIS
|
||||
|
||||
@@ -197,6 +197,7 @@ void SimulatedUIWidget::setLcd(LcdWidget * lcd)
|
||||
m_backLight = 0;
|
||||
|
||||
m_lcd->setBackgroundColor(m_backlightColors.at(m_backLight));
|
||||
connect(m_lcd, &LcdWidget::touchEvent, m_simulator, &SimulatorInterface::touchEvent);
|
||||
}
|
||||
|
||||
void SimulatedUIWidget::connectScrollActions()
|
||||
|
||||
@@ -144,6 +144,7 @@ class SimulatorInterface : public QObject
|
||||
virtual void setTrainerInput(unsigned int inputNumber, int16_t value) = 0;
|
||||
virtual void setInputValue(int type, uint8_t index, int16_t value) = 0;
|
||||
virtual void rotaryEncoderEvent(int steps) = 0;
|
||||
virtual void touchEvent(int type, int x, int y) = 0;
|
||||
virtual void setTrainerTimeout(uint16_t ms) = 0;
|
||||
virtual void sendTelemetry(const QByteArray data) = 0;
|
||||
virtual void setLuaStateReloadPermanentScripts() = 0;
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "lcdwidget.h"
|
||||
|
||||
void LcdWidget::setData(unsigned char *buf, int width, int height, int depth)
|
||||
{
|
||||
lcdBuf = buf;
|
||||
lcdWidth = width;
|
||||
lcdHeight = height;
|
||||
lcdDepth = depth;
|
||||
if (depth >= 8)
|
||||
lcdSize = (width * height) * ((depth + 7) / 8);
|
||||
else
|
||||
lcdSize = (width * ((height + 7) / 8)) * depth;
|
||||
|
||||
localBuf = (unsigned char *)malloc(lcdSize);
|
||||
memset(localBuf, 0, lcdSize);
|
||||
}
|
||||
|
||||
void LcdWidget::setBgDefaultColor(const QColor &color)
|
||||
{
|
||||
bgDefaultColor = color;
|
||||
}
|
||||
|
||||
void LcdWidget::setBackgroundColor(const QColor &color) { bgColor = color; }
|
||||
|
||||
void LcdWidget::makeScreenshot(const QString &fileName)
|
||||
{
|
||||
int width, height;
|
||||
if (lcdDepth < 12) {
|
||||
width = 2 * lcdWidth;
|
||||
height = 2 * lcdHeight;
|
||||
} else {
|
||||
width = lcdWidth;
|
||||
height = lcdHeight;
|
||||
}
|
||||
QPixmap buffer(width, height);
|
||||
QPainter p(&buffer);
|
||||
doPaint(p);
|
||||
if (fileName.isEmpty()) {
|
||||
QApplication::clipboard()->setPixmap(buffer);
|
||||
qInfo() << "Screenshot saved to clipboard";
|
||||
} else {
|
||||
buffer.toImage().save(fileName);
|
||||
qInfo() << "Screenshot saved to:" << fileName;
|
||||
}
|
||||
}
|
||||
|
||||
void LcdWidget::onLcdChanged(bool light)
|
||||
{
|
||||
QMutexLocker locker(&lcdMtx);
|
||||
lightEnable = light;
|
||||
memcpy(localBuf, lcdBuf, lcdSize);
|
||||
if (!redrawTimer.isValid() ||
|
||||
redrawTimer.hasExpired(LCD_WIDGET_REFRESH_PERIOD)) {
|
||||
update();
|
||||
redrawTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
void LcdWidget::doPaint(QPainter &p)
|
||||
{
|
||||
QRgb rgb;
|
||||
uint16_t z;
|
||||
|
||||
if (!localBuf) return;
|
||||
|
||||
if (lcdDepth == 16) {
|
||||
for (int x = 0; x < lcdWidth; x++) {
|
||||
for (int y = 0; y < lcdHeight; y++) {
|
||||
z = ((uint16_t *)localBuf)[y * lcdWidth + x];
|
||||
rgb = qRgb(255 * ((z & 0xF800) >> 11) / 0x1F,
|
||||
255 * ((z & 0x07E0) >> 5) / 0x3F, 255 * (z & 0x001F) / 0x1F);
|
||||
p.setPen(rgb);
|
||||
p.drawPoint(x, y);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (lcdDepth == 12) {
|
||||
for (int x = 0; x < lcdWidth; x++) {
|
||||
for (int y = 0; y < lcdHeight; y++) {
|
||||
z = ((uint16_t *)localBuf)[y * lcdWidth + x];
|
||||
rgb = qRgb(255 * ((z & 0xF00) >> 8) / 0x0F,
|
||||
255 * ((z & 0x0F0) >> 4) / 0x0F, 255 * (z & 0x00F) / 0x0F);
|
||||
p.setPen(rgb);
|
||||
p.drawPoint(x, y);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QColor bg;
|
||||
if (lightEnable)
|
||||
bg = bgColor;
|
||||
else
|
||||
bg = bgDefaultColor;
|
||||
|
||||
p.setBackground(QBrush(bg));
|
||||
p.eraseRect(0, 0, 2 * lcdWidth, 2 * lcdHeight);
|
||||
|
||||
if (lcdDepth == 1) {
|
||||
rgb = qRgb(0, 0, 0);
|
||||
p.setPen(rgb);
|
||||
p.setBrush(QBrush(rgb));
|
||||
}
|
||||
|
||||
uint16_t idx, mask;
|
||||
uint16_t previousDepth = 0xFF;
|
||||
|
||||
for (int y = 0; y < lcdHeight; y++) {
|
||||
idx = (y * lcdDepth / 8) * lcdWidth;
|
||||
mask = (1 << (y % 8));
|
||||
for (int x = 0; x < lcdWidth; x++, idx++) {
|
||||
if (lcdDepth == 1) {
|
||||
if (localBuf[idx] & mask) p.drawRect(2 * x, 2 * y, 1, 1);
|
||||
continue;
|
||||
}
|
||||
// lcdDepth == 4
|
||||
z = (y & 1) ? (localBuf[idx] >> 4) : (localBuf[idx] & 0x0F);
|
||||
if (!z) continue;
|
||||
if (z != previousDepth) {
|
||||
previousDepth = z;
|
||||
rgb = qRgb(bg.red() - (z * bg.red()) / 15,
|
||||
bg.green() - (z * bg.green()) / 15,
|
||||
bg.blue() - (z * bg.blue()) / 15);
|
||||
p.setPen(rgb);
|
||||
p.setBrush(QBrush(rgb));
|
||||
}
|
||||
p.drawRect(2 * x, 2 * y, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LcdWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter p(this);
|
||||
doPaint(p);
|
||||
}
|
||||
|
||||
void LcdWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
emit touchEvent(TouchSlide, event->pos().x(), event->pos().y());
|
||||
}
|
||||
|
||||
void LcdWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
emit touchEvent(TouchDown, event->pos().x(), event->pos().y());
|
||||
}
|
||||
|
||||
void LcdWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
emit touchEvent(TouchUp, event->pos().x(), event->pos().y());
|
||||
}
|
||||
@@ -18,8 +18,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _LCDWIDGET_H_
|
||||
#define _LCDWIDGET_H_
|
||||
#pragma once
|
||||
|
||||
#include <QApplication>
|
||||
#include <QWidget>
|
||||
@@ -29,6 +28,7 @@
|
||||
#include <QElapsedTimer>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "appdata.h"
|
||||
#include "appdebugmessagehandler.h"
|
||||
@@ -39,186 +39,56 @@ class LcdWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
public:
|
||||
enum TouchEvent { TouchUp = 0, TouchDown, TouchSlide };
|
||||
|
||||
LcdWidget(QWidget * parent = 0):
|
||||
LcdWidget(QWidget *parent = 0) :
|
||||
QWidget(parent),
|
||||
lcdBuf(NULL),
|
||||
localBuf(NULL),
|
||||
lightEnable(false),
|
||||
bgDefaultColor(QColor(198, 208, 199))
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
~LcdWidget()
|
||||
{
|
||||
if (localBuf) {
|
||||
free(localBuf);
|
||||
}
|
||||
}
|
||||
|
||||
~LcdWidget()
|
||||
{
|
||||
if (localBuf) {
|
||||
free(localBuf);
|
||||
}
|
||||
}
|
||||
void setData(unsigned char *buf, int width, int height, int depth = 1);
|
||||
void setBgDefaultColor(const QColor &color);
|
||||
void setBackgroundColor(const QColor &color);
|
||||
|
||||
void setData(unsigned char *buf, int width, int height, int depth=1)
|
||||
{
|
||||
lcdBuf = buf;
|
||||
lcdWidth = width;
|
||||
lcdHeight = height;
|
||||
lcdDepth = depth;
|
||||
if (depth >= 8)
|
||||
lcdSize = (width * height) * ((depth+7) / 8);
|
||||
else
|
||||
lcdSize = (width * ((height+7)/8)) * depth;
|
||||
void makeScreenshot(const QString &fileName);
|
||||
|
||||
localBuf = (unsigned char *)malloc(lcdSize);
|
||||
memset(localBuf, 0, lcdSize);
|
||||
}
|
||||
void onLcdChanged(bool light);
|
||||
|
||||
void setBgDefaultColor(const QColor & color)
|
||||
{
|
||||
bgDefaultColor = color;
|
||||
}
|
||||
signals:
|
||||
void touchEvent(int type, int x, int y);
|
||||
|
||||
void setBackgroundColor(const QColor & color)
|
||||
{
|
||||
bgColor = color;
|
||||
}
|
||||
protected:
|
||||
int lcdWidth;
|
||||
int lcdHeight;
|
||||
int lcdDepth;
|
||||
int lcdSize;
|
||||
|
||||
void makeScreenshot(const QString & fileName)
|
||||
{
|
||||
int width, height;
|
||||
if (lcdDepth < 12) {
|
||||
width = 2 * lcdWidth;
|
||||
height = 2 * lcdHeight;
|
||||
}
|
||||
else {
|
||||
width = lcdWidth;
|
||||
height = lcdHeight;
|
||||
}
|
||||
QPixmap buffer(width, height);
|
||||
QPainter p(&buffer);
|
||||
doPaint(p);
|
||||
if (fileName.isEmpty()) {
|
||||
QApplication::clipboard()->setPixmap( buffer );
|
||||
qInfo() << "Screenshot saved to clipboard";
|
||||
}
|
||||
else {
|
||||
buffer.toImage().save(fileName);
|
||||
qInfo() << "Screenshot saved to:" << fileName;
|
||||
}
|
||||
}
|
||||
unsigned char *lcdBuf;
|
||||
unsigned char *localBuf;
|
||||
|
||||
void onLcdChanged(bool light)
|
||||
{
|
||||
QMutexLocker locker(&lcdMtx);
|
||||
lightEnable = light;
|
||||
memcpy(localBuf, lcdBuf, lcdSize);
|
||||
if (!redrawTimer.isValid() || redrawTimer.hasExpired(LCD_WIDGET_REFRESH_PERIOD)) {
|
||||
update();
|
||||
redrawTimer.start();
|
||||
}
|
||||
}
|
||||
bool lightEnable;
|
||||
QColor bgColor;
|
||||
QColor bgDefaultColor;
|
||||
QMutex lcdMtx;
|
||||
QElapsedTimer redrawTimer;
|
||||
|
||||
protected:
|
||||
void doPaint(QPainter &p);
|
||||
|
||||
int lcdWidth;
|
||||
int lcdHeight;
|
||||
int lcdDepth;
|
||||
int lcdSize;
|
||||
|
||||
unsigned char *lcdBuf;
|
||||
unsigned char *localBuf;
|
||||
|
||||
bool lightEnable;
|
||||
QColor bgColor;
|
||||
QColor bgDefaultColor;
|
||||
QMutex lcdMtx;
|
||||
QElapsedTimer redrawTimer;
|
||||
|
||||
inline void doPaint(QPainter & p)
|
||||
{
|
||||
QRgb rgb;
|
||||
uint16_t z;
|
||||
|
||||
if (!localBuf)
|
||||
return;
|
||||
|
||||
if (lcdDepth == 16) {
|
||||
for (int x = 0; x < lcdWidth; x++) {
|
||||
for (int y = 0; y < lcdHeight; y++) {
|
||||
z = ((uint16_t *)localBuf)[y * lcdWidth + x];
|
||||
rgb = qRgb(255 * ((z & 0xF800) >> 11) / 0x1F,
|
||||
255 * ((z & 0x07E0) >> 5) / 0x3F,
|
||||
255 * (z & 0x001F) / 0x1F);
|
||||
p.setPen(rgb);
|
||||
p.drawPoint(x, y);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (lcdDepth == 12) {
|
||||
for (int x = 0; x < lcdWidth; x++) {
|
||||
for (int y = 0; y < lcdHeight; y++) {
|
||||
z = ((uint16_t *)localBuf)[y * lcdWidth + x];
|
||||
rgb = qRgb(255 * ((z & 0xF00) >> 8) / 0x0F,
|
||||
255 * ((z & 0x0F0) >> 4) / 0x0F,
|
||||
255 * (z & 0x00F) / 0x0F);
|
||||
p.setPen(rgb);
|
||||
p.drawPoint(x, y);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QColor bg;
|
||||
if (lightEnable)
|
||||
bg = bgColor;
|
||||
else
|
||||
bg = bgDefaultColor;
|
||||
|
||||
p.setBackground(QBrush(bg));
|
||||
p.eraseRect(0, 0, 2*lcdWidth, 2*lcdHeight);
|
||||
|
||||
if (lcdDepth == 1) {
|
||||
rgb = qRgb(0, 0, 0);
|
||||
p.setPen(rgb);
|
||||
p.setBrush(QBrush(rgb));
|
||||
}
|
||||
|
||||
uint16_t idx, mask;
|
||||
uint16_t previousDepth = 0xFF;
|
||||
|
||||
for (int y = 0; y < lcdHeight; y++) {
|
||||
idx = (y * lcdDepth / 8) * lcdWidth;
|
||||
mask = (1 << (y % 8));
|
||||
for (int x = 0; x < lcdWidth; x++, idx++) {
|
||||
if (lcdDepth == 1) {
|
||||
if (localBuf[idx] & mask)
|
||||
p.drawRect(2 * x, 2 * y, 1, 1);
|
||||
continue;
|
||||
}
|
||||
// lcdDepth == 4
|
||||
z = (y & 1) ? (localBuf[idx] >> 4) : (localBuf[idx] & 0x0F);
|
||||
if (!z)
|
||||
continue;
|
||||
if (z != previousDepth) {
|
||||
previousDepth = z;
|
||||
rgb = qRgb(bg.red() - (z * bg.red()) / 15,
|
||||
bg.green() - (z * bg.green()) / 15,
|
||||
bg.blue() - (z * bg.blue()) / 15);
|
||||
p.setPen(rgb);
|
||||
p.setBrush(QBrush(rgb));
|
||||
}
|
||||
p.drawRect(2*x, 2*y, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void paintEvent(QPaintEvent*)
|
||||
{
|
||||
QPainter p(this);
|
||||
doPaint(p);
|
||||
}
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
};
|
||||
|
||||
#endif // _LCDWIDGET_H_
|
||||
|
||||
@@ -299,6 +299,51 @@ void OpenTxSimulator::rotaryEncoderEvent(int steps)
|
||||
#endif // defined(ROTARY_ENCODER_NAVIGATION)
|
||||
}
|
||||
|
||||
void OpenTxSimulator::touchEvent(int type, int x, int y)
|
||||
{
|
||||
switch (type) {
|
||||
case TouchDown:
|
||||
TRACE_WINDOWS("[Mouse Press] %d %d", x, y);
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
touchState.event = TE_DOWN;
|
||||
touchState.startX = touchState.x = x;
|
||||
touchState.startY = touchState.y = y;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TouchUp:
|
||||
TRACE_WINDOWS("[Mouse Release] %d %d", x, y);
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
if (touchState.event == TE_DOWN) {
|
||||
touchState.event = TE_UP;
|
||||
touchState.x = touchState.startX;
|
||||
touchState.y = touchState.startY;
|
||||
} else {
|
||||
touchState.event = TE_SLIDE_END;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TouchSlide:
|
||||
TRACE_WINDOWS("[Mouse Move] %d %d", x, y);
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
touchState.deltaX += x - touchState.x;
|
||||
touchState.deltaY += y - touchState.y;
|
||||
if (touchState.event == TE_SLIDE ||
|
||||
abs(touchState.deltaX) >= SLIDE_RANGE ||
|
||||
abs(touchState.deltaY) >= SLIDE_RANGE) {
|
||||
touchState.event = TE_SLIDE;
|
||||
touchState.x = x;
|
||||
touchState.y = y;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenTxSimulator::setTrainerTimeout(uint16_t ms)
|
||||
{
|
||||
ppmInputValidityTimer = ms;
|
||||
|
||||
@@ -35,6 +35,12 @@ class DLLEXPORT OpenTxSimulator : public SimulatorInterface
|
||||
|
||||
public:
|
||||
|
||||
enum TouchEvent {
|
||||
TouchUp=0,
|
||||
TouchDown,
|
||||
TouchSlide
|
||||
};
|
||||
|
||||
OpenTxSimulator();
|
||||
virtual ~OpenTxSimulator();
|
||||
|
||||
@@ -64,6 +70,7 @@ class DLLEXPORT OpenTxSimulator : public SimulatorInterface
|
||||
virtual void setTrainerInput(unsigned int inputNumber, int16_t value);
|
||||
virtual void setInputValue(int type, uint8_t index, int16_t value);
|
||||
virtual void rotaryEncoderEvent(int steps);
|
||||
virtual void touchEvent(int type, int x, int y);
|
||||
virtual void setTrainerTimeout(uint16_t ms);
|
||||
virtual void sendTelemetry(const QByteArray data);
|
||||
virtual void setLuaStateReloadPermanentScripts();
|
||||
|
||||
@@ -101,6 +101,10 @@ cmake ${COMMON_OPTIONS} -DPCB=X9E ${SRCDIR}
|
||||
make -j${JOBS} libsimulator
|
||||
rm CMakeCache.txt
|
||||
|
||||
cmake ${COMMON_OPTIONS} -DPCB=NV14 ${SRCDIR}
|
||||
make -j${JOBS} libsimulator
|
||||
rm CMakeCache.txt
|
||||
|
||||
cmake ${COMMON_OPTIONS} -DPCB=X10 ${SRCDIR}
|
||||
make -j${JOBS} libsimulator
|
||||
rm CMakeCache.txt
|
||||
|
||||
Reference in New Issue
Block a user