diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bf83fdcde9..518672916b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1122,8 +1122,6 @@ Application::~Application() { _octreeProcessor.terminate(); _entityEditSender.terminate(); - Menu::getInstance()->deleteLater(); - _physicsEngine->setCharacterController(NULL); ModelEntityItem::cleanupLoadedAnimations(); @@ -1168,6 +1166,10 @@ Application::~Application() { #if 0 ConnexionClient::getInstance().destroy(); #endif + // The window takes ownership of the menu, so this has the side effect of destroying it. + _window->setMenuBar(nullptr); + + _window->deleteLater(); qInstallMessageHandler(NULL); // NOTE: Do this as late as possible so we continue to get our log messages } @@ -1334,7 +1336,7 @@ void Application::initializeUi() { _keyboardMouseDevice = std::dynamic_pointer_cast(inputPlugin); } } - Menu::setInstance(); + _window->setMenuBar(new Menu()); updateInputModes(); auto compositorHelper = DependencyManager::get(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 164f94a094..15fae25646 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -46,15 +46,8 @@ #include "Menu.h" -// Fixme make static member of Menu -static const char* const MENU_PROPERTY_NAME = "com.highfidelity.Menu"; - -void Menu::setInstance() { - globalInstance(MENU_PROPERTY_NAME); -} - Menu* Menu::getInstance() { - return static_cast(ui::Menu::getInstance()); + return static_cast(qApp->getWindow()->menuBar()); } Menu::Menu() { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6d5fd45b66..7130dd59e8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -20,7 +20,6 @@ class Menu : public ui::Menu { Q_OBJECT public: - static void setInstance(); static Menu* getInstance(); Menu(); Q_INVOKABLE void addMenuItem(const MenuItemProperties& properties); diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index 43a35e5ab4..574acbe586 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -23,124 +23,16 @@ PluginContainerProxy::PluginContainerProxy() { PluginContainerProxy::~PluginContainerProxy() { } +ui::Menu* PluginContainerProxy::getPrimaryMenu() { + auto appMenu = qApp->_window->menuBar(); + auto uiMenu = dynamic_cast(appMenu); + return uiMenu; +} + bool PluginContainerProxy::isForeground() { return qApp->isForeground() && !qApp->getWindow()->isMinimized(); } -void PluginContainerProxy::addMenu(const QString& menuName) { - Menu::getInstance()->addMenu(menuName); -} - -void PluginContainerProxy::removeMenu(const QString& menuName) { - Menu::getInstance()->removeMenu(menuName); -} - -QAction* PluginContainerProxy::addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { - auto menu = Menu::getInstance(); - MenuWrapper* parentItem = menu->getMenu(path); - QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); - if (!groupName.isEmpty()) { - QActionGroup* group{ nullptr }; - if (!_exclusiveGroups.count(groupName)) { - group = _exclusiveGroups[groupName] = new QActionGroup(menu); - group->setExclusive(true); - } else { - group = _exclusiveGroups[groupName]; - } - group->addAction(action); - } - connect(action, &QAction::triggered, [=] { - onClicked(action->isChecked()); - }); - action->setCheckable(checkable); - action->setChecked(checked); - if (type == PluginType::DISPLAY_PLUGIN) { - _currentDisplayPluginActions.push_back({ path, name }); - } else { - _currentInputPluginActions.push_back({ path, name }); - } - return action; -} - -void PluginContainerProxy::removeMenuItem(const QString& menuName, const QString& menuItem) { - Menu::getInstance()->removeMenuItem(menuName, menuItem); -} - -bool PluginContainerProxy::isOptionChecked(const QString& name) { - return Menu::getInstance()->isOptionChecked(name); -} - -void PluginContainerProxy::setIsOptionChecked(const QString& path, bool checked) { - Menu::getInstance()->setIsOptionChecked(path, checked); -} - -// FIXME there is a bug in the fullscreen setting, where leaving -// fullscreen does not restore the window frame, making it difficult -// or impossible to move or size the window. -// Additionally, setting fullscreen isn't hiding the menu on windows -// make it useless for stereoscopic modes. -void PluginContainerProxy::setFullscreen(const QScreen* target, bool hideMenu) { - auto _window = qApp->getWindow(); - if (!_window->isFullScreen()) { - _savedGeometry = _window->geometry(); - } - if (nullptr == target) { - // FIXME target the screen where the window currently is - target = qApp->primaryScreen(); - } - - _window->setGeometry(target->availableGeometry()); - _window->windowHandle()->setScreen((QScreen*)target); - _window->showFullScreen(); - -#ifndef Q_OS_MAC - // also hide the QMainWindow's menuBar - QMenuBar* menuBar = _window->menuBar(); - if (menuBar && hideMenu) { - menuBar->setVisible(false); - } -#endif -} - -void PluginContainerProxy::unsetFullscreen(const QScreen* avoid) { - auto _window = qApp->getWindow(); - _window->showNormal(); - - QRect targetGeometry = _savedGeometry; - if (avoid != nullptr) { - QRect avoidGeometry = avoid->geometry(); - if (avoidGeometry.contains(targetGeometry.topLeft())) { - QScreen* newTarget = qApp->primaryScreen(); - if (newTarget == avoid) { - foreach(auto screen, qApp->screens()) { - if (screen != avoid) { - newTarget = screen; - break; - } - } - } - targetGeometry = newTarget->availableGeometry(); - } - } -#ifdef Q_OS_MAC - QTimer* timer = new QTimer(); - timer->singleShot(2000, [=] { - _window->setGeometry(targetGeometry); - timer->deleteLater(); - }); -#else - _window->setGeometry(targetGeometry); -#endif - -#ifndef Q_OS_MAC - // also show the QMainWindow's menuBar - QMenuBar* menuBar = _window->menuBar(); - if (menuBar) { - menuBar->setVisible(true); - } -#endif -} - void PluginContainerProxy::requestReset() { // We could signal qApp to sequence this, but it turns out that requestReset is only used from within the main thread anyway. qApp->resetSensors(true); @@ -154,8 +46,8 @@ GLWidget* PluginContainerProxy::getPrimaryWidget() { return qApp->_glWidget; } -QWindow* PluginContainerProxy::getPrimaryWindow() { - return qApp->_glWidget->windowHandle(); +MainWindow* PluginContainerProxy::getPrimaryWindow() { + return qApp->getWindow(); } QOpenGLContext* PluginContainerProxy::getPrimaryContext() { @@ -184,13 +76,3 @@ void PluginContainerProxy::releaseOverlayTexture(const gpu::TexturePointer& text qApp->_applicationOverlay.releaseOverlay(texture); } -/// settings interface -bool PluginContainerProxy::getBoolSetting(const QString& settingName, bool defaultValue) { - Setting::Handle settingValue(settingName, defaultValue); - return settingValue.get(); -} - -void PluginContainerProxy::setBoolSetting(const QString& settingName, bool value) { - Setting::Handle settingValue(settingName, value); - return settingValue.set(value); -} diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index eff1dcf938..d6ee354192 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -14,34 +14,20 @@ class PluginContainerProxy : public QObject, PluginContainer { Q_OBJECT PluginContainerProxy(); virtual ~PluginContainerProxy(); - virtual void addMenu(const QString& menuName) override; - virtual void removeMenu(const QString& menuName) override; - virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override; - virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override; - virtual bool isOptionChecked(const QString& name) override; - virtual void setIsOptionChecked(const QString& path, bool checked) override; - virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = true) override; - virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override; virtual void showDisplayPluginsTools() override; virtual void requestReset() override; virtual bool makeRenderingContextCurrent() override; virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override; virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override; virtual GLWidget* getPrimaryWidget() override; - virtual QWindow* getPrimaryWindow() override; + virtual MainWindow* getPrimaryWindow() override; + virtual ui::Menu* getPrimaryMenu() override; virtual QOpenGLContext* getPrimaryContext() override; virtual bool isForeground() override; virtual const DisplayPlugin* getActiveDisplayPlugin() const override; - /// settings interface - virtual bool getBoolSetting(const QString& settingName, bool defaultValue) override; - virtual void setBoolSetting(const QString& settingName, bool value) override; - - QRect _savedGeometry{ 10, 120, 800, 600 }; - std::map _exclusiveGroups; - friend class Application; }; -#endif \ No newline at end of file +#endif diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index e735ba06d9..ee8a2a2fae 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -184,6 +184,9 @@ bool OBJReader::isValidTexture(const QByteArray &filename) { } QUrl candidateUrl = _url.resolved(QUrl(filename)); QNetworkReply *netReply = request(candidateUrl, true); + if (!netReply) { + return false; + } bool isValid = netReply->isFinished() && (netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200); netReply->deleteLater(); return isValid; @@ -257,6 +260,9 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } QNetworkReply* OBJReader::request(QUrl& url, bool isTest) { + if (!qApp) { + return nullptr; + } QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest netRequest(url); QNetworkReply* netReply = isTest ? networkAccessManager.head(netRequest) : networkAccessManager.get(netRequest); diff --git a/libraries/plugins/src/plugins/PluginContainer.cpp b/libraries/plugins/src/plugins/PluginContainer.cpp index 8afac745f3..2581389424 100644 --- a/libraries/plugins/src/plugins/PluginContainer.cpp +++ b/libraries/plugins/src/plugins/PluginContainer.cpp @@ -7,6 +7,14 @@ // #include "PluginContainer.h" +#include +#include +#include +#include + +#include +#include + static PluginContainer* INSTANCE{ nullptr }; PluginContainer& PluginContainer::getInstance() { @@ -23,3 +31,131 @@ PluginContainer::~PluginContainer() { Q_ASSERT(INSTANCE == this); INSTANCE = nullptr; }; + + +void PluginContainer::addMenu(const QString& menuName) { + getPrimaryMenu()->addMenu(menuName); +} + +void PluginContainer::removeMenu(const QString& menuName) { + getPrimaryMenu()->removeMenu(menuName); +} + +QAction* PluginContainer::addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { + auto menu = getPrimaryMenu(); + MenuWrapper* parentItem = menu->getMenu(path); + QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); + if (!groupName.isEmpty()) { + QActionGroup* group { nullptr }; + if (!_exclusiveGroups.count(groupName)) { + group = _exclusiveGroups[groupName] = new QActionGroup(menu); + group->setExclusive(true); + } else { + group = _exclusiveGroups[groupName]; + } + group->addAction(action); + } + QObject::connect(action, &QAction::triggered, [=] { + onClicked(action->isChecked()); + }); + action->setCheckable(checkable); + action->setChecked(checked); + if (type == PluginType::DISPLAY_PLUGIN) { + _currentDisplayPluginActions.push_back({ path, name }); + } else { + _currentInputPluginActions.push_back({ path, name }); + } + return action; +} + +void PluginContainer::removeMenuItem(const QString& menuName, const QString& menuItem) { + getPrimaryMenu()->removeMenuItem(menuName, menuItem); +} + +bool PluginContainer::isOptionChecked(const QString& name) { + return getPrimaryMenu()->isOptionChecked(name); +} + +void PluginContainer::setIsOptionChecked(const QString& path, bool checked) { + getPrimaryMenu()->setIsOptionChecked(path, checked); +} + + + +// FIXME there is a bug in the fullscreen setting, where leaving +// fullscreen does not restore the window frame, making it difficult +// or impossible to move or size the window. +// Additionally, setting fullscreen isn't hiding the menu on windows +// make it useless for stereoscopic modes. +void PluginContainer::setFullscreen(const QScreen* target, bool hideMenu) { + auto _window = getPrimaryWindow(); + if (!_window->isFullScreen()) { + _savedGeometry = _window->geometry(); + } + if (nullptr == target) { + // FIXME target the screen where the window currently is + target = qApp->primaryScreen(); + } + + _window->setGeometry(target->availableGeometry()); + _window->windowHandle()->setScreen((QScreen*)target); + _window->showFullScreen(); + +#ifndef Q_OS_MAC + // also hide the QMainWindow's menuBar + QMenuBar* menuBar = _window->menuBar(); + if (menuBar && hideMenu) { + menuBar->setVisible(false); + } +#endif +} + +void PluginContainer::unsetFullscreen(const QScreen* avoid) { + auto _window = getPrimaryWindow(); + _window->showNormal(); + + QRect targetGeometry = _savedGeometry; + if (avoid != nullptr) { + QRect avoidGeometry = avoid->geometry(); + if (avoidGeometry.contains(targetGeometry.topLeft())) { + QScreen* newTarget = qApp->primaryScreen(); + if (newTarget == avoid) { + foreach(auto screen, qApp->screens()) { + if (screen != avoid) { + newTarget = screen; + break; + } + } + } + targetGeometry = newTarget->availableGeometry(); + } + } +#ifdef Q_OS_MAC + QTimer* timer = new QTimer(); + timer->singleShot(2000, [=] { + _window->setGeometry(targetGeometry); + timer->deleteLater(); + }); +#else + _window->setGeometry(targetGeometry); +#endif + +#ifndef Q_OS_MAC + // also show the QMainWindow's menuBar + QMenuBar* menuBar = _window->menuBar(); + if (menuBar) { + menuBar->setVisible(true); + } +#endif +} + +/// settings interface +bool PluginContainer::getBoolSetting(const QString& settingName, bool defaultValue) { + Setting::Handle settingValue(settingName, defaultValue); + return settingValue.get(); +} + +void PluginContainer::setBoolSetting(const QString& settingName, bool value) { + Setting::Handle settingValue(settingName, value); + return settingValue.set(value); +} diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index b5ef4b0d55..991b8260c2 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -8,10 +8,13 @@ #pragma once #include +#include #include -#include + +#include #include #include +#include #include "Forward.h" @@ -28,33 +31,44 @@ namespace gpu { using TexturePointer = std::shared_ptr; } +namespace ui { + class Menu; +} + +class QActionGroup; +class MainWindow; + class PluginContainer { public: static PluginContainer& getInstance(); PluginContainer(); virtual ~PluginContainer(); - virtual void addMenu(const QString& menuName) = 0; - virtual void removeMenu(const QString& menuName) = 0; - virtual QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0; - virtual void removeMenuItem(const QString& menuName, const QString& menuItem) = 0; - virtual bool isOptionChecked(const QString& name) = 0; - virtual void setIsOptionChecked(const QString& path, bool checked) = 0; - virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = false) = 0; - virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0; + + void addMenu(const QString& menuName); + void removeMenu(const QString& menuName); + QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = ""); + void removeMenuItem(const QString& menuName, const QString& menuItem); + bool isOptionChecked(const QString& name); + void setIsOptionChecked(const QString& path, bool checked); + + void setFullscreen(const QScreen* targetScreen, bool hideMenu = false); + void unsetFullscreen(const QScreen* avoidScreen = nullptr); + + virtual ui::Menu* getPrimaryMenu() = 0; virtual void showDisplayPluginsTools() = 0; virtual void requestReset() = 0; virtual bool makeRenderingContextCurrent() = 0; virtual void releaseSceneTexture(const gpu::TexturePointer& texture) = 0; virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) = 0; virtual GLWidget* getPrimaryWidget() = 0; - virtual QWindow* getPrimaryWindow() = 0; + virtual MainWindow* getPrimaryWindow() = 0; virtual QOpenGLContext* getPrimaryContext() = 0; virtual bool isForeground() = 0; virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0; /// settings interface - virtual bool getBoolSetting(const QString& settingName, bool defaultValue) = 0; - virtual void setBoolSetting(const QString& settingName, bool value) = 0; + bool getBoolSetting(const QString& settingName, bool defaultValue); + void setBoolSetting(const QString& settingName, bool value); QVector>& currentDisplayActions() { return _currentDisplayPluginActions; @@ -67,5 +81,6 @@ public: protected: QVector> _currentDisplayPluginActions; QVector> _currentInputPluginActions; - + std::map _exclusiveGroups; + QRect _savedGeometry { 10, 120, 800, 600 }; }; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 8db66f3fca..c979d8f4b6 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "SharedUtil.h" + #include #include #include @@ -33,7 +35,6 @@ #include "NumericalConstants.h" #include "OctalCode.h" #include "SharedLogging.h" -#include "SharedUtil.h" static int usecTimestampNowAdjust = 0; // in usec void usecTimestampNowForceClockSkew(int clockSkew) { diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 1fae3bcff6..01c5a74bb4 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -24,12 +24,33 @@ #include #include +// Access to the global instance pointer to enable setting / unsetting +template +std::unique_ptr& globalInstancePointer() { + static std::unique_ptr instancePtr; + return instancePtr; +} + +template +void setGlobalInstance(const char* propertyName, T* instance) { + globalInstancePointer().reset(instance); +} + +template +bool destroyGlobalInstance() { + std::unique_ptr& instancePtr = globalInstancePointer(); + if (instancePtr.get()) { + instancePtr.reset(); + return true; + } + return false; +} + // Provides efficient access to a named global type. By storing the value // in the QApplication by name we can implement the singleton pattern and // have the single instance function across DLL boundaries. template T* globalInstance(const char* propertyName, Args&&... args) { - static std::unique_ptr instancePtr; static T* resultInstance { nullptr }; static std::mutex mutex; if (!resultInstance) { @@ -37,10 +58,12 @@ T* globalInstance(const char* propertyName, Args&&... args) { if (!resultInstance) { auto variant = qApp->property(propertyName); if (variant.isNull()) { - // Since we're building the object, store it in a shared_ptr so it's - // destroyed by the destructor of the static instancePtr - instancePtr = std::unique_ptr(new T(std::forward(args)...)); - + std::unique_ptr& instancePtr = globalInstancePointer(); + if (!instancePtr.get()) { + // Since we're building the object, store it in a shared_ptr so it's + // destroyed by the destructor of the static instancePtr + instancePtr = std::unique_ptr(new T(std::forward(args)...)); + } void* voidInstance = &(*instancePtr); variant = QVariant::fromValue(voidInstance); qApp->setProperty(propertyName, variant); @@ -52,6 +75,7 @@ T* globalInstance(const char* propertyName, Args&&... args) { return resultInstance; } + const int BYTES_PER_COLOR = 3; const int BYTES_PER_FLAGS = 1; typedef unsigned char colorPart; diff --git a/interface/src/MainWindow.cpp b/libraries/ui/src/MainWindow.cpp similarity index 97% rename from interface/src/MainWindow.cpp rename to libraries/ui/src/MainWindow.cpp index 16aedc4bb7..ce23bd02a2 100644 --- a/interface/src/MainWindow.cpp +++ b/libraries/ui/src/MainWindow.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "MainWindow.h" + #include #include #include @@ -20,10 +22,8 @@ #include #include #include +#include -#include "MainWindow.h" -#include "Menu.h" -#include "Util.h" MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), @@ -33,6 +33,10 @@ MainWindow::MainWindow(QWidget* parent) : setAcceptDrops(true); } +MainWindow::~MainWindow() { + qDebug() << "Destroying main window"; +} + void MainWindow::restoreGeometry() { // Did not use setGeometry() on purpose, // see http://doc.qt.io/qt-5/qsettings.html#restoring-the-state-of-a-gui-application diff --git a/interface/src/MainWindow.h b/libraries/ui/src/MainWindow.h similarity index 98% rename from interface/src/MainWindow.h rename to libraries/ui/src/MainWindow.h index eb262e0f97..3fee62692d 100644 --- a/interface/src/MainWindow.h +++ b/libraries/ui/src/MainWindow.h @@ -20,6 +20,7 @@ class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget* parent = NULL); + ~MainWindow(); public slots: void restoreGeometry(); diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index 47f7aa4eac..1b70213876 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -18,15 +18,8 @@ #include "Logging.h" using namespace ui; -static const char* const MENU_PROPERTY_NAME = "com.highfidelity.Menu"; -Menu* Menu::getInstance() { - static Menu* instance = globalInstance(MENU_PROPERTY_NAME); - return instance; -} - -Menu::Menu() { -} +Menu::Menu() {} void Menu::toggleAdvancedMenus() { setGroupingIsVisible("Advanced", !getGroupingIsVisible("Advanced")); @@ -223,7 +216,7 @@ void Menu::removeAction(MenuWrapper* menu, const QString& actionName) { void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(Menu::getInstance(), "setIsOptionChecked", Qt::BlockingQueuedConnection, + QMetaObject::invokeMethod(this, "setIsOptionChecked", Qt::BlockingQueuedConnection, Q_ARG(const QString&, menuOption), Q_ARG(bool, isChecked)); return; @@ -275,7 +268,7 @@ QAction* Menu::getActionFromName(const QString& menuName, MenuWrapper* menu) { MenuWrapper* Menu::getSubMenuFromName(const QString& menuName, MenuWrapper* menu) { QAction* action = getActionFromName(menuName, menu); if (action) { - return MenuWrapper::fromMenu(action->menu()); + return _backMap[action->menu()]; } return NULL; } @@ -320,7 +313,7 @@ QAction* Menu::getMenuAction(const QString& menuName) { if (!action) { break; } - parent = MenuWrapper::fromMenu(action->menu()); + parent = _backMap[action->menu()]; } return action; } @@ -357,7 +350,7 @@ MenuWrapper* Menu::addMenu(const QString& menuName, const QString& grouping) { menu = getSubMenuFromName(menuTreePart.trimmed(), addTo); if (!menu) { if (!addTo) { - menu = new MenuWrapper(QMenuBar::addMenu(menuTreePart.trimmed())); + menu = new MenuWrapper(*this, QMenuBar::addMenu(menuTreePart.trimmed())); } else { menu = addTo->addMenu(menuTreePart.trimmed()); } @@ -498,11 +491,11 @@ void Menu::removeActionGroup(const QString& groupName) { removeMenu(groupName); } -MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) { +MenuWrapper::MenuWrapper(ui::Menu& rootMenu, QMenu* menu) : _rootMenu(rootMenu), _realMenu(menu) { VrMenu::executeOrQueue([=](VrMenu* vrMenu) { vrMenu->addMenu(menu); }); - _backMap[menu] = this; + _rootMenu._backMap[menu] = this; } QList MenuWrapper::actions() { @@ -510,7 +503,7 @@ QList MenuWrapper::actions() { } MenuWrapper* MenuWrapper::addMenu(const QString& menuName) { - return new MenuWrapper(_realMenu->addMenu(menuName)); + return new MenuWrapper(_rootMenu, _realMenu->addMenu(menuName)); } void MenuWrapper::setEnabled(bool enabled) { @@ -558,4 +551,3 @@ void MenuWrapper::insertAction(QAction* before, QAction* action) { }); } -QHash MenuWrapper::_backMap; diff --git a/libraries/ui/src/ui/Menu.h b/libraries/ui/src/ui/Menu.h index 44aa661a21..895e40fe68 100644 --- a/libraries/ui/src/ui/Menu.h +++ b/libraries/ui/src/ui/Menu.h @@ -41,14 +41,9 @@ public: } private: - MenuWrapper(QMenu* menu); - - static MenuWrapper* fromMenu(QMenu* menu) { - return _backMap[menu]; - } - + MenuWrapper(ui::Menu& rootMenu, QMenu* menu); + ui::Menu& _rootMenu; QMenu* const _realMenu; - static QHash _backMap; friend class ui::Menu; }; @@ -60,7 +55,6 @@ public: static const int UNSPECIFIED_POSITION = -1; Menu(); - static Menu* getInstance(); void loadSettings(); void saveSettings(); @@ -146,8 +140,10 @@ protected: bool isValidGrouping(const QString& grouping) const { return grouping == "Advanced" || grouping == "Developer"; } QHash _groupingVisible; QHash> _groupingActions; + QHash _backMap; static bool _isSomeSubmenuShown; + friend class ::MenuWrapper; }; } // namespace ui diff --git a/plugins/hifiNeuron/CMakeLists.txt b/plugins/hifiNeuron/CMakeLists.txt index 9c512fc877..1cab2359a9 100644 --- a/plugins/hifiNeuron/CMakeLists.txt +++ b/plugins/hifiNeuron/CMakeLists.txt @@ -8,6 +8,6 @@ set(TARGET_NAME hifiNeuron) setup_hifi_plugin(Script Qml Widgets) -link_hifi_libraries(shared controllers plugins input-plugins) +link_hifi_libraries(shared controllers ui plugins input-plugins) target_neuron() diff --git a/plugins/hifiSdl2/CMakeLists.txt b/plugins/hifiSdl2/CMakeLists.txt index 2f106aedce..7e499e314a 100644 --- a/plugins/hifiSdl2/CMakeLists.txt +++ b/plugins/hifiSdl2/CMakeLists.txt @@ -8,5 +8,5 @@ set(TARGET_NAME hifiSdl2) setup_hifi_plugin(Script Qml Widgets) -link_hifi_libraries(shared controllers plugins input-plugins script-engine) +link_hifi_libraries(shared controllers ui plugins input-plugins script-engine) target_sdl2() diff --git a/plugins/hifiSixense/CMakeLists.txt b/plugins/hifiSixense/CMakeLists.txt index c790f6f14d..589b5b8964 100644 --- a/plugins/hifiSixense/CMakeLists.txt +++ b/plugins/hifiSixense/CMakeLists.txt @@ -8,5 +8,5 @@ set(TARGET_NAME hifiSixense) setup_hifi_plugin(Script Qml Widgets) -link_hifi_libraries(shared controllers plugins input-plugins) +link_hifi_libraries(shared controllers ui plugins input-plugins) target_sixense() diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 4b2927e0fa..e5cbffda21 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -13,7 +13,7 @@ if (WIN32) set(TARGET_NAME oculus) setup_hifi_plugin() - link_hifi_libraries(shared gl gpu controllers plugins display-plugins input-plugins) + link_hifi_libraries(shared gl gpu controllers ui plugins display-plugins input-plugins) include_hifi_library_headers(octree) diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index 878df3bfa5..1ba8d05b92 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -11,7 +11,7 @@ if (WIN32) add_definitions(-DGLEW_STATIC) set(TARGET_NAME openvr) setup_hifi_plugin(OpenGL Script Qml Widgets) - link_hifi_libraries(shared gl networking controllers + link_hifi_libraries(shared gl networking controllers ui plugins display-plugins input-plugins script-engine render-utils model gpu render model-networking fbx) diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index 8d5b6cc7f7..9bf74fc501 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -81,26 +81,17 @@ class PluginContainerProxy : public QObject, PluginContainer { Q_OBJECT public: virtual ~PluginContainerProxy() {} - virtual void addMenu(const QString& menuName) override {} - virtual void removeMenu(const QString& menuName) override {} - virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr; } - virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override {} - virtual bool isOptionChecked(const QString& name) override { return false; } - virtual void setIsOptionChecked(const QString& path, bool checked) override {} - virtual void setFullscreen(const QScreen* targetScreen, bool hideMenu = true) override {} - virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override {} virtual void showDisplayPluginsTools() override {} virtual void requestReset() override {} virtual bool makeRenderingContextCurrent() override { return true; } virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override {} virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override {} virtual GLWidget* getPrimaryWidget() override { return nullptr; } - virtual QWindow* getPrimaryWindow() override { return nullptr; } + virtual MainWindow* getPrimaryWindow() override { return nullptr; } virtual QOpenGLContext* getPrimaryContext() override { return nullptr; } - virtual bool isForeground() override { return true; } + virtual ui::Menu* getPrimaryMenu() { return nullptr; } + virtual bool isForeground() override { return true; } virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr; } - virtual bool getBoolSetting(const QString& settingName, bool defaultValue) override { return defaultValue; } - virtual void setBoolSetting(const QString& settingName, bool value) override { } }; class MyControllerScriptingInterface : public controller::ScriptingInterface {