622 lines
16 KiB
C++
622 lines
16 KiB
C++
/*
|
|
* Copyright (C) OpenTX
|
|
*
|
|
* Based on code named
|
|
* 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.
|
|
*/
|
|
|
|
#define GBALL_SIZE 25
|
|
#define GBALL_SIZE_MN 20
|
|
#define GBALL_SIZE_MX 35
|
|
#define CENTER_INTERVAL 50 // ms
|
|
|
|
#include "virtualjoystickwidget.h"
|
|
|
|
#include "boards.h"
|
|
#include "modeledit/node.h"
|
|
#include "helpers.h"
|
|
#include "radiotrimwidget.h"
|
|
#include "simulator.h"
|
|
|
|
VirtualJoystickWidget::VirtualJoystickWidget(QWidget *parent, QChar side, bool showTrims, bool showBtns, bool showValues, QSize size) :
|
|
QWidget(parent),
|
|
stickSide(side),
|
|
prefSize(size),
|
|
hTrimWidget(NULL),
|
|
vTrimWidget(NULL),
|
|
btnHoldX(NULL),
|
|
btnHoldY(NULL),
|
|
btnFixX(NULL),
|
|
btnFixY(NULL),
|
|
nodeLabelX(NULL),
|
|
nodeLabelY(NULL),
|
|
m_stickScale(1024),
|
|
m_stickPressed(false)
|
|
{
|
|
ar = (float)size.width() / size.height();
|
|
extraSize = QSize(0, 0);
|
|
|
|
// 5 col x 4 rows
|
|
layout = new QGridLayout(this);
|
|
layout->setContentsMargins(0, 0, 0, 0);
|
|
layout->setSpacing(0);
|
|
|
|
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
setSizePolicy(sizePolicy);
|
|
|
|
gv = new QGraphicsView(this);
|
|
gv->setSizePolicy(sizePolicy);
|
|
gv->setMinimumSize(size);
|
|
gv->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
gv->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
gv->setRenderHints(QPainter::Antialiasing);
|
|
|
|
scene = new CustomGraphicsScene(gv);
|
|
scene->setItemIndexMethod(QGraphicsScene::NoIndex);
|
|
gv->setScene(scene);
|
|
|
|
node = new Node();
|
|
node->setPos(-GBALL_SIZE / 2, -GBALL_SIZE / 2);
|
|
node->setBallSize(GBALL_SIZE);
|
|
scene->addItem(node);
|
|
|
|
int colvt, colbb, colvx, colvy;
|
|
if (stickSide == 'L') {
|
|
colvt = 3;
|
|
colbb = 1;
|
|
colvx = 1;
|
|
colvy = 3;
|
|
}
|
|
else {
|
|
colvt = 1;
|
|
colbb = 3;
|
|
colvx = 3;
|
|
colvy = 1;
|
|
}
|
|
|
|
if (showTrims) {
|
|
hTrimWidget = createTrimWidget('H');
|
|
vTrimWidget = createTrimWidget('V');
|
|
|
|
layout->addWidget(vTrimWidget, 1, colvt, 1, 1);
|
|
layout->addWidget(hTrimWidget, 2, 2, 1, 1);
|
|
|
|
extraSize += QSize(vTrimWidget->sizeHint().width(), hTrimWidget->sizeHint().height());
|
|
}
|
|
else {
|
|
colvx = colvy = colvt;
|
|
}
|
|
|
|
if (showBtns) {
|
|
QVBoxLayout * btnbox = new QVBoxLayout();
|
|
btnbox->setContentsMargins(9, 9, 9, 9);
|
|
btnbox->setSpacing(2);
|
|
btnbox->addWidget(btnHoldY = createButtonWidget(HOLD_Y));
|
|
btnbox->addWidget(btnFixY = createButtonWidget(FIX_Y));
|
|
btnbox->addWidget(btnFixX = createButtonWidget(FIX_X));
|
|
btnbox->addWidget(btnHoldX = createButtonWidget(HOLD_X));
|
|
|
|
layout->addLayout(btnbox, 1, colbb, 1, 1);
|
|
|
|
extraSize.setWidth(extraSize.width() + btnbox->sizeHint().width());
|
|
}
|
|
|
|
if (showValues) {
|
|
QLayout * valX = createNodeValueLayout('X', nodeLabelX);
|
|
QLayout * valY = createNodeValueLayout('Y', nodeLabelY);
|
|
if (!showTrims) {
|
|
QVBoxLayout * vertXY = new QVBoxLayout();
|
|
vertXY->addLayout(valX);
|
|
vertXY->addLayout(valY);
|
|
layout->addLayout(vertXY, 1, colvx, 1, 1);
|
|
extraSize += QSize(nodeLabelX->sizeHint().width(), 0);
|
|
}
|
|
else {
|
|
layout->addLayout(valX, 2, colvx, 1, 1);
|
|
layout->addLayout(valY, 2, colvy, 1, 1);
|
|
}
|
|
}
|
|
|
|
layout->addItem(new QSpacerItem(0, 0), 0, 0, 1, 5); // r0 c0-4: top v spacer
|
|
layout->addItem(new QSpacerItem(0, 0), 1, 0, 2, 1); // r1-2 c0: left h spacer
|
|
layout->addWidget(gv, 1, 2, 1, 1); // r1 c2: stick widget
|
|
layout->addItem(new QSpacerItem(0, 0), 1, 4, 2, 1); // r1-2 c4: right h spacer
|
|
layout->addItem(new QSpacerItem(0, 0), 3, 0, 1, 5); // r4 c0-4: bot v spacer
|
|
|
|
setStickIndices(getStickIndex('H'), getStickIndex('V'));
|
|
|
|
connect(node, &Node::xChanged, this, &VirtualJoystickWidget::onNodeXChanged);
|
|
connect(node, &Node::yChanged, this, &VirtualJoystickWidget::onNodeYChanged);
|
|
|
|
connect(scene, &CustomGraphicsScene::mouseEvent, this, &VirtualJoystickWidget::onGsMouseEvent);
|
|
|
|
setSize(prefSize, frameSize());
|
|
|
|
centerStickTimer.setInterval(CENTER_INTERVAL);
|
|
connect(¢erStickTimer, &QTimer::timeout, this, &VirtualJoystickWidget::centerStick);
|
|
centerStickTimer.start();
|
|
}
|
|
|
|
void VirtualJoystickWidget::setStickX(qreal x)
|
|
{
|
|
node->setX(x);
|
|
}
|
|
|
|
void VirtualJoystickWidget::setStickY(qreal y)
|
|
{
|
|
node->setY(y);
|
|
}
|
|
|
|
void VirtualJoystickWidget::setStickPos(QPointF xy)
|
|
{
|
|
node->setPos(xy);
|
|
}
|
|
|
|
void VirtualJoystickWidget::setStickAxisValue(int index, int value)
|
|
{
|
|
using namespace Board;
|
|
qreal rvalue = value / 1024.0f;
|
|
|
|
switch (index) {
|
|
case STICK_AXIS_LH :
|
|
if (stickSide == 'L')
|
|
setStickX(rvalue);
|
|
break;
|
|
case STICK_AXIS_RH :
|
|
if (stickSide == 'R')
|
|
setStickX(rvalue);
|
|
break;
|
|
case STICK_AXIS_LV :
|
|
if (stickSide == 'L')
|
|
setStickY(rvalue);
|
|
break;
|
|
case STICK_AXIS_RV :
|
|
if (stickSide == 'R')
|
|
setStickY(rvalue);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void VirtualJoystickWidget::centerStick()
|
|
{
|
|
node->stepToCenter();
|
|
}
|
|
|
|
qreal VirtualJoystickWidget::getStickX()
|
|
{
|
|
return getStickPos().x();
|
|
}
|
|
|
|
qreal VirtualJoystickWidget::getStickY()
|
|
{
|
|
return getStickPos().y();
|
|
}
|
|
|
|
QPointF VirtualJoystickWidget::getStickPos()
|
|
{
|
|
return QPointF(node->getX(), node->getY());
|
|
}
|
|
|
|
void VirtualJoystickWidget::setTrimsRange(int min, int max)
|
|
{
|
|
if (hTrimWidget)
|
|
hTrimWidget->setTrimRange(min, max);
|
|
if (vTrimWidget)
|
|
vTrimWidget->setTrimRange(min, max);
|
|
}
|
|
|
|
void VirtualJoystickWidget::setTrimsRange(int rng)
|
|
{
|
|
setTrimsRange(-rng, rng);
|
|
}
|
|
|
|
void VirtualJoystickWidget::setTrimRange(int index, int min, int max)
|
|
{
|
|
if (index == Board::TRIM_AXIS_COUNT) {
|
|
setTrimsRange(min, max);
|
|
return;
|
|
}
|
|
RadioTrimWidget * trim = getTrimWidget(index);
|
|
if (trim) {
|
|
trim->setTrimRange(min, max);
|
|
}
|
|
}
|
|
|
|
void VirtualJoystickWidget::setTrimValue(int index, int value)
|
|
{
|
|
RadioTrimWidget * trim = getTrimWidget(index);
|
|
if (trim) {
|
|
trim->setValue(value);
|
|
}
|
|
}
|
|
|
|
int VirtualJoystickWidget::getStickScale() const
|
|
{
|
|
return m_stickScale;
|
|
}
|
|
|
|
void VirtualJoystickWidget::setStickScale(int stickScale)
|
|
{
|
|
m_stickScale = stickScale;
|
|
}
|
|
|
|
void VirtualJoystickWidget::setWidgetValue(const RadioWidget::RadioWidgetType type, const int index, const int value)
|
|
{
|
|
if (type == RadioWidget::RADIO_WIDGET_TRIM)
|
|
setTrimValue(index, value);
|
|
else if (type == RadioWidget::RADIO_WIDGET_STICK)
|
|
setStickAxisValue(index, value);
|
|
}
|
|
|
|
int VirtualJoystickWidget::getTrimValue(int which)
|
|
{
|
|
RadioTrimWidget * trim = getTrimWidget(which);
|
|
if (trim) {
|
|
return trim->getValue();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void VirtualJoystickWidget::setStickIndices(int xIdx, int yIdx)
|
|
{
|
|
m_xIndex = xIdx;
|
|
m_yIndex = yIdx;
|
|
}
|
|
|
|
void VirtualJoystickWidget::setStickConstraint(quint8 index, bool active)
|
|
{
|
|
if (btnHoldX == NULL || !index)
|
|
return; // no buttons
|
|
|
|
if (index & HOLD_X)
|
|
btnHoldX->setChecked(active);
|
|
if (index & HOLD_Y)
|
|
btnHoldY->setChecked(active);
|
|
if (index & FIX_X)
|
|
btnFixX->setChecked(active);
|
|
if (index & FIX_Y)
|
|
btnFixY->setChecked(active);
|
|
}
|
|
|
|
void VirtualJoystickWidget::setStickColor(const QColor & color)
|
|
{
|
|
node->setColor(color);
|
|
}
|
|
|
|
void VirtualJoystickWidget::loadDefaultsForMode(const unsigned mode)
|
|
{
|
|
if (((mode & 1) && stickSide == 'L') || (!(mode & 1) && stickSide == 'R')) {
|
|
setStickConstraint(HOLD_Y, true);
|
|
setStickY(1.0);
|
|
onNodeYChanged();
|
|
}
|
|
}
|
|
|
|
QSize VirtualJoystickWidget::sizeHint() const {
|
|
return prefSize;
|
|
}
|
|
|
|
void VirtualJoystickWidget::resizeEvent(QResizeEvent * event)
|
|
{
|
|
QWidget::resizeEvent(event);
|
|
setSize(event->size(), event->oldSize());
|
|
}
|
|
|
|
void VirtualJoystickWidget::onNodeXChanged()
|
|
{
|
|
emit valueChange(RadioWidget::RADIO_WIDGET_STICK, m_xIndex, int(m_stickScale * getStickX()));
|
|
updateNodeValueLabels();
|
|
}
|
|
|
|
void VirtualJoystickWidget::onNodeYChanged()
|
|
{
|
|
emit valueChange(RadioWidget::RADIO_WIDGET_STICK, m_yIndex, int(-m_stickScale * getStickY()));
|
|
updateNodeValueLabels();
|
|
}
|
|
|
|
void VirtualJoystickWidget::setSize(const QSize & size, const QSize &)
|
|
{
|
|
float thisAspectRatio = (float)size.width() / size.height();
|
|
float newGvSz, spacerSz;
|
|
bool sized = false;
|
|
|
|
if (thisAspectRatio > ar) {
|
|
// constrain width
|
|
newGvSz = (height() - extraSize.height()) * ar; // new width
|
|
spacerSz = (width() - newGvSz - extraSize.width()) / 2; // + 0.5;
|
|
if (spacerSz >= 0.0f) {
|
|
layout->setRowStretch(0, 0);
|
|
layout->setColumnStretch(0, spacerSz);
|
|
layout->setColumnStretch(4, spacerSz);
|
|
layout->setRowStretch(3, 0);
|
|
sized = true;
|
|
}
|
|
}
|
|
if (!sized) {
|
|
// constrain height
|
|
newGvSz = (width() - extraSize.width()) * ar; // new height
|
|
spacerSz = (height() - newGvSz - extraSize.height()) / 2; // + 0.5;
|
|
spacerSz = qMax(spacerSz, 0.0f);
|
|
layout->setRowStretch(0, spacerSz);
|
|
layout->setColumnStretch(0, 0);
|
|
layout->setColumnStretch(4, 0);
|
|
layout->setRowStretch(3, spacerSz);
|
|
}
|
|
|
|
layout->setColumnStretch(2, newGvSz);
|
|
layout->setRowStretch(1, newGvSz);
|
|
|
|
gv->resize(newGvSz, newGvSz);
|
|
gv->updateGeometry();
|
|
|
|
int ballSize = (newGvSz * GBALL_SIZE * 0.005f);
|
|
ballSize = qMin(GBALL_SIZE_MX, qMax(ballSize, GBALL_SIZE_MN));
|
|
|
|
QRectF qr = (QRectF)gv->contentsRect();
|
|
qreal w = qr.width() - ballSize;
|
|
qreal h = qr.height() - ballSize;
|
|
qreal cx = qr.width() / 2;
|
|
qreal cy = qr.height() / 2;
|
|
qreal nodeX = node->getX();
|
|
qreal nodeY = node->getY();
|
|
|
|
scene->setSceneRect(-cx,-cy,w,h);
|
|
|
|
node->setBallSize(ballSize);
|
|
node->setX(nodeX);
|
|
node->setY(nodeY);
|
|
|
|
//qDebug() << thisAspectRatio << size << newGvSz << spacerSz << extraSize << gv->geometry() << gv->contentsRect() << gv->frameRect() << getStickPos();
|
|
}
|
|
|
|
RadioTrimWidget * VirtualJoystickWidget::createTrimWidget(QChar type)
|
|
{
|
|
RadioTrimWidget * trimWidget = new RadioTrimWidget(type == 'H' ? Qt::Horizontal : Qt::Vertical);
|
|
trimWidget->setIndices(getTrimSliderType(type), getTrimButtonType(type, 0), getTrimButtonType(type, 1));
|
|
|
|
connect(trimWidget, &RadioTrimWidget::valueChange, this, &VirtualJoystickWidget::valueChange);
|
|
|
|
return trimWidget;
|
|
}
|
|
|
|
QToolButton * VirtualJoystickWidget::createButtonWidget(int type)
|
|
{
|
|
QString btnLabel, tooltip;
|
|
QIcon icon;
|
|
switch (type) {
|
|
case HOLD_Y:
|
|
btnLabel = tr("Hld Y");
|
|
tooltip = tr("Hold Vertical stick position.");
|
|
icon = Simulator::SimulatorIcon("hold_y");
|
|
break;
|
|
case FIX_Y:
|
|
btnLabel = tr("Fix Y");
|
|
tooltip = tr("Prevent Vertical movement of stick.");
|
|
icon = Simulator::SimulatorIcon("fixed_y");
|
|
break;
|
|
case FIX_X:
|
|
btnLabel = tr("Fix X");
|
|
tooltip = tr("Prevent Horizontal movement of stick.");
|
|
icon = Simulator::SimulatorIcon("fixed_x");
|
|
break;
|
|
case HOLD_X:
|
|
btnLabel = tr("Hld X");
|
|
tooltip = tr("Hold Horizontal stick position.");
|
|
icon = Simulator::SimulatorIcon("hold_x");
|
|
break;
|
|
default:
|
|
return NULL;
|
|
}
|
|
QToolButton * btn = new QToolButton(this);
|
|
btn->setProperty("btnType", type);
|
|
btn->setIcon(icon);
|
|
btn->setIconSize(QSize(20, 20));
|
|
btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
|
|
btn->setText(btnLabel);
|
|
btn->setToolTip(tooltip);
|
|
btn->setCheckable(true);
|
|
btn->setAutoRaise(true);
|
|
|
|
connect(btn, &QToolButton::toggled, this, &VirtualJoystickWidget::onButtonChange);
|
|
|
|
return btn;
|
|
}
|
|
|
|
QLayout *VirtualJoystickWidget::createNodeValueLayout(QChar type, QLabel *& valLabel)
|
|
{
|
|
QLabel * lbl = new QLabel(QString("%1 %").arg(type), this);
|
|
lbl->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
|
lbl->setAlignment(Qt::AlignCenter);
|
|
QLabel * val = new QLabel("0");
|
|
val->setObjectName(QString("val_%1").arg(type));
|
|
val->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
|
val->setAlignment(Qt::AlignCenter);
|
|
val->setMinimumWidth(val->fontMetrics().width("-100 "));
|
|
// TODO 2.4 => val->setMinimumWidth(val->fontMetrics().horizontalAdvance("-100 "));
|
|
QVBoxLayout * layout = new QVBoxLayout();
|
|
layout->setContentsMargins(2, 2, 2, 2);
|
|
layout->setSpacing(2);
|
|
layout->addWidget(lbl);
|
|
layout->addWidget(val);
|
|
|
|
valLabel = val;
|
|
return layout;
|
|
}
|
|
|
|
int VirtualJoystickWidget::getStickIndex(QChar type)
|
|
{
|
|
using namespace Board;
|
|
|
|
if (stickSide == 'L') {
|
|
if (type == 'H')
|
|
return STICK_AXIS_LH;
|
|
else
|
|
return STICK_AXIS_LV;
|
|
}
|
|
else {
|
|
if (type == 'H')
|
|
return STICK_AXIS_RH;
|
|
else
|
|
return STICK_AXIS_RV;
|
|
}
|
|
}
|
|
|
|
int VirtualJoystickWidget::getTrimSliderType(QChar type)
|
|
{
|
|
using namespace Board;
|
|
|
|
if (stickSide == 'L') {
|
|
if (type == 'H')
|
|
return TRIM_AXIS_LH;
|
|
else
|
|
return TRIM_AXIS_LV;
|
|
}
|
|
else {
|
|
if (type == 'H')
|
|
return TRIM_AXIS_RH;
|
|
else
|
|
return TRIM_AXIS_RV;
|
|
}
|
|
}
|
|
|
|
int VirtualJoystickWidget::getTrimButtonType(QChar type, int pos)
|
|
{
|
|
using namespace Board;
|
|
|
|
if (stickSide == 'L') {
|
|
if (type == 'H') {
|
|
if (pos == 0)
|
|
return TRIM_SW_LH_DEC;
|
|
else
|
|
return TRIM_SW_LH_INC;
|
|
}
|
|
else {
|
|
if (pos == 0)
|
|
return TRIM_SW_LV_DEC;
|
|
else
|
|
return TRIM_SW_LV_INC;
|
|
}
|
|
}
|
|
// right side
|
|
else {
|
|
if (type == 'H') {
|
|
if (pos == 0)
|
|
return TRIM_SW_RH_DEC;
|
|
else
|
|
return TRIM_SW_RH_INC;
|
|
}
|
|
else {
|
|
if (pos == 0)
|
|
return TRIM_SW_RV_DEC;
|
|
else
|
|
return TRIM_SW_RV_INC;
|
|
}
|
|
}
|
|
}
|
|
|
|
RadioTrimWidget * VirtualJoystickWidget::getTrimWidget(int which)
|
|
{
|
|
if ((stickSide == 'L' && which == Board::TRIM_AXIS_LH) || (stickSide == 'R' && which == Board::TRIM_AXIS_RH))
|
|
return hTrimWidget;
|
|
else if ((stickSide == 'L' && which == Board::TRIM_AXIS_LV) || (stickSide == 'R' && which == Board::TRIM_AXIS_RV))
|
|
return vTrimWidget;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void VirtualJoystickWidget::onButtonChange(bool checked)
|
|
{
|
|
if (!sender() || !sender()->property("btnType").isValid())
|
|
return;
|
|
|
|
switch (sender()->property("btnType").toInt()) {
|
|
case HOLD_Y:
|
|
node->setCenteringY(!checked);
|
|
break;
|
|
case FIX_Y:
|
|
node->setFixedY(checked);
|
|
break;
|
|
case FIX_X:
|
|
node->setFixedX(checked);
|
|
break;
|
|
case HOLD_X:
|
|
node->setCenteringX(!checked);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void VirtualJoystickWidget::updateNodeValueLabels()
|
|
{
|
|
if (nodeLabelX)
|
|
nodeLabelX->setText(QString("%1").arg(node->getX() * 100.0f, 2, 'f', 0));
|
|
if (nodeLabelY)
|
|
nodeLabelY->setText(QString("%1").arg(node->getY() * -100.0f, 2, 'f', 0));
|
|
}
|
|
|
|
void VirtualJoystickWidget::onGsMouseEvent(QGraphicsSceneMouseEvent * event)
|
|
{
|
|
if (!node)
|
|
return;
|
|
|
|
//qDebug() << event->type() << event->scenePos() << event->buttons() << event->isAccepted() << m_stickPressed;
|
|
if (event->type() == QEvent::GraphicsSceneMouseRelease && m_stickPressed) {
|
|
node->setPressed(false);
|
|
m_stickPressed = false;
|
|
return;
|
|
}
|
|
|
|
if (!(event->buttons() & Qt::LeftButton))
|
|
return;
|
|
|
|
if (event->type() == QEvent::GraphicsSceneMousePress) {
|
|
node->setPressed(true);
|
|
m_stickPressed = true;
|
|
}
|
|
else if (!m_stickPressed || event->type() != QEvent::GraphicsSceneMouseMove) {
|
|
return;
|
|
}
|
|
node->setPos(event->scenePos());
|
|
}
|
|
|
|
|
|
/*
|
|
* CustomGraphicsScene
|
|
*/
|
|
|
|
void CustomGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent * event)
|
|
{
|
|
QGraphicsScene::mousePressEvent(event);
|
|
if (!event->isAccepted()) {
|
|
event->accept();
|
|
emit mouseEvent(event);
|
|
}
|
|
}
|
|
|
|
void CustomGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
|
|
{
|
|
QGraphicsScene::mouseReleaseEvent(event);
|
|
emit mouseEvent(event);
|
|
}
|
|
|
|
void CustomGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
|
|
{
|
|
QGraphicsScene::mouseMoveEvent(event);
|
|
if (!event->isAccepted() && (event->buttons() & Qt::LeftButton)) {
|
|
event->accept();
|
|
emit mouseEvent(event);
|
|
}
|
|
}
|