Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquick3dxrvirtualmouse.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
6
7#include <QtQuick3D/private/qquick3dnode_p.h>
8#include <QtGui/QMouseEvent>
9
11
12/*!
13 \qmltype XrVirtualMouse
14 \inherits Item
15 \inqmlmodule QtQuick3D.Xr
16 \brief Maps 3D controller input to mouse input in 2D items.
17
18 The XrVirtualMouse provides a way to interact with \l{Qt Quick 3D Scenes with 2D Content}{2D user interfaces}
19 in the 3D scene.
20
21 It is typically used like this:
22
23 \qml
24 // XrView { id: xrView
25 // XrController { id: rightController
26 XrInputAction {
27 id: rightTrigger
28 hand: XrInputAction.RightHand
29 actionId: [XrInputAction.TriggerPressed, XrInputAction.TriggerValue]
30 }
31 XrVirtualMouse {
32 view: xrView
33 source: rightController
34 leftMouseButton: rightTrigger.pressed
35 }
36 \endqml
37*/
38
40{
41 m_scrollTimer = new QTimer(this);
42 m_scrollTimer->setInterval(m_scrollTimerInterval);
43 connect(m_scrollTimer, SIGNAL(timeout()), this, SLOT(generateWheelEvent()));
44}
45
46/*!
47 \qmlproperty bool XrVirtualMouse::rightMouseButton
48 \brief Sets the state of the right mouse button.
49
50 When set to true, the right mouse button is pressed.
51*/
52
54{
55 return m_rightMouseButton;
56}
57
58/*!
59 \qmlproperty bool XrVirtualMouse::leftMouseButton
60 \brief Sets the state of the left mouse button.
61
62 When set to true, the left mouse button is pressed.
63*/
64
66{
67 return m_leftMouseButton;
68}
69
70/*!
71 \qmlproperty bool XrVirtualMouse::middleMouseButton
72 \brief Sets the state of the middle mouse button.
73
74 When set to true, the middle mouse button is pressed.
75*/
76
78{
79 return m_middleMouseButton;
80}
81
82/*!
83 \qmlproperty float XrVirtualMouse::scrollWheelX
84 \brief Sets the horizontal scrolling speed.
85
86 Positive values scroll right and negative values scroll left.
87 Scroll speed increases relative to distance from zero.
88
89 \sa scrollPixelDelta
90*/
91
93{
94 return m_scrollWheelX;
95}
96
97/*!
98 \qmlproperty float XrVirtualMouse::scrollWheelY
99 \brief Sets the vertical scrolling speed.
100
101 Positive values scroll up and negative values scroll down.
102 Scroll speed increases relative to distance from zero.
103
104 \sa scrollPixelDelta
105*/
106
108{
109 return m_scrollWheelY;
110}
111
112/*!
113 \qmlproperty int XrVirtualMouse::scrollTimerInterval
114 \brief Defines time in milliseconds between scrolling events sent to the system.
115 \default 30
116*/
117
119{
120 return m_scrollTimerInterval;
121}
122
123/*!
124 \qmlproperty float XrVirtualMouse::scrollPixelDelta
125 \brief Defines the base distance scrolled with each scrolling event.
126 \default 15
127
128 This is the distance scrolled when the scrolling speed is 1.
129
130 \sa scrollWheelX, scrollWheelY
131*/
132
134{
135 return m_scrollPixelDelta;
136}
137
138/*!
139 \qmlproperty Node XrVirtualMouse::source
140 \brief The 3D node controlling the virtual mouse.
141
142 The \c source property is normally set to an \l XrController. Mouse events
143 are generated for the position where the \l{QtQuick3D::Node::forward}{forward vector} of
144 the \c source node intersects with a 2D item.
145*/
146
147QQuick3DNode *QQuick3DXrVirtualMouse::source() const
148{
149 return m_source;
150}
151
152/*!
153 \qmlproperty XrView XrVirtualMouse::view
154 \brief The XR view associated with the virtual mouse.
155 Holds the view in which the virtual mouse operates.
156*/
157
158QQuick3DXrView *QQuick3DXrVirtualMouse::view() const
159{
160 return m_view;
161}
162
163/*!
164 \qmlproperty bool XrVirtualMouse::enabled
165 \brief Indicates whether the virtual mouse is enabled.
166 When true, the virtual mouse sends mouse events to 2D objects in the scene.
167*/
168
170{
171 return m_enabled;
172}
173
174void QQuick3DXrVirtualMouse::setRightMouseButton(bool rightMouseButton)
175{
176 if (m_rightMouseButton == rightMouseButton)
177 return;
178
179 m_rightMouseButton = rightMouseButton;
180 emit rightMouseButtonChanged(m_rightMouseButton);
181 if (m_rightMouseButton) {
182 // Press
183 generateEvent(QEvent::MouseButtonPress, Qt::RightButton);
184 } else {
185 // Release
186 generateEvent(QEvent::MouseButtonRelease, Qt::RightButton);
187 }
188}
189
191{
192 if (m_leftMouseButton == leftMouseButton)
193 return;
194
195 m_leftMouseButton = leftMouseButton;
196 emit leftMouseButtonChanged(m_leftMouseButton);
197 if (m_leftMouseButton) {
198 // Press
199 generateEvent(QEvent::MouseButtonPress, Qt::LeftButton);
200 } else {
201 // Release
202 generateEvent(QEvent::MouseButtonRelease, Qt::LeftButton);
203 }
204}
205
206void QQuick3DXrVirtualMouse::setMiddleMouseButton(bool middleMouseButton)
207{
208 if (m_middleMouseButton == middleMouseButton)
209 return;
210
211 m_middleMouseButton = middleMouseButton;
212 emit middleMouseButtonChanged(m_middleMouseButton);
213 if (m_middleMouseButton) {
214 // Press
215 generateEvent(QEvent::MouseButtonPress, Qt::MiddleButton);
216 } else {
217 // Release
218 generateEvent(QEvent::MouseButtonRelease, Qt::MiddleButton);
219 }
220}
221
223{
224 if (m_scrollWheelX == scrollWheelX)
225 return;
226
227 m_scrollWheelX = scrollWheelX;
228 emit scrollWheelXChanged(m_scrollWheelX);
229 if ((m_scrollTimer->isActive()) && (m_scrollWheelX == 0)) {
230 m_scrollTimer->stop();
231 } else if (!m_scrollTimer->isActive()) {
232 m_scrollTimer->start();
233 }
234}
235
237{
238 if (m_scrollWheelY == scrollWheelY)
239 return;
240
241 m_scrollWheelY = scrollWheelY;
242 emit scrollWheelYChanged(m_scrollWheelY);
243 if ((m_scrollTimer->isActive()) && (m_scrollWheelY == 0)) {
244 m_scrollTimer->stop();
245 } else if (!m_scrollTimer->isActive()) {
246 m_scrollTimer->start();
247 }
248}
249
250void QQuick3DXrVirtualMouse::setScrollTimerInterval(int scrollTimerInterval)
251{
252 if (m_scrollTimerInterval == scrollTimerInterval)
253 return;
254
255 m_scrollTimerInterval = scrollTimerInterval;
256 m_scrollTimer->setInterval(m_scrollTimerInterval);
257
258 emit scrollTimerIntervalChanged(m_scrollTimerInterval);
259}
260
262{
263 if (m_scrollPixelDelta == scrollPixelDelta)
264 return;
265
266 m_scrollPixelDelta = scrollPixelDelta;
267
268 emit scrollPixelDeltaChanged(m_scrollPixelDelta);
269}
270
271void QQuick3DXrVirtualMouse::setSource(QQuick3DNode *source)
272{
273 if (m_source == source)
274 return;
275
276 if (!source)
277 disconnect(m_source, &QQuick3DNode::sceneTransformChanged, this, &QQuick3DXrVirtualMouse::moveEvent);
278
279 m_source = source;
280 emit sourceChanged(m_source);
281
282 if (m_source)
283 connect(m_source, &QQuick3DNode::sceneTransformChanged, this, &QQuick3DXrVirtualMouse::moveEvent);
284}
285
286void QQuick3DXrVirtualMouse::setView(QQuick3DXrView *view)
287{
288 if (m_view == view)
289 return;
290
291 m_view = view;
292 emit viewChanged(m_view);
293}
294
296{
297 if (m_enabled == enabled)
298 return;
299 m_enabled = enabled;
300 emit enabledChanged(m_enabled);
301
302 // Generate mouse release event if we disable when pressed
303 if (!m_enabled && (m_leftMouseButton || m_rightMouseButton || m_middleMouseButton)) {
304 Qt::MouseButton button = m_leftMouseButton ? Qt::LeftButton : m_rightMouseButton ? Qt::RightButton : Qt::MiddleButton;
305 m_leftMouseButton = m_rightMouseButton = m_middleMouseButton = false;
306 generateEvent(QEvent::MouseButtonRelease, button);
307 }
308}
309
310void QQuick3DXrVirtualMouse::moveEvent()
311{
312 generateEvent(QEvent::MouseMove, Qt::NoButton);
313}
314
315void QQuick3DXrVirtualMouse::generateWheelEvent()
316{
317 if (!m_view || !m_source || m_view->m_inDestructor || !m_enabled)
318 return;
319
320 // Get Ray
321 const QVector3D origin = m_source->scenePosition();
322 const QVector3D direction = m_source->forward();
323
324 float x = 0;
325 float y = 0;
326
327 if (m_scrollWheelX > 0) {
328 x = m_scrollPixelDelta * m_scrollWheelX * m_scrollWheelX;
329 } else if (m_scrollWheelX < 0) {
330 x = -m_scrollPixelDelta * m_scrollWheelX * m_scrollWheelX;
331 }
332
333 if (m_scrollWheelY > 0) {
334 y = m_scrollPixelDelta * m_scrollWheelY * m_scrollWheelY;
335 } else if (m_scrollWheelY < 0) {
336 y = -m_scrollPixelDelta * m_scrollWheelY * m_scrollWheelY;
337 }
338
339 QPoint pixelDelta = QPoint(x, y);
340 QPoint angleDelta = QPoint(x*8, y*8);
341
342 // Position will be generated by QtQuick3D
343 QWheelEvent *event = new QWheelEvent(QPointF(), QPointF(), pixelDelta, angleDelta,
344 Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
345
346 // Send to View with Ray
347 if (m_view->view3d()) // no internal view3D if XrView init failed but the object is still alive, handle this gracefully
348 m_view->view3d()->singlePointPick(event, origin, direction);
349
350 // Cleanup
351 delete event;
352}
353
354void QQuick3DXrVirtualMouse::generateEvent(QEvent::Type type, Qt::MouseButton button)
355{
356 if (!m_view || !m_source || m_view->m_inDestructor || !m_enabled)
357 return;
358
359 // Get Ray
360 const QVector3D origin = m_source->scenePosition();
361 const QVector3D direction = m_source->forward();
362
363 // Generate Pointer Event
364 Qt::MouseButtons buttons = Qt::NoButton;
365 if (m_leftMouseButton)
366 buttons |= Qt::LeftButton;
367 if (m_rightMouseButton)
368 buttons |= Qt::RightButton;
369 if (m_middleMouseButton)
370 buttons |= Qt::MiddleButton;
371
372 // Position will be generated by QtQuick3D
373 QMouseEvent *event = new QMouseEvent(type, QPointF(), QPointF(), button, buttons, Qt::NoModifier);
374
375 // Send to View with Ray
376 if (m_view->view3d()) // no internal view3D if XrView init failed but the object is still alive, handle this gracefully
377 m_view->view3d()->singlePointPick(event, origin, direction);
378
379 // Cleanup
380 delete event;
381}
382
383QT_END_NAMESPACE
QObject * parent
Definition qobject.h:73
\inmodule QtCore
Definition qobject.h:103
bool middleMouseButton() const
\qmlproperty bool XrVirtualMouse::middleMouseButton
QQuick3DXrView * view() const
\qmlproperty XrView XrVirtualMouse::view
float scrollWheelY() const
\qmlproperty float XrVirtualMouse::scrollWheelY
void setScrollWheelY(float scrollWheelY)
void setScrollWheelX(float scrollWheelX)
void setView(QQuick3DXrView *view)
float scrollWheelX() const
\qmlproperty float XrVirtualMouse::scrollWheelX
int scrollPixelDelta() const
\qmlproperty float XrVirtualMouse::scrollPixelDelta
bool rightMouseButton() const
\qmlproperty bool XrVirtualMouse::rightMouseButton
void setScrollTimerInterval(int scrollTimerInterval)
QQuick3DNode * source() const
\qmlproperty Node XrVirtualMouse::source
void setScrollPixelDelta(int scrollPixelDelta)
bool leftMouseButton() const
\qmlproperty bool XrVirtualMouse::leftMouseButton
void setMiddleMouseButton(bool middleMouseButton)
bool enabled() const
\qmlproperty bool XrVirtualMouse::enabled
int scrollTimerInterval() const
\qmlproperty int XrVirtualMouse::scrollTimerInterval
void setSource(QQuick3DNode *source)
void setLeftMouseButton(bool leftMouseButton)
Combined button and popup list for selecting options.