There is a class QVTKInteractorAdapter
that is a layer between QtQuick and VTK for interaction. Qt has an event QEvent::HoverMove
(The mouse cursor moves inside a hover widget). This event corresponds to the event from VTK - vtkCommand::MouseMoveEvent. But it is not implemented in QVTKInteractorAdapter::ProcessEvent
, there is only QEvent::HoverLeave
:
bool QVTKInteractorAdapter::ProcessEvent(QEvent* e, vtkRenderWindowInteractor* iren)
{
if (iren == nullptr || e == nullptr)
return false;
const QEvent::Type t = e->type();
if (t == QEvent::FocusIn)
{
// For 3DConnexion devices:
QVTKInteractor* qiren = QVTKInteractor::SafeDownCast(iren);
if (qiren)
{
qiren->StartListening();
}
return true;
}
if (t == QEvent::FocusOut)
{
// For 3DConnexion devices:
QVTKInteractor* qiren = QVTKInteractor::SafeDownCast(iren);
if (qiren)
{
qiren->StopListening();
}
return true;
}
if (t == QEvent::HoverLeave)
{
iren->InvokeEvent(vtkCommand::HoverEvent, nullptr);
}
// the following events only happen if the interactor is enabled
if (!iren->GetEnabled())
return false;
if (t == QEvent::MouseButtonPress || t == QEvent::MouseButtonRelease ||
t == QEvent::MouseButtonDblClick || t == QEvent::MouseMove)
{
QMouseEvent* e2 = static_cast<QMouseEvent*>(e);
// give interactor the event information
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
auto x = e2->x();
auto y = e2->y();
#else
auto x = e2->position().x();
auto y = e2->position().y();
#endif
iren->SetEventInformationFlipY(
static_cast<int>(x * this->DevicePixelRatio + DevicePixelRatioTolerance),
static_cast<int>(y * this->DevicePixelRatio + DevicePixelRatioTolerance),
(e2->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0,
(e2->modifiers() & Qt::ShiftModifier) > 0 ? 1 : 0, 0,
e2->type() == QEvent::MouseButtonDblClick ? 1 : 0);
iren->SetAltKey((e2->modifiers() & Qt::AltModifier) > 0 ? 1 : 0);
if (t == QEvent::MouseMove)
{
iren->InvokeEvent(vtkCommand::MouseMoveEvent, e2);
}
else if (t == QEvent::MouseButtonPress)
{
switch (e2->button())
{
case Qt::LeftButton:
iren->InvokeEvent(vtkCommand::LeftButtonPressEvent, e2);
break;
case Qt::MiddleButton:
iren->InvokeEvent(vtkCommand::MiddleButtonPressEvent, e2);
break;
case Qt::RightButton:
iren->InvokeEvent(vtkCommand::RightButtonPressEvent, e2);
break;
default:
break;
}
}
else if (t == QEvent::MouseButtonDblClick)
{
switch (e2->button())
{
case Qt::LeftButton:
iren->InvokeEvent(vtkCommand::LeftButtonDoubleClickEvent, e2);
break;
case Qt::MiddleButton:
iren->InvokeEvent(vtkCommand::MiddleButtonDoubleClickEvent, e2);
break;
case Qt::RightButton:
iren->InvokeEvent(vtkCommand::RightButtonDoubleClickEvent, e2);
break;
default:
break;
}
}
else if (t == QEvent::MouseButtonRelease)
{
switch (e2->button())
{
case Qt::LeftButton:
iren->InvokeEvent(vtkCommand::LeftButtonReleaseEvent, e2);
break;
case Qt::MiddleButton:
iren->InvokeEvent(vtkCommand::MiddleButtonReleaseEvent, e2);
break;
case Qt::RightButton:
iren->InvokeEvent(vtkCommand::RightButtonReleaseEvent, e2);
break;
default:
break;
}
}
return true;
}
if (t == QEvent::TouchBegin || t == QEvent::TouchUpdate || t == QEvent::TouchEnd)
{
QTouchEvent* e2 = dynamic_cast<QTouchEvent*>(e);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Q_FOREACH (const QTouchEvent::TouchPoint& point, e2->touchPoints())
#else
Q_FOREACH (const QTouchEvent::TouchPoint& point, e2->points())
#endif
{
if (point.id() >= VTKI_MAX_POINTERS)
{
break;
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPointF pos = point.pos();
#else
QPointF pos = point.position();
#endif
// give interactor the event information
iren->SetEventInformationFlipY(
static_cast<int>(pos.x() * this->DevicePixelRatio + DevicePixelRatioTolerance),
static_cast<int>(pos.y() * this->DevicePixelRatio + DevicePixelRatioTolerance),
(e2->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0,
(e2->modifiers() & Qt::ShiftModifier) > 0 ? 1 : 0, 0, 0, nullptr, point.id());
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Q_FOREACH (const QTouchEvent::TouchPoint& point, e2->touchPoints())
#else
Q_FOREACH (const QTouchEvent::TouchPoint& point, e2->points())
#endif
{
if (point.id() >= VTKI_MAX_POINTERS)
{
break;
}
iren->SetPointerIndex(point.id());
if (point.state() & Qt::TouchPointReleased)
{
iren->InvokeEvent(vtkCommand::LeftButtonReleaseEvent, nullptr);
}
if (point.state() & Qt::TouchPointPressed)
{
iren->InvokeEvent(vtkCommand::LeftButtonPressEvent, nullptr);
}
if (point.state() & Qt::TouchPointMoved)
{
iren->InvokeEvent(vtkCommand::MouseMoveEvent, nullptr);
}
}
e2->accept();
return true;
}
if (t == QEvent::Enter)
{
iren->InvokeEvent(vtkCommand::EnterEvent, e);
return true;
}
if (t == QEvent::Leave)
{
iren->InvokeEvent(vtkCommand::LeaveEvent, e);
return true;
}
if (t == QEvent::KeyPress || t == QEvent::KeyRelease)
{
QKeyEvent* e2 = static_cast<QKeyEvent*>(e);
// get key and keysym information
int ascii_key = e2->text().length() ? e2->text().unicode()->toLatin1() : 0;
const char* keysym = ascii_to_key_sym(ascii_key);
if (!keysym || e2->modifiers() == Qt::KeypadModifier)
{
// get virtual keys
keysym = qt_key_to_key_sym(static_cast<Qt::Key>(e2->key()), e2->modifiers());
}
if (!keysym)
{
keysym = "None";
}
// give interactor event information
iren->SetKeyEventInformation((e2->modifiers() & Qt::ControlModifier),
(e2->modifiers() & Qt::ShiftModifier), ascii_key, e2->count(), keysym);
iren->SetAltKey((e2->modifiers() & Qt::AltModifier) > 0 ? 1 : 0);
if (t == QEvent::KeyPress)
{
// invoke vtk event
iren->InvokeEvent(vtkCommand::KeyPressEvent, e2);
// invoke char event only for ascii characters
if (ascii_key)
{
iren->InvokeEvent(vtkCommand::CharEvent, e2);
}
}
else
{
iren->InvokeEvent(vtkCommand::KeyReleaseEvent, e2);
}
return true;
}
if (t == QEvent::Wheel)
{
QWheelEvent* e2 = static_cast<QWheelEvent*>(e);
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
auto x = e2->x();
auto y = e2->y();
#else
auto x = e2->position().x();
auto y = e2->position().y();
#endif
iren->SetEventInformationFlipY(
static_cast<int>(x * this->DevicePixelRatio + DevicePixelRatioTolerance),
static_cast<int>(y * this->DevicePixelRatio + DevicePixelRatioTolerance),
(e2->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0,
(e2->modifiers() & Qt::ShiftModifier) > 0 ? 1 : 0);
iren->SetAltKey((e2->modifiers() & Qt::AltModifier) > 0 ? 1 : 0);
double horizontalDelta = e2->angleDelta().x();
double verticalDelta = e2->angleDelta().y();
this->AccumulatedDelta += verticalDelta + horizontalDelta;
const int threshold = 120;
// invoke vtk event when accumulated delta passes the threshold
if (this->AccumulatedDelta >= threshold && verticalDelta != 0.0)
{
iren->InvokeEvent(vtkCommand::MouseWheelForwardEvent, e2);
this->AccumulatedDelta = 0;
}
else if (this->AccumulatedDelta <= -threshold && verticalDelta != 0.0)
{
iren->InvokeEvent(vtkCommand::MouseWheelBackwardEvent, e2);
this->AccumulatedDelta = 0;
}
else if (this->AccumulatedDelta >= threshold && horizontalDelta != 0.0)
{
iren->InvokeEvent(vtkCommand::MouseWheelLeftEvent, e2);
this->AccumulatedDelta = 0;
}
else if (this->AccumulatedDelta <= -threshold && horizontalDelta != 0.0)
{
iren->InvokeEvent(vtkCommand::MouseWheelRightEvent, e2);
this->AccumulatedDelta = 0;
}
return true;
}
if (t == QEvent::ContextMenu)
{
QContextMenuEvent* e2 = static_cast<QContextMenuEvent*>(e);
// give interactor the event information
iren->SetEventInformationFlipY(
static_cast<int>(e2->x() * this->DevicePixelRatio + DevicePixelRatioTolerance),
static_cast<int>(e2->y() * this->DevicePixelRatio + DevicePixelRatioTolerance),
(e2->modifiers() & Qt::ControlModifier) > 0 ? 1 : 0,
(e2->modifiers() & Qt::ShiftModifier) > 0 ? 1 : 0);
iren->SetAltKey((e2->modifiers() & Qt::AltModifier) > 0 ? 1 : 0);
// invoke event and pass qt event for additional data as well
iren->InvokeEvent(QVTKInteractor::ContextMenuEvent, e2);
return true;
}
if (t == QEvent::DragEnter)
{
QDragEnterEvent* e2 = static_cast<QDragEnterEvent*>(e);
// invoke event and pass qt event for additional data as well
iren->InvokeEvent(QVTKInteractor::DragEnterEvent, e2);
return true;
}
if (t == QEvent::DragLeave)
{
QDragLeaveEvent* e2 = static_cast<QDragLeaveEvent*>(e);
// invoke event and pass qt event for additional data as well
iren->InvokeEvent(QVTKInteractor::DragLeaveEvent, e2);
return true;
}
if (t == QEvent::DragMove)
{
QDragMoveEvent* e2 = static_cast<QDragMoveEvent*>(e);
// give interactor the event information
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPoint pos = e2->pos();
#else
QPoint pos = e2->position().toPoint();
#endif
iren->SetEventInformationFlipY(
static_cast<int>(pos.x() * this->DevicePixelRatio + DevicePixelRatioTolerance),
static_cast<int>(pos.y() * this->DevicePixelRatio + DevicePixelRatioTolerance));
// invoke event and pass qt event for additional data as well
iren->InvokeEvent(QVTKInteractor::DragMoveEvent, e2);
return true;
}
if (t == QEvent::Drop)
{
QDropEvent* e2 = static_cast<QDropEvent*>(e);
// give interactor the event information
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QPoint pos = e2->pos();
#else
QPoint pos = e2->position().toPoint();
#endif
iren->SetEventInformationFlipY(
static_cast<int>(pos.x() * this->DevicePixelRatio + DevicePixelRatioTolerance),
static_cast<int>(pos.y() * this->DevicePixelRatio + DevicePixelRatioTolerance));
// invoke event and pass qt event for additional data as well
iren->InvokeEvent(QVTKInteractor::DropEvent, e2);
return true;
}
if (e->type() == QEvent::Gesture)
{
// Store event information to restore after gesture is completed
int eventPosition[2];
iren->GetEventPosition(eventPosition);
int lastEventPosition[2];
iren->GetLastEventPosition(lastEventPosition);
QGestureEvent* e2 = static_cast<QGestureEvent*>(e);
if (QSwipeGesture* swipe = static_cast<QSwipeGesture*>(e2->gesture(Qt::SwipeGesture)))
{
e2->accept(Qt::SwipeGesture);
double angle = swipe->swipeAngle();
iren->SetRotation(angle);
switch (swipe->state())
{
case Qt::GestureCanceled:
case Qt::GestureFinished:
iren->InvokeEvent(vtkCommand::EndSwipeEvent, e2);
break;
case Qt::GestureStarted:
iren->InvokeEvent(vtkCommand::StartSwipeEvent, e2);
iren->InvokeEvent(vtkCommand::SwipeEvent, e2);
break;
default:
iren->InvokeEvent(vtkCommand::SwipeEvent, e2);
}
}
if (QPinchGesture* pinch = static_cast<QPinchGesture*>(e2->gesture(Qt::PinchGesture)))
{
e2->accept(Qt::PinchGesture);
QPointF position = pinch->centerPoint().toPoint();
// When using MacOS trackpad, the center of the pinch event is already reported in widget
// coordinates. For other platforms, the coordinates need to be converted from global to
// local.
#ifndef Q_OS_OSX
QWidget* widget = qobject_cast<QWidget*>(this->parent());
if (widget)
{
position = widget->mapFromGlobal(pinch->centerPoint().toPoint());
}
else
{
// Pinch gesture position is in global coordinates, but could not find a widget to convert
// to local coordinates QVTKInteractorAdapter parent is not set in QVTKRenderWindowAdapter.
// Gesture coordinate mapping may be incorrect.
qWarning("Could not find parent widget. Gesture coordinate mapping may be incorrect");
}
#endif
iren->SetEventInformationFlipY(
static_cast<int>(position.x() * this->DevicePixelRatio + DevicePixelRatioTolerance),
static_cast<int>(position.y() * this->DevicePixelRatio + DevicePixelRatioTolerance));
iren->SetScale(1.0);
iren->SetScale(pinch->scaleFactor());
switch (pinch->state())
{
case Qt::GestureFinished:
case Qt::GestureCanceled:
iren->InvokeEvent(vtkCommand::EndPinchEvent, e2);
break;
case Qt::GestureStarted:
iren->InvokeEvent(vtkCommand::StartPinchEvent, e2);
iren->InvokeEvent(vtkCommand::PinchEvent, e2);
break;
default:
iren->InvokeEvent(vtkCommand::PinchEvent, e2);
}
iren->SetRotation(-1.0 * pinch->lastRotationAngle());
iren->SetRotation(-1.0 * pinch->rotationAngle());
switch (pinch->state())
{
case Qt::GestureFinished:
case Qt::GestureCanceled:
iren->InvokeEvent(vtkCommand::EndRotateEvent, e2);
break;
case Qt::GestureStarted:
iren->InvokeEvent(vtkCommand::StartRotateEvent, e2);
iren->InvokeEvent(vtkCommand::RotateEvent, e2);
break;
default:
iren->InvokeEvent(vtkCommand::RotateEvent, e2);
}
}
if (QPanGesture* pan = static_cast<QPanGesture*>(e2->gesture(Qt::PanGesture)))
{
e2->accept(Qt::PanGesture);
QPointF delta = pan->delta();
double translation[2] = { (delta.x() * this->DevicePixelRatio +
QVTKInteractorAdapter::DevicePixelRatioTolerance),
-(delta.y() * this->DevicePixelRatio + QVTKInteractorAdapter::DevicePixelRatioTolerance) };
iren->SetTranslation(translation);
switch (pan->state())
{
case Qt::GestureFinished:
case Qt::GestureCanceled:
iren->InvokeEvent(vtkCommand::EndPanEvent, e2);
break;
case Qt::GestureStarted:
iren->InvokeEvent(vtkCommand::StartPanEvent, e2);
iren->InvokeEvent(vtkCommand::PanEvent, e2);
break;
default:
iren->InvokeEvent(vtkCommand::PanEvent, e2);
}
}
if (QTapGesture* tap = static_cast<QTapGesture*>(e2->gesture(Qt::TapGesture)))
{
e2->accept(Qt::TapGesture);
QPointF position = tap->position().toPoint();
iren->SetEventInformationFlipY(static_cast<int>(position.x() * this->DevicePixelRatio +
QVTKInteractorAdapter::DevicePixelRatioTolerance),
static_cast<int>(position.y() * this->DevicePixelRatio +
QVTKInteractorAdapter::DevicePixelRatioTolerance));
if (tap->state() == Qt::GestureStarted)
{
iren->InvokeEvent(vtkCommand::TapEvent, e2);
}
}
if (QTapAndHoldGesture* tapAndHold =
static_cast<QTapAndHoldGesture*>(e2->gesture(Qt::TapAndHoldGesture)))
{
e2->accept(Qt::TapAndHoldGesture);
QPointF position = tapAndHold->position().toPoint();
QWidget* widget = qobject_cast<QWidget*>(this->parent());
if (widget)
{
position = widget->mapFromGlobal(tapAndHold->position().toPoint());
}
else
{
// TapAndHold gesture position is in global coordinates, but could not find a widget to
// convert to local coordinates QVTKInteractorAdapter parent is not set in
// QVTKRenderWindowAdapter. Gesture coordinate mapping may be incorrect.
qWarning("Could not find parent widget. Gesture coordinate mapping may be incorrect");
}
iren->SetEventInformationFlipY(static_cast<int>(position.x() * this->DevicePixelRatio +
QVTKInteractorAdapter::DevicePixelRatioTolerance),
static_cast<int>(position.y() * this->DevicePixelRatio +
QVTKInteractorAdapter::DevicePixelRatioTolerance));
if (tapAndHold->state() == Qt::GestureStarted)
{
iren->InvokeEvent(vtkCommand::LongTapEvent, e2);
}
}
iren->SetEventPosition(eventPosition);
iren->SetLastEventPosition(lastEventPosition);
return true;
}
return false;
}
Did I understand everything correctly?