Merge pull request #1502 from daleglass/qt5-fix-userdata

Remove deprecated usage of setUserData.
This commit is contained in:
Dale Glass 2022-01-22 20:16:00 +01:00 committed by GitHub
commit ec18f7a528
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 160 additions and 153 deletions

View file

@ -38,14 +38,14 @@
* <p><em>This API currently has no effect and is not used.</em></p> * <p><em>This API currently has no effect and is not used.</em></p>
* *
* @namespace OffscreenFlags * @namespace OffscreenFlags
* *
* @hifi-interface * @hifi-interface
* @hifi-client-entity * @hifi-client-entity
* @hifi-avatar * @hifi-avatar
* *
* @property {boolean} navigationFocused - <code>true</code> if UI has joystick navigation focus, <code>false</code> if it * @property {boolean} navigationFocused - <code>true</code> if UI has joystick navigation focus, <code>false</code> if it
* doesn't. * doesn't.
* @property {boolean} navigationFocusDisabled - <code>true</code> if UI joystick navigation focus is disabled, * @property {boolean} navigationFocusDisabled - <code>true</code> if UI joystick navigation focus is disabled,
* <code>false</code> if it isn't. * <code>false</code> if it isn't.
*/ */
@ -75,7 +75,7 @@ public:
emit navigationFocusDisabledChanged(); emit navigationFocusDisabledChanged();
} }
} }
signals: signals:
/*@jsdoc /*@jsdoc
@ -99,9 +99,9 @@ private:
static OffscreenFlags* offscreenFlags { nullptr }; static OffscreenFlags* offscreenFlags { nullptr };
// This hack allows the QML UI to work with keys that are also bound as // This hack allows the QML UI to work with keys that are also bound as
// shortcuts at the application level. However, it seems as though the // shortcuts at the application level. However, it seems as though the
// bound actions are still getting triggered. At least for backspace. // bound actions are still getting triggered. At least for backspace.
// Not sure why. // Not sure why.
// //
// However, the problem may go away once we switch to the new menu system, // However, the problem may go away once we switch to the new menu system,
@ -168,7 +168,7 @@ void OffscreenUi::onRootContextCreated(QQmlContext* qmlContext) {
qmlContext->setContextProperty("fileDialogHelper", new FileDialogHelper()); qmlContext->setContextProperty("fileDialogHelper", new FileDialogHelper());
#ifdef DEBUG #ifdef DEBUG
qmlContext->setContextProperty("DebugQML", QVariant(true)); qmlContext->setContextProperty("DebugQML", QVariant(true));
#else #else
qmlContext->setContextProperty("DebugQML", QVariant(false)); qmlContext->setContextProperty("DebugQML", QVariant(false));
#endif #endif
@ -284,7 +284,7 @@ QQuickItem* OffscreenUi::createMessageBox(Icon icon, const QString& title, const
map.insert("buttons", buttons.operator int()); map.insert("buttons", buttons.operator int());
map.insert("defaultButton", defaultButton); map.insert("defaultButton", defaultButton);
QVariant result; QVariant result;
bool invokeResult; bool invokeResult = false;
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode() && _desktop) { if (tablet->getToolbarMode() && _desktop) {
@ -309,7 +309,7 @@ int OffscreenUi::waitForMessageBoxResult(QQuickItem* messageBox) {
if (!messageBox) { if (!messageBox) {
return QMessageBox::NoButton; return QMessageBox::NoButton;
} }
return MessageBoxListener(messageBox).waitForButtonResult(); return MessageBoxListener(messageBox).waitForButtonResult();
} }
@ -424,8 +424,8 @@ QString OffscreenUi::getText(const Icon icon, const QString& title, const QStrin
QString OffscreenUi::getItem(const Icon icon, const QString& title, const QString& label, const QStringList& items, QString OffscreenUi::getItem(const Icon icon, const QString& title, const QString& label, const QStringList& items,
int current, bool editable, bool* ok) { int current, bool editable, bool* ok) {
if (ok) { if (ok) {
*ok = false; *ok = false;
} }
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
@ -580,7 +580,7 @@ QQuickItem* OffscreenUi::createInputDialog(const Icon icon, const QString& title
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
bool invokeResult; bool invokeResult = false;
if (tablet->getToolbarMode() && _desktop) { if (tablet->getToolbarMode() && _desktop) {
invokeResult = QMetaObject::invokeMethod(_desktop, "inputDialog", invokeResult = QMetaObject::invokeMethod(_desktop, "inputDialog",
Q_RETURN_ARG(QVariant, result), Q_RETURN_ARG(QVariant, result),
@ -608,7 +608,7 @@ QQuickItem* OffscreenUi::createCustomInputDialog(const Icon icon, const QString&
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
bool invokeResult; bool invokeResult = false;
if (tablet->getToolbarMode() && _desktop) { if (tablet->getToolbarMode() && _desktop) {
invokeResult = QMetaObject::invokeMethod(_desktop, "inputDialog", invokeResult = QMetaObject::invokeMethod(_desktop, "inputDialog",
Q_RETURN_ARG(QVariant, result), Q_RETURN_ARG(QVariant, result),
@ -619,7 +619,7 @@ QQuickItem* OffscreenUi::createCustomInputDialog(const Icon icon, const QString&
Q_ARG(QVariant, QVariant::fromValue(map))); Q_ARG(QVariant, QVariant::fromValue(map)));
emit tabletScriptingInterface->tabletNotification(); emit tabletScriptingInterface->tabletNotification();
} }
if (!invokeResult) { if (!invokeResult) {
qWarning() << "Failed to create custom message box"; qWarning() << "Failed to create custom message box";
return nullptr; return nullptr;
@ -648,13 +648,13 @@ void OffscreenUi::setNavigationFocused(bool focused) {
// FIXME HACK.... // FIXME HACK....
// This hack is an attempt to work around the 'offscreen UI can't gain keyboard focus' bug // This hack is an attempt to work around the 'offscreen UI can't gain keyboard focus' bug
// https://app.asana.com/0/27650181942747/83176475832393 // https://app.asana.com/0/27650181942747/83176475832393
// The problem seems related to https://bugreports.qt.io/browse/QTBUG-50309 // The problem seems related to https://bugreports.qt.io/browse/QTBUG-50309
// //
// The workaround seems to be to give some other window (same process or another process doesn't seem to matter) // The workaround seems to be to give some other window (same process or another process doesn't seem to matter)
// focus and then put focus back on the interface main window. // focus and then put focus back on the interface main window.
// //
// If I could reliably reproduce this bug I could eventually track down what state change is occuring // If I could reliably reproduce this bug I could eventually track down what state change is occuring
// during the process of the main window losing and then gaining focus, but failing that, here's a // during the process of the main window losing and then gaining focus, but failing that, here's a
// brute force way of triggering that state change at application start in a way that should be nearly // brute force way of triggering that state change at application start in a way that should be nearly
// imperceptible to the user. // imperceptible to the user.
class KeyboardFocusHack : public QObject { class KeyboardFocusHack : public QObject {
@ -754,7 +754,7 @@ private slots:
QString OffscreenUi::fileDialog(const QVariantMap& properties) { QString OffscreenUi::fileDialog(const QVariantMap& properties) {
QVariant buildDialogResult; QVariant buildDialogResult;
bool invokeResult; bool invokeResult = false;
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode() && _desktop) { if (tablet->getToolbarMode() && _desktop) {
@ -783,7 +783,7 @@ QString OffscreenUi::fileDialog(const QVariantMap& properties) {
ModalDialogListener* OffscreenUi::fileDialogAsync(const QVariantMap& properties) { ModalDialogListener* OffscreenUi::fileDialogAsync(const QVariantMap& properties) {
QVariant buildDialogResult; QVariant buildDialogResult;
bool invokeResult; bool invokeResult = false;
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode() && _desktop) { if (tablet->getToolbarMode() && _desktop) {
@ -1003,7 +1003,7 @@ class AssetDialogListener : public ModalDialogListener {
QString OffscreenUi::assetDialog(const QVariantMap& properties) { QString OffscreenUi::assetDialog(const QVariantMap& properties) {
// ATP equivalent of fileDialog(). // ATP equivalent of fileDialog().
QVariant buildDialogResult; QVariant buildDialogResult;
bool invokeResult; bool invokeResult = false;
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode() && _desktop) { if (tablet->getToolbarMode() && _desktop) {
@ -1033,7 +1033,7 @@ QString OffscreenUi::assetDialog(const QVariantMap& properties) {
ModalDialogListener *OffscreenUi::assetDialogAsync(const QVariantMap& properties) { ModalDialogListener *OffscreenUi::assetDialogAsync(const QVariantMap& properties) {
// ATP equivalent of fileDialog(). // ATP equivalent of fileDialog().
QVariant buildDialogResult; QVariant buildDialogResult;
bool invokeResult; bool invokeResult = false;
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); TabletProxy* tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"));
if (tablet->getToolbarMode() && _desktop) { if (tablet->getToolbarMode() && _desktop) {
@ -1165,7 +1165,7 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) {
} }
// QML input elements absorb key press, but apparently not key release. // QML input elements absorb key press, but apparently not key release.
// therefore we want to ensure that key release events for key presses that were // therefore we want to ensure that key release events for key presses that were
// accepted by the QML layer are suppressed // accepted by the QML layer are suppressed
if (type == QEvent::KeyRelease && pressed) { if (type == QEvent::KeyRelease && pressed) {
pressed = false; pressed = false;
@ -1175,10 +1175,6 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) {
return result; return result;
} }
unsigned int OffscreenUi::getMenuUserDataId() const {
return _vrMenu->_userDataId;
}
ModalDialogListener::ModalDialogListener(QQuickItem *dialog) : _dialog(dialog) { ModalDialogListener::ModalDialogListener(QQuickItem *dialog) : _dialog(dialog) {
if (!dialog) { if (!dialog) {
_finished = true; _finished = true;

View file

@ -74,7 +74,7 @@ public:
// Setting pinned to true will hide all overlay elements on the desktop that don't have a pinned flag // Setting pinned to true will hide all overlay elements on the desktop that don't have a pinned flag
void setPinned(bool pinned = true); void setPinned(bool pinned = true);
void togglePinned(); void togglePinned();
void setConstrainToolbarToCenterX(bool constrained); void setConstrainToolbarToCenterX(bool constrained);
@ -237,7 +237,6 @@ public:
static ModalDialogListener* getTextAsync(const Icon icon, const QString & title, const QString & label, const QString & text = QString()); static ModalDialogListener* getTextAsync(const Icon icon, const QString & title, const QString & label, const QString & text = QString());
static ModalDialogListener* getItemAsync(const Icon icon, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true); static ModalDialogListener* getItemAsync(const Icon icon, const QString & title, const QString & label, const QStringList & items, int current = 0, bool editable = true);
unsigned int getMenuUserDataId() const;
QList<QObject *> &getModalDialogListeners(); QList<QObject *> &getModalDialogListeners();
signals: signals:
@ -270,7 +269,7 @@ private:
QList<QObject*> _modalDialogListeners; QList<QObject*> _modalDialogListeners;
std::unordered_map<int, bool> _pressedKeys; std::unordered_map<int, bool> _pressedKeys;
VrMenu* _vrMenu { nullptr }; VrMenu* _vrMenu { nullptr };
QQueue<std::function<void(VrMenu*)>> _queuedMenuInitializers; QQueue<std::function<void(VrMenu*)>> _queuedMenuInitializers;
}; };
#endif #endif

View file

@ -17,139 +17,116 @@
#include "OffscreenUi.h" #include "OffscreenUi.h"
#include "ui/Logging.h" #include "ui/Logging.h"
static unsigned int USER_DATA_ID = 0;
// Binds together a Qt Action or Menu with the QML Menu or MenuItem
//
// TODO On reflection, it may be pointless to use the UUID. Perhaps
// simply creating the bidirectional link pointing to both the widget
// and qml object and inject the pointer into both objects
class MenuUserData : public QObjectUserData {
public:
MenuUserData(QAction* action, QObject* qmlObject, QObject* qmlParent) {
if (!USER_DATA_ID) {
USER_DATA_ID = DependencyManager::get<OffscreenUi>()->getMenuUserDataId();
}
_action = action;
_qml = qmlObject;
_qmlParent = qmlParent;
action->setUserData(USER_DATA_ID, this); MenuUserData::MenuUserData(QAction* action, QObject* qmlObject, QObject* qmlParent) {
qmlObject->setUserData(USER_DATA_ID, this); _action = action;
qmlObject->setObjectName(uuid.toString()); _qml = qmlObject;
// Make sure we can find it again in the future _qmlParent = qmlParent;
action->setProperty(USER_DATA, QVariant::fromValue(this));
qmlObject->setProperty(USER_DATA, QVariant::fromValue(this));
qmlObject->setObjectName(uuid.toString());
// Make sure we can find it again in the future
updateQmlItemFromAction();
_changedConnection = QObject::connect(action, &QAction::changed, [=] {
updateQmlItemFromAction(); updateQmlItemFromAction();
_changedConnection = QObject::connect(action, &QAction::changed, [=] { });
updateQmlItemFromAction(); _shutdownConnection = QObject::connect(qApp, &QCoreApplication::aboutToQuit, [=] {
});
_shutdownConnection = QObject::connect(qApp, &QCoreApplication::aboutToQuit, [=] {
QObject::disconnect(_changedConnection);
});
class ExclusionGroupSetter : public QObject {
public:
ExclusionGroupSetter(QObject* from, QObject* to, QObject* qmlParent) : QObject(from), _from(from), _to(to), _qmlParent(qmlParent) {
_from->installEventFilter(this);
}
~ExclusionGroupSetter() {
_from->removeEventFilter(this);
}
protected:
virtual bool eventFilter(QObject* o, QEvent* e) override {
if (e->type() == QEvent::DynamicPropertyChange) {
QDynamicPropertyChangeEvent* dpc = static_cast<QDynamicPropertyChangeEvent*>(e);
if (dpc->propertyName() == "exclusionGroup")
{
// unfortunately Qt doesn't support passing dynamic properties between C++ / QML, so we have to use this ugly helper function
QMetaObject::invokeMethod(_qmlParent,
"addExclusionGroup",
Qt::DirectConnection,
Q_ARG(QVariant, QVariant::fromValue(_to)),
Q_ARG(QVariant, _from->property(dpc->propertyName())));
}
}
return QObject::eventFilter(o, e);
}
private:
QObject* _from;
QObject* _to;
QObject* _qmlParent;
};
new ExclusionGroupSetter(action, qmlObject, qmlParent);
}
~MenuUserData() {
QObject::disconnect(_changedConnection); QObject::disconnect(_changedConnection);
QObject::disconnect(_shutdownConnection); });
_action->setUserData(USER_DATA_ID, nullptr);
_qml->setUserData(USER_DATA_ID, nullptr);
}
void updateQmlItemFromAction() { class ExclusionGroupSetter : public QObject {
_qml->setProperty("checkable", _action->isCheckable()); public:
_qml->setProperty("enabled", _action->isEnabled()); ExclusionGroupSetter(QObject* from, QObject* to, QObject* qmlParent) : QObject(from), _from(from), _to(to), _qmlParent(qmlParent) {
QString text = _action->text(); _from->installEventFilter(this);
_qml->setProperty("text", text);
_qml->setProperty("shortcut", _action->shortcut().toString());
_qml->setProperty("checked", _action->isChecked());
_qml->setProperty("visible", _action->isVisible());
}
void clear() {
_qml->setProperty("checkable", 0);
_qml->setProperty("enabled", 0);
_qml->setProperty("text", 0);
_qml->setProperty("shortcut", 0);
_qml->setProperty("checked", 0);
_qml->setProperty("visible", 0);
_action->setUserData(USER_DATA_ID, nullptr);
_qml->setUserData(USER_DATA_ID, nullptr);
}
const QUuid uuid{ QUuid::createUuid() };
static bool hasData(QAction* object) {
if (!object) {
qWarning() << "Attempted to fetch MenuUserData for null object";
return false;
} }
return (nullptr != static_cast<MenuUserData*>(object->userData(USER_DATA_ID)));
}
static MenuUserData* forObject(QAction* object) { ~ExclusionGroupSetter() {
if (!object) { _from->removeEventFilter(this);
qWarning() << "Attempted to fetch MenuUserData for null object";
return nullptr;
} }
auto result = static_cast<MenuUserData*>(object->userData(USER_DATA_ID)); protected:
if (!result) { virtual bool eventFilter(QObject* o, QEvent* e) override {
qWarning() << "Unable to find MenuUserData for object " << object; if (e->type() == QEvent::DynamicPropertyChange) {
if (auto action = dynamic_cast<QAction*>(object)) { QDynamicPropertyChangeEvent* dpc = static_cast<QDynamicPropertyChangeEvent*>(e);
qWarning() << action->text(); if (dpc->propertyName() == "exclusionGroup") {
} else if (auto menu = dynamic_cast<QMenu*>(object)) { // unfortunately Qt doesn't support passing dynamic properties between C++ / QML, so we have to use this ugly helper function
qWarning() << menu->title(); QMetaObject::invokeMethod(_qmlParent,
"addExclusionGroup",
Qt::DirectConnection,
Q_ARG(QVariant, QVariant::fromValue(_to)),
Q_ARG(QVariant, _from->property(dpc->propertyName())));
}
} }
return nullptr;
return QObject::eventFilter(o, e);
} }
return result;
private:
QObject* _from;
QObject* _to;
QObject* _qmlParent;
};
new ExclusionGroupSetter(action, qmlObject, qmlParent);
}
MenuUserData::~MenuUserData() {
QObject::disconnect(_changedConnection);
QObject::disconnect(_shutdownConnection);
_action->setProperty(USER_DATA, QVariant());
_qml->setProperty(USER_DATA, QVariant());
}
void MenuUserData::updateQmlItemFromAction() {
_qml->setProperty("checkable", _action->isCheckable());
_qml->setProperty("enabled", _action->isEnabled());
QString text = _action->text();
_qml->setProperty("text", text);
_qml->setProperty("shortcut", _action->shortcut().toString());
_qml->setProperty("checked", _action->isChecked());
_qml->setProperty("visible", _action->isVisible());
}
void MenuUserData::clear() {
_qml->setProperty("checkable", 0);
_qml->setProperty("enabled", 0);
_qml->setProperty("text", 0);
_qml->setProperty("shortcut", 0);
_qml->setProperty("checked", 0);
_qml->setProperty("visible", 0);
_action->setProperty(USER_DATA, QVariant());
_qml->setProperty(USER_DATA, QVariant());
}
bool MenuUserData::hasData(QAction* object) {
if (!object) {
qWarning() << "Attempted to fetch MenuUserData for null object";
return false;
} }
return (nullptr != object->property(USER_DATA).value<MenuUserData*>());
}
private: MenuUserData* MenuUserData::forObject(QAction* object) {
Q_DISABLE_COPY(MenuUserData); if (!object) {
qWarning() << "Attempted to fetch MenuUserData for null object";
QMetaObject::Connection _shutdownConnection; return nullptr;
QMetaObject::Connection _changedConnection; }
QAction* _action { nullptr }; auto result = object->property(USER_DATA).value<MenuUserData*>();
QObject* _qml { nullptr }; if (!result) {
QObject* _qmlParent{ nullptr }; qWarning() << "Unable to find MenuUserData for object " << object;
}; if (auto action = dynamic_cast<QAction*>(object)) {
qWarning() << action->text();
} else if (auto menu = dynamic_cast<QMenu*>(object)) {
qWarning() << menu->title();
}
return nullptr;
}
return result;
}
VrMenu::VrMenu(OffscreenUi* parent) : QObject(parent) { VrMenu::VrMenu(OffscreenUi* parent) : QObject(parent) {
_rootMenu = parent->getRootItem()->findChild<QObject*>("rootMenu"); _rootMenu = parent->getRootItem()->findChild<QObject*>("rootMenu");

View file

@ -18,8 +18,44 @@
#include <QSignalMapper> #include <QSignalMapper>
#include <QAction> #include <QAction>
#include <QMenu> #include <QMenu>
#include <QUuid>
#include "OffscreenUi.h" #include "OffscreenUi.h"
// Binds together a Qt Action or Menu with the QML Menu or MenuItem
//
// TODO On reflection, it may be pointless to use the UUID. Perhaps
// simply creating the bidirectional link pointing to both the widget
// and qml object and inject the pointer into both objects
class MenuUserData : public QObject {
Q_OBJECT
public:
MenuUserData(QAction* action, QObject* qmlObject, QObject* qmlParent);
~MenuUserData();
void updateQmlItemFromAction();
void clear();
const QUuid uuid{ QUuid::createUuid() };
static bool hasData(QAction* object);
static MenuUserData* forObject(QAction* object);
private:
Q_DISABLE_COPY(MenuUserData);
static constexpr const char *USER_DATA{"user_data"};
QMetaObject::Connection _shutdownConnection;
QMetaObject::Connection _changedConnection;
QAction* _action { nullptr };
QObject* _qml { nullptr };
QObject* _qmlParent{ nullptr };
};
// FIXME break up the rendering code (VrMenu) and the code for mirroring a Widget based menu in QML // FIXME break up the rendering code (VrMenu) and the code for mirroring a Widget based menu in QML
class VrMenu : public QObject { class VrMenu : public QObject {
Q_OBJECT Q_OBJECT
@ -37,7 +73,6 @@ protected:
friend class MenuUserData; friend class MenuUserData;
friend class OffscreenUi; friend class OffscreenUi;
const unsigned int _userDataId { QObject::registerUserData() };
}; };
#endif // hifi_VrMenu_h #endif // hifi_VrMenu_h