Overte C++ Documentation
Overlays.h
1 //
2 // Overlays.h
3 // interface/src/ui/overlays
4 //
5 // Modified by Zander Otavka on 7/15/15
6 // Copyright 2014 High Fidelity, Inc.
7 // Copyright 2023 Overte e.V.
8 //
9 // Distributed under the Apache License, Version 2.0.
10 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
11 // SPDX-License-Identifier: Apache-2.0
12 //
13 // Exposes methods to scripts for managing `Overlay`s and `OverlayPanel`s.
14 //
15 // YOU SHOULD NOT USE `Overlays` DIRECTLY, unless you like pain and deprecation. Instead, use
16 // the object oriented API replacement found in `examples/libraries/overlayManager.js`. See
17 // that file for docs and usage.
18 //
19 
20 #ifndef hifi_Overlays_h
21 #define hifi_Overlays_h
22 
23 #include <QMouseEvent>
24 #include <QReadWriteLock>
25 
26 #include <PointerEvent.h>
27 #include <ScriptValue.h>
28 
29 #include "Overlay.h"
30 
31 #include <EntityScriptingInterface.h>
32 
33 class PickRay;
34 class ScriptEngine;
35 
36 /*@jsdoc
37  * The result of a {@link PickRay} search using {@link Overlays.findRayIntersection|findRayIntersection}.
38  * @typedef {object} Overlays.RayToOverlayIntersectionResult
39  * @property {boolean} intersects - <code>true</code> if the {@link PickRay} intersected with a 3D overlay, otherwise
40  * <code>false</code>.
41  * @property {Uuid} overlayID - The UUID of the local entity that was intersected.
42  * @property {number} distance - The distance from the {@link PickRay} origin to the intersection point.
43  * @property {Vec3} surfaceNormal - The normal of the overlay surface at the intersection point.
44  * @property {Vec3} intersection - The position of the intersection point.
45  * @property {object} extraInfo Additional intersection details, if available.
46  */
47 class RayToOverlayIntersectionResult {
48 public:
49  bool intersects { false };
50  QUuid overlayID;
51  float distance { 0.0f };
52  BoxFace face { UNKNOWN_FACE };
53  glm::vec3 surfaceNormal;
54  glm::vec3 intersection;
55  QVariantMap extraInfo;
56 };
57 Q_DECLARE_METATYPE(RayToOverlayIntersectionResult);
58 ScriptValue RayToOverlayIntersectionResultToScriptValue(ScriptEngine* engine, const RayToOverlayIntersectionResult& value);
59 bool RayToOverlayIntersectionResultFromScriptValue(const ScriptValue& object, RayToOverlayIntersectionResult& value);
60 
61 class ParabolaToOverlayIntersectionResult {
62 public:
63  bool intersects { false };
64  QUuid overlayID;
65  float distance { 0.0f };
66  float parabolicDistance { 0.0f };
67  BoxFace face { UNKNOWN_FACE };
68  glm::vec3 surfaceNormal;
69  glm::vec3 intersection;
70  QVariantMap extraInfo;
71 };
72 
73 /*@jsdoc
74  * The <code>Overlays</code> API provides facilities to create and interact with overlays. These are 2D and 3D objects visible
75  * only to yourself and that aren't persisted to the domain. They are used for UI.
76  *
77  * <p><strong>Note:</strong> 3D overlays are local {@link Entities}, internally, so many of the methods also work with
78  * entities.</p>
79  *
80  * @namespace Overlays
81  *
82  * @hifi-interface
83  * @hifi-client-entity
84  * @hifi-avatar
85  *
86  * @property {Uuid} keyboardFocusOverlay - The <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay
87  * ({@link Entities.EntityProperties-Web|Web} entity) that has keyboard focus. If no overlay (entity) has keyboard focus,
88  * returns <code>null</code>; set to <code>null</code> or {@link Uuid(0)|Uuid.NULL} to clear keyboard focus.
89  */
90 
91 class Overlays : public QObject {
92  Q_OBJECT
93 
94  Q_PROPERTY(QUuid keyboardFocusOverlay READ getKeyboardFocusOverlay WRITE setKeyboardFocusOverlay)
95 
96 public:
97  Overlays();
98 
99  void init();
100  void update(float deltatime);
101  void render(RenderArgs* renderArgs);
102 
103  Overlay::Pointer take2DOverlay(const QUuid& id);
104  Overlay::Pointer get2DOverlay(const QUuid& id) const;
105 
107  QUuid addOverlay(Overlay* overlay) { return add2DOverlay(Overlay::Pointer(overlay)); }
108  QUuid add2DOverlay(const Overlay::Pointer& overlay);
109 
110  RayToOverlayIntersectionResult findRayIntersectionVector(const PickRay& ray, bool precisionPicking,
111  const QVector<EntityItemID>& include,
112  const QVector<EntityItemID>& discard,
113  bool visibleOnly = false, bool collidableOnly = false);
114 
115  ParabolaToOverlayIntersectionResult findParabolaIntersectionVector(const PickParabola& parabola, bool precisionPicking,
116  const QVector<EntityItemID>& include,
117  const QVector<EntityItemID>& discard,
118  bool visibleOnly = false, bool collidableOnly = false);
119 
120  void cleanupAllOverlays();
121 
122 public slots:
123  /*@jsdoc
124  * Adds an overlay to the scene.
125  * @function Overlays.addOverlay
126  * @param {Overlays.OverlayType} type - The type of the overlay to add.
127  * @param {Overlays.OverlayProperties} properties - The properties of the overlay to add.
128  * @returns {Uuid} The ID of the newly created overlay if successful, otherwise {@link Uuid(0)|Uuid.NULL}.
129  * @example <caption>Add a cube overlay in front of your avatar.</caption>
130  * var overlay = Overlays.addOverlay("cube", {
131  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
132  * rotation: MyAvatar.orientation,
133  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
134  * solid: true
135  * });
136  */
137  QUuid addOverlay(const QString& type, const QVariant& properties);
138 
139  /*@jsdoc
140  * Creates a clone of an existing overlay (or entity).
141  * <p>Note: For cloning behavior of 3D overlays and entities, see {@link Entities.cloneEntity}.</p>
142  * @function Overlays.cloneOverlay
143  * @param {Uuid} id - The ID of the overlay (or entity) to clone.
144  * @returns {Uuid} The ID of the new overlay (or entity) if successful, otherwise {@link Uuid(0)|Uuid.NULL}.
145  */
146  QUuid cloneOverlay(const QUuid& id);
147 
148  /*@jsdoc
149  * Edits an overlay's (or entity's) properties.
150  * @function Overlays.editOverlay
151  * @param {Uuid} id - The ID of the overlay (or entity) to edit.
152  * @param {Overlays.OverlayProperties} properties - The properties changes to make.
153  * @returns {boolean} <code>false</code> if Interface is exiting. Otherwise, if a 2D overlay then <code>true</code> always,
154  * and if a 3D overlay then <code>true</code> if the overlay was found and edited, otherwise <code>false</code>.
155  * @example <caption>Add an overlay in front of your avatar then change its color.</caption>
156  * var overlay = Overlays.addOverlay("cube", {
157  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
158  * rotation: MyAvatar.orientation,
159  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
160  * solid: true
161  * });
162  *
163  * var success = Overlays.editOverlay(overlay, {
164  * color: { red: 255, green: 0, blue: 0 }
165  * });
166  * print("Success: " + success);
167  */
168  bool editOverlay(const QUuid& id, const QVariant& properties);
169 
170  /*@jsdoc
171  * Edits the properties of multiple overlays (or entities).
172  * @function Overlays.editOverlays
173  * @param propertiesById {object.<Uuid, Overlays.OverlayProperties>} - An object with overlay (or entity) IDs as keys and
174  * {@link Overlays.OverlayProperties|OverlayProperties} edits to make as values.
175  * @returns {boolean} <code>false</code> if Interface is exiting, otherwise <code>true</code>.
176  * @example <caption>Create two overlays in front of your avatar then change their colors.</caption>
177  * var overlayA = Overlays.addOverlay("cube", {
178  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: -0.3, y: 0, z: -3 })),
179  * rotation: MyAvatar.orientation,
180  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
181  * solid: true
182  * });
183  * var overlayB = Overlays.addOverlay("cube", {
184  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0.3, y: 0, z: -3 })),
185  * rotation: MyAvatar.orientation,
186  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
187  * solid: true
188  * });
189  *
190  * var overlayEdits = {};
191  * overlayEdits[overlayA] = { color: { red: 255, green: 0, blue: 0 } };
192  * overlayEdits[overlayB] = { color: { red: 0, green: 255, blue: 0 } };
193  * var success = Overlays.editOverlays(overlayEdits);
194  * print("Success: " + success);
195  */
196  bool editOverlays(const QVariant& propertiesById);
197 
198  /*@jsdoc
199  * Deletes an overlay (or entity).
200  * @function Overlays.deleteOverlay
201  * @param {Uuid} id - The ID of the overlay (or entity) to delete.
202  */
203  void deleteOverlay(const QUuid& id);
204 
205  /*@jsdoc
206  * Gets the type of an overlay.
207  * @function Overlays.getOverlayType
208  * @param {Uuid} id - The ID of the overlay to get the type of.
209  * @returns {Overlays.OverlayType} The type of the overlay if found, otherwise <code>"unknown"</code>.
210  * @example <caption>Create an overlay in front of your avatar then get and report its type.</caption>
211  * var overlay = Overlays.addOverlay("cube", {
212  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
213  * rotation: MyAvatar.orientation,
214  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
215  * solid: true
216  * });
217  * var type = Overlays.getOverlayType(overlay);
218  * print("Type: " + type); // cube
219  */
220  QString getOverlayType(const QUuid& id);
221 
222  /*@jsdoc
223  * Gets an overlay's (or entity's) script object. In particular, this is useful for accessing a
224  * <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay's <code>EventBridge</code> script object to
225  * exchange messages with the web page script.
226  * <p>To send a message from an Interface script to a <code>"web3d"</code> overlay over its event bridge:</p>
227  * <pre class="prettyprint"><code>var overlayObject = Overlays.getOverlayObject(overlayID);
228  * overlayObject.emitScriptEvent(message);</code></pre>
229  * <p>To receive a message from a <code>"web3d"</code> overlay over its event bridge in an Interface script:</p>
230  * <pre class="prettyprint"><code>var overlayObject = Overlays.getOverlayObject(overlayID);
231  * overlayObject.webEventReceived.connect(function(message) {
232  * ...
233  * };</code></pre>
234  * @function Overlays.getOverlayObject
235  * @param {Uuid} overlayID - The ID of the overlay to get the script object of.
236  * @returns {object} The script object for the overlay if found.
237  * @example <caption>Exchange messages with a <code>"web3d"</code> overlay.</caption>
238  * // HTML file, name: "web3d.html".
239  * <!DOCTYPE html>
240  * <html>
241  * <head>
242  * <title>HELLO</title>
243  * </head>
244  * <body>
245  * <h1>HELLO</h1>
246  * <script>
247  * function onScriptEventReceived(message) {
248  * // Message received from the script.
249  * console.log("Message received: " + message);
250  * }
251  *
252  * EventBridge.scriptEventReceived.connect(onScriptEventReceived);
253  *
254  * setInterval(function () {
255  * // Send a message to the script.
256  * EventBridge.emitWebEvent("hello");
257  * }, 2000);
258  * </script>
259  * </body>
260  * </html>
261  *
262  * // Interface script file.
263  * var web3DOverlay = Overlays.addOverlay("web3d", {
264  * type: "Web",
265  * position : Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y : 0.5, z : -3 })),
266  * rotation : MyAvatar.orientation,
267  * sourceUrl : Script.resolvePath("web3d.html"),
268  * alpha : 1.0
269  * });
270  *
271  * var overlayObject;
272  *
273  * function onWebEventReceived(message) {
274  * // Message received.
275  * print("Message received: " + message);
276  *
277  * // Send a message back.
278  * overlayObject.emitScriptEvent(message + " back");
279  * }
280  *
281  * Script.setTimeout(function() {
282  * overlayObject = Overlays.getOverlayObject(web3DOverlay);
283  * overlayObject.webEventReceived.connect(onWebEventReceived);
284  * }, 500);
285  *
286  * Script.scriptEnding.connect(function() {
287  * Overlays.deleteOverlay(web3DOverlay);
288  * });
289  */
290  QObject* getOverlayObject(const QUuid& id);
291 
292  /*@jsdoc
293  * Gets the ID of the 2D overlay at a particular point on the desktop screen or HUD surface.
294  * @function Overlays.getOverlayAtPoint
295  * @param {Vec2} point - The point to check for an overlay.
296  * @returns {Uuid} The ID of the 2D overlay at the specified point if found, otherwise <code>null</code>.
297  * @example <caption>Create a 2D overlay and add an event function that reports the overlay clicked on, if any.</caption>
298  * var overlay = Overlays.addOverlay("rectangle", {
299  * bounds: { x: 100, y: 100, width: 200, height: 100 },
300  * color: { red: 255, green: 255, blue: 255 }
301  * });
302  * print("Created: " + overlay);
303  *
304  * Controller.mousePressEvent.connect(function (event) {
305  * var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
306  * print("Clicked: " + overlay);
307  * });
308  */
309  QUuid getOverlayAtPoint(const glm::vec2& point);
310 
311  /*@jsdoc
312  * Finds the closest 3D overlay (or local entity) intersected by a {@link PickRay}.
313  * @function Overlays.findRayIntersection
314  * @param {PickRay} pickRay - The PickRay to use for finding overlays.
315  * @param {boolean} [precisionPicking=false] - <code>true</code> to pick against precise meshes, <code>false</code> to pick
316  * against coarse meshes. If <code>true</code> and the intersected entity is a model, the result's
317  * <code>extraInfo</code> property includes more information than it otherwise would.
318  * @param {Array.<Uuid>} [include=[]] - If not empty, then the search is restricted to these overlays (and local entities).
319  * @param {Array.<Uuid>} [discard=[]] - Overlays (and local entities) to ignore during the search.
320  * @param {boolean} [visibleOnly=false] - <code>true</code> if only overlays (and local entities) that are
321  * <code>{@link Overlays.OverlayProperties|visible}</code> should be searched.
322  * @param {boolean} [collideableOnly=false] - <code>true</code> if only local entities that are not
323  * <code>{@link Entities.EntityProperties|collisionless}</code> should be searched.
324  * @returns {Overlays.RayToOverlayIntersectionResult} The result of the search for the first intersected overlay (or local
325  * entity.
326  * @example <caption>Create a cube overlay in front of your avatar. Report 3D overlay intersection details for mouse
327  * clicks.</caption>
328  * var overlay = Overlays.addOverlay("cube", {
329  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
330  * rotation: MyAvatar.orientation,
331  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
332  * solid: true
333  * });
334  *
335  * Controller.mousePressEvent.connect(function (event) {
336  * var pickRay = Camera.computePickRay(event.x, event.y);
337  * var intersection = Overlays.findRayIntersection(pickRay);
338  * print("Intersection: " + JSON.stringify(intersection));
339  * });
340  */
341  RayToOverlayIntersectionResult findRayIntersection(const PickRay& ray,
342  bool precisionPicking = false,
343  const ScriptValue& include = ScriptValue(),
344  const ScriptValue& discard = ScriptValue(),
345  bool visibleOnly = false,
346  bool collidableOnly = false);
347 
348  /*@jsdoc
349  * Gets a list of visible 3D overlays (local entities) with bounding boxes that touch a search sphere.
350  * @function Overlays.findOverlays
351  * @param {Vec3} center - The center of the search sphere.
352  * @param {number} radius - The radius of the search sphere.
353  * @returns {Uuid[]} The IDs of the overlays (local entities) that are visible and have bounding boxes that touch a search
354  * sphere.
355  * @example <caption>Create two overlays in front of your avatar then search for overlays near your avatar.</caption>
356  * var overlayA = Overlays.addOverlay("cube", {
357  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: -0.3, y: 0, z: -3 })),
358  * rotation: MyAvatar.orientation,
359  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
360  * solid: true
361  * });
362  * print("Overlay A: " + overlayA);
363  * var overlayB = Overlays.addOverlay("cube", {
364  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0.3, y: 0, z: -3 })),
365  * rotation: MyAvatar.orientation,
366  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
367  * solid: true
368  * });
369  * print("Overlay B: " + overlayB);
370  *
371  * var overlaysFound = Overlays.findOverlays(MyAvatar.position, 5.0);
372  * print("Overlays found: " + JSON.stringify(overlaysFound));
373  */
374  QVector<QUuid> findOverlays(const glm::vec3& center, float radius);
375 
376  /*@jsdoc
377  * Checks whether an overlay's (or entity's) assets have been loaded. For example, for an
378  * <code>{@link Overlays.OverlayProperties-Image|"image"}</code> overlay, the result indicates whether its image has been
379  * loaded.
380  * @function Overlays.isLoaded
381  * @param {Uuid} id - The ID of the overlay (or entity) to check.
382  * @returns {boolean} <code>true</code> if the overlay's (or entity's) assets have been loaded, otherwise
383  * <code>false</code>.
384  * @example <caption>Create an image overlay and report whether its image is loaded after 1s.</caption>
385  * var overlay = Overlays.addOverlay("image", {
386  * bounds: { x: 100, y: 100, width: 200, height: 200 },
387  * imageURL: "https://content.overte.org/Bazaar/Assets/Textures/Defaults/Interface/default_particle.png"
388  * });
389  * Script.setTimeout(function () {
390  * var isLoaded = Overlays.isLoaded(overlay);
391  * print("Image loaded: " + isLoaded);
392  * }, 1000);
393  */
394  bool isLoaded(const QUuid& id);
395 
396  /*@jsdoc
397  * Calculates the size of some text in a text overlay (or entity). The overlay (or entity) need not be set visible.
398  * <p><strong>Note:</strong> The size of text in a 3D overlay (or entity) cannot be calculated immediately after the
399  * overlay (or entity) is created; a short delay is required while the overlay (or entity) finishes being created.</p>
400  * @function Overlays.textSize
401  * @param {Uuid} id - The ID of the overlay (or entity) to use for calculation.
402  * @param {string} text - The string to calculate the size of.
403  * @returns {Size} The size of the <code>text</code> if the object is a text overlay (or entity), otherwise
404  * <code>{ height: 0, width : 0 }</code>. If the object is a 2D overlay, the size is in pixels; if the object is a 3D
405  * overlay (or entity), the size is in meters.
406  * @example <caption>Calculate the size of "hello" in a 3D text entity.</caption>
407  * var overlay = Overlays.addOverlay("text3d", {
408  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -2 })),
409  * rotation: MyAvatar.orientation,
410  * lineHeight: 0.2,
411  * visible: false
412  * });
413  *
414  * Script.setTimeout(function() {
415  * var textSize = Overlays.textSize(overlay, "hello");
416  * print("Size of \"hello\": " + JSON.stringify(textSize));
417  * }, 500);
418  */
419  QSizeF textSize(const QUuid& id, const QString& text);
420 
421  /*@jsdoc
422  * Gets the width of the Interface window or HUD surface.
423  * @function Overlays.width
424  * @returns {number} The width, in pixels, of the Interface window if in desktop mode or the HUD surface if in HMD mode.
425  */
426  float width();
427 
428  /*@jsdoc
429  * Gets the height of the Interface window or HUD surface.
430  * @function Overlays.height
431  * @returns {number} The height, in pixels, of the Interface window if in desktop mode or the HUD surface if in HMD mode.
432  */
433  float height();
434 
435  /*@jsdoc
436  * Checks if an overlay (or entity) exists.
437  * @function Overlays.isAddedOverlay
438  * @param {Uuid} id - The ID of the overlay (or entity) to check.
439  * @returns {boolean} <code>true</code> if an overlay (or entity) with the given ID exists, <code>false</code> if it doesn't.
440  */
441  bool isAddedOverlay(const QUuid& id);
442 
443  /*@jsdoc
444  * Generates a mouse press event on an overlay (or local entity).
445  * @function Overlays.sendMousePressOnOverlay
446  * @param {Uuid} id - The ID of the overlay (or local entity) to generate a mouse press event on.
447  * @param {PointerEvent} event - The mouse press event details.
448  * @example <caption>Create a 2D rectangle overlay plus a 3D cube overlay and generate mousePressOnOverlay events for the
449  * 2D overlay.</caption>
450  * var overlay3D = Overlays.addOverlay("cube", {
451  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
452  * rotation: MyAvatar.orientation,
453  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
454  * solid: true
455  * });
456  * print("3D overlay: " + overlay);
457  *
458  * var overlay2D = Overlays.addOverlay("rectangle", {
459  * bounds: { x: 100, y: 100, width: 200, height: 100 },
460  * color: { red: 255, green: 255, blue: 255 }
461  * });
462  * print("2D overlay: " + overlay);
463  *
464  * // Overlays.mousePressOnOverlay by default applies only to 3D overlays.
465  * Overlays.mousePressOnOverlay.connect(function(overlayID, event) {
466  * print("Clicked: " + overlayID);
467  * });
468  *
469  * Controller.mousePressEvent.connect(function (event) {
470  * // Overlays.getOverlayAtPoint applies only to 2D overlays.
471  * var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
472  * if (overlay) {
473  * Overlays.sendMousePressOnOverlay(overlay, {
474  * type: "press",
475  * id: 0,
476  * pos2D: event
477  * });
478  * }
479  * });
480  */
481  void sendMousePressOnOverlay(const QUuid& id, const PointerEvent& event);
482 
483  /*@jsdoc
484  * Generates a mouse release event on an overlay (or local entity).
485  * @function Overlays.sendMouseReleaseOnOverlay
486  * @param {Uuid} id - The ID of the overlay (or local entity) to generate a mouse release event on.
487  * @param {PointerEvent} event - The mouse release event details.
488  */
489  void sendMouseReleaseOnOverlay(const QUuid& id, const PointerEvent& event);
490 
491  /*@jsdoc
492  * Generates a mouse move event on an overlay (or local entity).
493  * @function Overlays.sendMouseMoveOnOverlay
494  * @param {Uuid} id - The ID of the overlay (or local entity) to generate a mouse move event on.
495  * @param {PointerEvent} event - The mouse move event details.
496  */
497  void sendMouseMoveOnOverlay(const QUuid& id, const PointerEvent& event);
498 
499  /*@jsdoc
500  * Generates a hover enter event on an overlay (or local entity).
501  * @function Overlays.sendHoverEnterOverlay
502  * @param {Uuid} id - The ID of the overlay (or local entity) to generate a hover enter event on.
503  * @param {PointerEvent} event - The hover enter event details.
504  */
505  void sendHoverEnterOverlay(const QUuid& id, const PointerEvent& event);
506 
507  /*@jsdoc
508  * Generates a hover over event on an overlay (or entity).
509  * @function Overlays.sendHoverOverOverlay
510  * @param {Uuid} id - The ID of the overlay (or local entity) to generate a hover over event on.
511  * @param {PointerEvent} event - The hover over event details.
512  */
513  void sendHoverOverOverlay(const QUuid& id, const PointerEvent& event);
514 
515  /*@jsdoc
516  * Generates a hover leave event on an overlay (or local entity).
517  * @function Overlays.sendHoverLeaveOverlay
518  * @param {Uuid} id - The ID of the overlay (or local entity) to generate a hover leave event on.
519  * @param {PointerEvent} event - The hover leave event details.
520  */
521  void sendHoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
522 
523  /*@jsdoc
524  * Gets the ID of the <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay
525  * ({@link Entities.EntityProperties-Web|Web} entity) that has keyboard focus.
526  * @function Overlays.getKeyboardFocusOverlay
527  * @returns {Uuid} The ID of the <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay
528  * ({@link Entities.EntityProperties-Web|Web} entity) that has focus, if any, otherwise <code>null</code>.
529  */
530  QUuid getKeyboardFocusOverlay() { return DependencyManager::get<EntityScriptingInterface>()->getKeyboardFocusEntity(); }
531 
532  /*@jsdoc
533  * Sets the <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay
534  * ({@link Entities.EntityProperties-Web|Web} entity) that has keyboard focus.
535  * @function Overlays.setKeyboardFocusOverlay
536  * @param {Uuid} id - The ID of the <code>{@link Overlays.OverlayProperties-Web3D|"web3d"}</code> overlay
537  * ({@link Entities.EntityProperties-Web|Web} entity) to set keyboard focus to. Use <code>null</code> or
538  * {@link Uuid(0)|Uuid.NULL} to unset keyboard focus from an overlay (entity).
539  */
540  void setKeyboardFocusOverlay(const QUuid& id) { DependencyManager::get<EntityScriptingInterface>()->setKeyboardFocusEntity(id); }
541 
542 signals:
543  /*@jsdoc
544  * Triggered when an overlay (or entity) is deleted.
545  * @function Overlays.overlayDeleted
546  * @param {Uuid} id - The ID of the overlay (or entity) that was deleted.
547  * @returns {Signal}
548  * @example <caption>Create an overlay then delete it after 1s.</caption>
549  * var overlay = Overlays.addOverlay("cube", {
550  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
551  * rotation: MyAvatar.orientation,
552  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
553  * solid: true
554  * });
555  * print("Overlay: " + overlay);
556  *
557  * Overlays.overlayDeleted.connect(function(overlayID) {
558  * print("Deleted: " + overlayID);
559  * });
560  * Script.setTimeout(function () {
561  * Overlays.deleteOverlay(overlay);
562  * }, 1000);
563  */
564  void overlayDeleted(const QUuid& id);
565 
566  /*@jsdoc
567  * Triggered when a mouse press event occurs on an overlay. Only occurs for 3D overlays (unless you use
568  * {@link Overlays.sendMousePressOnOverlay|sendMousePressOnOverlay} for a 2D overlay).
569  * @function Overlays.mousePressOnOverlay
570  * @param {Uuid} id - The ID of the overlay the mouse press event occurred on.
571  * @param {PointerEvent} event - The mouse press event details.
572  * @returns {Signal}
573  * @example <caption>Create a cube overlay in front of your avatar and report mouse clicks on it.</caption>
574  * var overlay = Overlays.addOverlay("cube", {
575  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
576  * rotation: MyAvatar.orientation,
577  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
578  * solid: true
579  * });
580  * print("My overlay: " + overlay);
581  *
582  * Overlays.mousePressOnOverlay.connect(function(overlayID, event) {
583  * if (overlayID === overlay) {
584  * print("Clicked on my overlay");
585  * }
586  * });
587  */
588  void mousePressOnOverlay(const QUuid& id, const PointerEvent& event);
589 
590  /*@jsdoc
591  * Triggered when a mouse double press event occurs on an overlay. Only occurs for 3D overlays.
592  * @function Overlays.mouseDoublePressOnOverlay
593  * @param {Uuid} id - The ID of the overlay the mouse double press event occurred on.
594  * @param {PointerEvent} event - The mouse double press event details.
595  * @returns {Signal}
596  */
597  void mouseDoublePressOnOverlay(const QUuid& id, const PointerEvent& event);
598 
599  /*@jsdoc
600  * Triggered when a mouse release event occurs on an overlay. Only occurs for 3D overlays (unless you use
601  * {@link Overlays.sendMouseReleaseOnOverlay|sendMouseReleaseOnOverlay} for a 2D overlay).
602  * @function Overlays.mouseReleaseOnOverlay
603  * @param {Uuid} id - The ID of the overlay the mouse release event occurred on.
604  * @param {PointerEvent} event - The mouse release event details.
605  * @returns {Signal}
606  */
607  void mouseReleaseOnOverlay(const QUuid& id, const PointerEvent& event);
608 
609  /*@jsdoc
610  * Triggered when a mouse move event occurs on an overlay. Only occurs for 3D overlays (unless you use
611  * {@link Overlays.sendMouseMoveOnOverlay|sendMouseMoveOnOverlay} for a 2D overlay).
612  * @function Overlays.mouseMoveOnOverlay
613  * @param {Uuid} id - The ID of the overlay the mouse moved event occurred on.
614  * @param {PointerEvent} event - The mouse move event details.
615  * @returns {Signal}
616  */
617  void mouseMoveOnOverlay(const QUuid& id, const PointerEvent& event);
618 
619  /*@jsdoc
620  * Triggered when a mouse press event occurs on something other than a 3D overlay.
621  * @function Overlays.mousePressOffOverlay
622  * @returns {Signal}
623  */
624  void mousePressOffOverlay();
625 
626  /*@jsdoc
627  * Triggered when a mouse double press event occurs on something other than a 3D overlay.
628  * @function Overlays.mouseDoublePressOffOverlay
629  * @returns {Signal}
630  */
631  void mouseDoublePressOffOverlay();
632 
633  /*@jsdoc
634  * Triggered when a mouse cursor starts hovering over an overlay. Only occurs for 3D overlays (unless you use
635  * {@link Overlays.sendHoverEnterOverlay|sendHoverEnterOverlay} for a 2D overlay).
636  * @function Overlays.hoverEnterOverlay
637  * @param {Uuid} id - The ID of the overlay the mouse moved event occurred on.
638  * @param {PointerEvent} event - The mouse move event details.
639  * @returns {Signal}
640  * @example <caption>Create a cube overlay in front of your avatar and report when you start hovering your mouse over
641  * it.</caption>
642  * var overlay = Overlays.addOverlay("cube", {
643  * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -3 })),
644  * rotation: MyAvatar.orientation,
645  * dimensions: { x: 0.3, y: 0.3, z: 0.3 },
646  * solid: true
647  * });
648  * print("Overlay: " + overlay);
649  * Overlays.hoverEnterOverlay.connect(function(overlayID, event) {
650  * print("Hover enter: " + overlayID);
651  * });
652  */
653  void hoverEnterOverlay(const QUuid& id, const PointerEvent& event);
654 
655  /*@jsdoc
656  * Triggered when a mouse cursor continues hovering over an overlay. Only occurs for 3D overlays (unless you use
657  * {@link Overlays.sendHoverOverOverlay|sendHoverOverOverlay} for a 2D overlay).
658  * @function Overlays.hoverOverOverlay
659  * @param {Uuid} id - The ID of the overlay the hover over event occurred on.
660  * @param {PointerEvent} event - The hover over event details.
661  * @returns {Signal}
662  */
663  void hoverOverOverlay(const QUuid& id, const PointerEvent& event);
664 
665  /*@jsdoc
666  * Triggered when a mouse cursor finishes hovering over an overlay. Only occurs for 3D overlays (unless you use
667  * {@link Overlays.sendHoverLeaveOverlay|sendHoverLeaveOverlay} for a 2D overlay).
668  * @function Overlays.hoverLeaveOverlay
669  * @param {Uuid} id - The ID of the overlay the hover leave event occurred on.
670  * @param {PointerEvent} event - The hover leave event details.
671  * @returns {Signal}
672  */
673  void hoverLeaveOverlay(const QUuid& id, const PointerEvent& event);
674 
675 private:
676  void cleanupOverlaysToDelete();
677 
678  mutable QRecursiveMutex _mutex;
679  QMap<QUuid, Overlay::Pointer> _overlays;
680  QList<Overlay::Pointer> _overlaysToDelete;
681 
682  unsigned int _stackOrder { 1 };
683 
684  std::atomic<bool> _shuttingDown { false };
685 
686  PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult,
687  QMouseEvent* event, PointerEvent::EventType eventType);
688 
689  static QString entityToOverlayType(const QString& type);
690  static std::unordered_map<QString, QString> _entityToOverlayTypes;
691  static std::unordered_map<QString, QString> _overlayToEntityTypes;
692 
693 private slots:
694  void mousePressOnPointerEvent(const QUuid& id, const PointerEvent& event);
695  void mousePressOffPointerEvent();
696  void mouseDoublePressOnPointerEvent(const QUuid& id, const PointerEvent& event);
697  void mouseDoublePressOffPointerEvent();
698  void mouseReleasePointerEvent(const QUuid& id, const PointerEvent& event);
699  void mouseMovePointerEvent(const QUuid& id, const PointerEvent& event);
700  void hoverEnterPointerEvent(const QUuid& id, const PointerEvent& event);
701  void hoverOverPointerEvent(const QUuid& id, const PointerEvent& event);
702  void hoverLeavePointerEvent(const QUuid& id, const PointerEvent& event);
703 
704 
705 };
706 
707 #define ADD_TYPE_MAP(entity, overlay) \
708  _entityToOverlayTypes[#entity] = #overlay; \
709  _overlayToEntityTypes[#overlay] = #entity;
710 
711 #endif // hifi_Overlays_h
Represents a 2D or 3D pointer to the scripting engine. Exposed as PointerEvent
Definition: PointerEvent.h:30
Provides an engine-independent interface for a scripting engine.
Definition: ScriptEngine.h:93
[ScriptInterface] Provides an engine-independent interface for QScriptValue
Definition: ScriptValue.h:40