//// Menu.cpp// interface/src//// Created by Stephen Birarda on 8/12/13.// Copyright 2013 High Fidelity, Inc.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include <cstdlib> #include <QBoxLayout>#include <QColorDialog>#include <QDialogButtonBox>#include <QDoubleSpinBox>#include <QFileDialog>#include <QFormLayout>#include <QInputDialog>#include <QLineEdit>#include <QMainWindow>#include <QMenuBar>#include <QMessageBox>#include <QShortcut>#include <QSlider>#include <QUuid>#include <QHBoxLayout>#include <QDesktopServices> #include <AccountManager.h>#include <XmppClient.h>#include <UUID.h>#include <UserActivityLogger.h> #include "Application.h"#include "AccountManager.h"#include "Menu.h"#include "scripting/MenuScriptingInterface.h"#include "Util.h"#include "ui/AnimationsDialog.h"#include "ui/AttachmentsDialog.h"#include "ui/InfoView.h"#include "ui/MetavoxelEditor.h"#include "ui/ModelsBrowser.h"#include "ui/LoginDialog.h"#include "ui/NodeBounds.h"#include "devices/OculusManager.h" Menu* Menu::_instance = NULL; Menu* Menu::getInstance() { static QMutex menuInstanceMutex; // lock the menu instance mutex to make sure we don't race and create two menus and crash menuInstanceMutex.lock(); if (!_instance) { qDebug("First call to Menu::getInstance() - initing menu."); _instance = new Menu(); } menuInstanceMutex.unlock(); return _instance;} const ViewFrustumOffset DEFAULT_FRUSTUM_OFFSET = {-135.0f, 0.0f, 0.0f, 25.0f, 0.0f};const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f;const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f;const int ONE_SECOND_OF_FRAMES = 60;const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES;const float MUTE_RADIUS = 50; const QString CONSOLE_TITLE = "Scripting Console";const float CONSOLE_WINDOW_OPACITY = 0.95f;const int CONSOLE_WIDTH = 800;const int CONSOLE_HEIGHT = 200; Menu::Menu() : _actionHash(), _audioJitterBufferSamples(0), _bandwidthDialog(NULL), _fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES), _realWorldFieldOfView(DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES), _faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION), _frustumDrawMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET), _jsConsole(NULL), _octreeStatsDialog(NULL), _lodToolsDialog(NULL), _userLocationsDialog(NULL), _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE), _sixenseReticleMoveSpeed(DEFAULT_SIXENSE_RETICLE_MOVE_SPEED), _invertSixenseButtons(DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS), _automaticAvatarLOD(true), _avatarLODDecreaseFPS(DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS), _avatarLODIncreaseFPS(ADJUST_LOD_UP_FPS), _avatarLODDistanceMultiplier(DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER), _boundaryLevelAdjust(0), _maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS), _lastAdjust(usecTimestampNow()), _lastAvatarDetailDrop(usecTimestampNow()), _fpsAverage(FIVE_SECONDS_OF_FRAMES), _fastFPSAverage(ONE_SECOND_OF_FRAMES), _loginAction(NULL), _preferencesDialog(NULL), _loginDialog(NULL), _snapshotsLocation(), _scriptsLocation(), _walletPrivateKey(){ Application *appInstance = Application::getInstance(); QMenu* fileMenu = addMenu("File"); #ifdef Q_OS_MAC addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, this, SLOT(aboutApp()), QAction::AboutRole);#endif AccountManager& accountManager = AccountManager::getInstance(); _loginAction = addActionToQMenuAndActionHash(fileMenu, MenuOption::Logout); // call our toggle login function now so the menu option is setup properly toggleLoginMenuItem(); // connect to the appropriate slots of the AccountManager so that we can change the Login/Logout menu item connect(&accountManager, &AccountManager::profileChanged, this, &Menu::toggleLoginMenuItem); connect(&accountManager, &AccountManager::logoutComplete, this, &Menu::toggleLoginMenuItem); addDisabledActionAndSeparator(fileMenu, "Scripts"); addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadDialog())); addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL, Qt::CTRL | Qt::SHIFT | Qt::Key_O, appInstance, SLOT(loadScriptURLDialog())); addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, appInstance, SLOT(stopAllScripts())); addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, 0, appInstance, SLOT(reloadAllScripts())); addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, appInstance, SLOT(toggleRunningScriptsWidget())); addDisabledActionAndSeparator(fileMenu, "Go"); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoHome, Qt::CTRL | Qt::Key_G, appInstance->getAvatar(), SLOT(goHome())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoToDomain, Qt::CTRL | Qt::Key_D, this, SLOT(goToDomainDialog())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoToLocation, Qt::CTRL | Qt::SHIFT | Qt::Key_L, this, SLOT(goToLocation())); addActionToQMenuAndActionHash(fileMenu, MenuOption::NameLocation, Qt::CTRL | Qt::Key_N, this, SLOT(nameLocation())); addActionToQMenuAndActionHash(fileMenu, MenuOption::MyLocations, Qt::CTRL | Qt::Key_K, this, SLOT(toggleLocationList())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoTo, Qt::Key_At, this, SLOT(goTo())); connect(&LocationManager::getInstance(), &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model"); addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0, Application::getInstance(), SLOT(uploadHead())); addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadSkeleton, 0, Application::getInstance(), SLOT(uploadSkeleton())); addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadAttachment, 0, Application::getInstance(), SLOT(uploadAttachment())); addDisabledActionAndSeparator(fileMenu, "Settings"); addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsImport, 0, this, SLOT(importSettings())); addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsExport, 0, this, SLOT(exportSettings())); addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, Qt::CTRL | Qt::Key_Q, appInstance, SLOT(quit()), QAction::QuitRole); QMenu* editMenu = addMenu("Edit"); QUndoStack* undoStack = Application::getInstance()->getUndoStack(); QAction* undoAction = undoStack->createUndoAction(editMenu); undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); addActionToQMenuAndActionHash(editMenu, undoAction); QAction* redoAction = undoStack->createRedoAction(editMenu); redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); addActionToQMenuAndActionHash(editMenu, redoAction); addActionToQMenuAndActionHash(editMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_Comma, this, SLOT(editPreferences()), QAction::PreferencesRole); addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0, this, SLOT(editAttachments())); addActionToQMenuAndActionHash(editMenu, MenuOption::Animations, 0, this, SLOT(editAnimations())); addDisabledActionAndSeparator(editMenu, "Physics"); QObject* avatar = appInstance->getAvatar(); addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false, avatar, SLOT(updateMotionBehaviorsFromMenu())); addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::StandOnNearbyFloors, 0, true, avatar, SLOT(updateMotionBehaviorsFromMenu())); addAvatarCollisionSubMenu(editMenu); QMenu* toolsMenu = addMenu("Tools"); addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0, this, SLOT(showMetavoxelEditor())); addActionToQMenuAndActionHash(toolsMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S, this, SLOT(showScriptEditor())); #ifdef HAVE_QXMPP _chatAction = addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, 0, this, SLOT(showChat())); const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); toggleChat(); connect(&xmppClient, &QXmppClient::connected, this, &Menu::toggleChat); connect(&xmppClient, &QXmppClient::disconnected, this, &Menu::toggleChat); QDir::setCurrent(Application::resourcesPath()); // init chat window to listen chat _chatWindow = new ChatWindow(Application::getInstance()->getWindow());#endif addActionToQMenuAndActionHash(toolsMenu, MenuOption::Console, Qt::CTRL | Qt::ALT | Qt::Key_J, this, SLOT(toggleConsole())); QMenu* viewMenu = addMenu("View"); #ifdef Q_OS_MAC addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Fullscreen, Qt::CTRL | Qt::META | Qt::Key_F, false, appInstance, SLOT(setFullscreen(bool)));#else addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Fullscreen, Qt::CTRL | Qt::Key_F, false, appInstance, SLOT(setFullscreen(bool)));#endif addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true, appInstance,SLOT(cameraMenuChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, appInstance, SLOT(cameraMenuChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0, false, appInstance, SLOT(setEnableVRMode(bool))); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0, false, appInstance, SLOT(setEnable3DTVMode(bool))); QMenu* nodeBordersMenu = viewMenu->addMenu("Server Borders"); NodeBounds& nodeBounds = appInstance->getNodeBoundsDisplay(); addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersVoxelNodes, Qt::CTRL | Qt::SHIFT | Qt::Key_1, false, &nodeBounds, SLOT(setShowVoxelNodes(bool))); addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersModelNodes, Qt::CTRL | Qt::SHIFT | Qt::Key_2, false, &nodeBounds, SLOT(setShowModelNodes(bool))); addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersParticleNodes, Qt::CTRL | Qt::SHIFT | Qt::Key_3, false, &nodeBounds, SLOT(setShowParticleNodes(bool))); QMenu* avatarSizeMenu = viewMenu->addMenu("Avatar Size"); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::IncreaseAvatarSize, Qt::Key_Plus, appInstance->getAvatar(), SLOT(increaseSize())); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::DecreaseAvatarSize, Qt::Key_Minus, appInstance->getAvatar(), SLOT(decreaseSize())); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::ResetAvatarSize, Qt::Key_Equal, appInstance->getAvatar(), SLOT(resetSize())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MoveWithLean, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HeadMouse, 0, false); addDisabledActionAndSeparator(viewMenu, "Stats"); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Percent); addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, appInstance, SLOT(toggleLogDialog())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails())); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails())); QMenu* developerMenu = addMenu("Developer"); QMenu* renderOptionsMenu = developerMenu->addMenu("Rendering Options"); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true); addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::GlowMode, 0, appInstance->getGlowEffect(), SLOT(cycleRenderMode())); QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows"); QActionGroup* shadowGroup = new QActionGroup(shadowMenu); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::StringHair, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true); addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools())); QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options"); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::Voxels, Qt::SHIFT | Qt::Key_V, true, appInstance, SLOT(setRenderVoxels(bool))); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DisableAutoAdjustLOD); QMenu* modelOptionsMenu = developerMenu->addMenu("Model Options"); addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::Models, 0, true); addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelBounds, 0, false); addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelElementProxy, 0, false); addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelElementChildProxies, 0, false); QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::AvatarsReceiveShadows, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderSkeletonCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderHeadCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderBoundingCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::CollideAsRagdoll); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, false);#ifdef HAVE_FACESHIFT addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Faceshift, 0, true, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool)));#endif #ifdef HAVE_FACEPLUS addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Faceplus, 0, true, appInstance->getFaceplus(), SLOT(updateEnabled()));#endif #ifdef HAVE_VISAGE addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, false, appInstance->getVisage(), SLOT(updateEnabled()));#endif addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::GlowWhenSpeaking, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::FocusIndicators, 0, false); QMenu* sixenseOptionsMenu = developerMenu->addMenu("Sixense Options"); addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true); addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseLasers, 0, true); QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::FilterSixense, 0, true, appInstance->getSixenseManager(), SLOT(setFilter(bool))); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::LowVelocityFilter, 0, true, appInstance, SLOT(setLowVelocityFilter(bool))); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false); addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableActivityLogger, 0, false, &UserActivityLogger::getInstance(), SLOT(disable(bool))); addActionToQMenuAndActionHash(developerMenu, MenuOption::WalletPrivateKey, 0, this, SLOT(changePrivateKey())); addDisabledActionAndSeparator(developerMenu, "Testing"); QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools"); QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer"); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarSimulateTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandOtherAvatarTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::TestPing, 0, true); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer); addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, this, SLOT(runTests())); QMenu* frustumMenu = developerMenu->addMenu("View Frustum Debugging Tools"); addCheckableActionToQMenuAndActionHash(frustumMenu, MenuOption::DisplayFrustum, Qt::SHIFT | Qt::Key_F); addActionToQMenuAndActionHash(frustumMenu, MenuOption::FrustumRenderMode, Qt::SHIFT | Qt::Key_R, this, SLOT(cycleFrustumRenderMode())); updateFrustumRenderModeAction(); QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools"); addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings); addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings); QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools"); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, 0, true, appInstance->getAudio(), SLOT(toggleAudioNoiseReduction())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false, appInstance->getAudio(), SLOT(toggleStereoInput())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteAudio, Qt::CTRL | Qt::Key_M, false, appInstance->getAudio(), SLOT(toggleMute())); addActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteEnvironment, 0, this,Lines 1–500 of 1859. Load more
// // Menu.cpp // interface/src // // Created by Stephen Birarda on 8/12/13. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include <cstdlib> #include <QBoxLayout> #include <QColorDialog> #include <QDialogButtonBox> #include <QDoubleSpinBox> #include <QFileDialog> #include <QFormLayout> #include <QInputDialog> #include <QLineEdit> #include <QMainWindow> #include <QMenuBar> #include <QMessageBox> #include <QShortcut> #include <QSlider> #include <QUuid> #include <QHBoxLayout> #include <QDesktopServices> #include <AccountManager.h> #include <XmppClient.h> #include <UUID.h> #include <UserActivityLogger.h> #include "Application.h" #include "AccountManager.h" #include "Menu.h" #include "scripting/MenuScriptingInterface.h" #include "Util.h" #include "ui/AnimationsDialog.h" #include "ui/AttachmentsDialog.h" #include "ui/InfoView.h" #include "ui/MetavoxelEditor.h" #include "ui/ModelsBrowser.h" #include "ui/LoginDialog.h" #include "ui/NodeBounds.h" #include "devices/OculusManager.h" Menu* Menu::_instance = NULL; Menu* Menu::getInstance() { static QMutex menuInstanceMutex; // lock the menu instance mutex to make sure we don't race and create two menus and crash menuInstanceMutex.lock(); if (!_instance) { qDebug("First call to Menu::getInstance() - initing menu."); _instance = new Menu(); } menuInstanceMutex.unlock(); return _instance; } const ViewFrustumOffset DEFAULT_FRUSTUM_OFFSET = {-135.0f, 0.0f, 0.0f, 25.0f, 0.0f}; const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; const float MUTE_RADIUS = 50; const QString CONSOLE_TITLE = "Scripting Console"; const float CONSOLE_WINDOW_OPACITY = 0.95f; const int CONSOLE_WIDTH = 800; const int CONSOLE_HEIGHT = 200; Menu::Menu() : _actionHash(), _audioJitterBufferSamples(0), _bandwidthDialog(NULL), _fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES), _realWorldFieldOfView(DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES), _faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION), _frustumDrawMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET), _jsConsole(NULL), _octreeStatsDialog(NULL), _lodToolsDialog(NULL), _userLocationsDialog(NULL), _maxVoxels(DEFAULT_MAX_VOXELS_PER_SYSTEM), _voxelSizeScale(DEFAULT_OCTREE_SIZE_SCALE), _oculusUIAngularSize(DEFAULT_OCULUS_UI_ANGULAR_SIZE), _sixenseReticleMoveSpeed(DEFAULT_SIXENSE_RETICLE_MOVE_SPEED), _invertSixenseButtons(DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS), _automaticAvatarLOD(true), _avatarLODDecreaseFPS(DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS), _avatarLODIncreaseFPS(ADJUST_LOD_UP_FPS), _avatarLODDistanceMultiplier(DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER), _boundaryLevelAdjust(0), _maxVoxelPacketsPerSecond(DEFAULT_MAX_VOXEL_PPS), _lastAdjust(usecTimestampNow()), _lastAvatarDetailDrop(usecTimestampNow()), _fpsAverage(FIVE_SECONDS_OF_FRAMES), _fastFPSAverage(ONE_SECOND_OF_FRAMES), _loginAction(NULL), _preferencesDialog(NULL), _loginDialog(NULL), _snapshotsLocation(), _scriptsLocation(), _walletPrivateKey() { Application *appInstance = Application::getInstance(); QMenu* fileMenu = addMenu("File"); #ifdef Q_OS_MAC addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, this, SLOT(aboutApp()), QAction::AboutRole); #endif AccountManager& accountManager = AccountManager::getInstance(); _loginAction = addActionToQMenuAndActionHash(fileMenu, MenuOption::Logout); // call our toggle login function now so the menu option is setup properly toggleLoginMenuItem(); // connect to the appropriate slots of the AccountManager so that we can change the Login/Logout menu item connect(&accountManager, &AccountManager::profileChanged, this, &Menu::toggleLoginMenuItem); connect(&accountManager, &AccountManager::logoutComplete, this, &Menu::toggleLoginMenuItem); addDisabledActionAndSeparator(fileMenu, "Scripts"); addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadDialog())); addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL, Qt::CTRL | Qt::SHIFT | Qt::Key_O, appInstance, SLOT(loadScriptURLDialog())); addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, appInstance, SLOT(stopAllScripts())); addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, 0, appInstance, SLOT(reloadAllScripts())); addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, appInstance, SLOT(toggleRunningScriptsWidget())); addDisabledActionAndSeparator(fileMenu, "Go"); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoHome, Qt::CTRL | Qt::Key_G, appInstance->getAvatar(), SLOT(goHome())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoToDomain, Qt::CTRL | Qt::Key_D, this, SLOT(goToDomainDialog())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoToLocation, Qt::CTRL | Qt::SHIFT | Qt::Key_L, this, SLOT(goToLocation())); addActionToQMenuAndActionHash(fileMenu, MenuOption::NameLocation, Qt::CTRL | Qt::Key_N, this, SLOT(nameLocation())); addActionToQMenuAndActionHash(fileMenu, MenuOption::MyLocations, Qt::CTRL | Qt::Key_K, this, SLOT(toggleLocationList())); addActionToQMenuAndActionHash(fileMenu, MenuOption::GoTo, Qt::Key_At, this, SLOT(goTo())); connect(&LocationManager::getInstance(), &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model"); addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadHead, 0, Application::getInstance(), SLOT(uploadHead())); addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadSkeleton, 0, Application::getInstance(), SLOT(uploadSkeleton())); addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadAttachment, 0, Application::getInstance(), SLOT(uploadAttachment())); addDisabledActionAndSeparator(fileMenu, "Settings"); addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsImport, 0, this, SLOT(importSettings())); addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsExport, 0, this, SLOT(exportSettings())); addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, Qt::CTRL | Qt::Key_Q, appInstance, SLOT(quit()), QAction::QuitRole); QMenu* editMenu = addMenu("Edit"); QUndoStack* undoStack = Application::getInstance()->getUndoStack(); QAction* undoAction = undoStack->createUndoAction(editMenu); undoAction->setShortcut(Qt::CTRL | Qt::Key_Z); addActionToQMenuAndActionHash(editMenu, undoAction); QAction* redoAction = undoStack->createRedoAction(editMenu); redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z); addActionToQMenuAndActionHash(editMenu, redoAction); addActionToQMenuAndActionHash(editMenu, MenuOption::Preferences, Qt::CTRL | Qt::Key_Comma, this, SLOT(editPreferences()), QAction::PreferencesRole); addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0, this, SLOT(editAttachments())); addActionToQMenuAndActionHash(editMenu, MenuOption::Animations, 0, this, SLOT(editAnimations())); addDisabledActionAndSeparator(editMenu, "Physics"); QObject* avatar = appInstance->getAvatar(); addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false, avatar, SLOT(updateMotionBehaviorsFromMenu())); addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::StandOnNearbyFloors, 0, true, avatar, SLOT(updateMotionBehaviorsFromMenu())); addAvatarCollisionSubMenu(editMenu); QMenu* toolsMenu = addMenu("Tools"); addActionToQMenuAndActionHash(toolsMenu, MenuOption::MetavoxelEditor, 0, this, SLOT(showMetavoxelEditor())); addActionToQMenuAndActionHash(toolsMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S, this, SLOT(showScriptEditor())); #ifdef HAVE_QXMPP _chatAction = addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, 0, this, SLOT(showChat())); const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); toggleChat(); connect(&xmppClient, &QXmppClient::connected, this, &Menu::toggleChat); connect(&xmppClient, &QXmppClient::disconnected, this, &Menu::toggleChat); QDir::setCurrent(Application::resourcesPath()); // init chat window to listen chat _chatWindow = new ChatWindow(Application::getInstance()->getWindow()); #endif addActionToQMenuAndActionHash(toolsMenu, MenuOption::Console, Qt::CTRL | Qt::ALT | Qt::Key_J, this, SLOT(toggleConsole())); QMenu* viewMenu = addMenu("View"); #ifdef Q_OS_MAC addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Fullscreen, Qt::CTRL | Qt::META | Qt::Key_F, false, appInstance, SLOT(setFullscreen(bool))); #else addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Fullscreen, Qt::CTRL | Qt::Key_F, false, appInstance, SLOT(setFullscreen(bool))); #endif addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true, appInstance,SLOT(cameraMenuChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, appInstance, SLOT(cameraMenuChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0, false, appInstance, SLOT(setEnableVRMode(bool))); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0, false, appInstance, SLOT(setEnable3DTVMode(bool))); QMenu* nodeBordersMenu = viewMenu->addMenu("Server Borders"); NodeBounds& nodeBounds = appInstance->getNodeBoundsDisplay(); addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersVoxelNodes, Qt::CTRL | Qt::SHIFT | Qt::Key_1, false, &nodeBounds, SLOT(setShowVoxelNodes(bool))); addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersModelNodes, Qt::CTRL | Qt::SHIFT | Qt::Key_2, false, &nodeBounds, SLOT(setShowModelNodes(bool))); addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersParticleNodes, Qt::CTRL | Qt::SHIFT | Qt::Key_3, false, &nodeBounds, SLOT(setShowParticleNodes(bool))); QMenu* avatarSizeMenu = viewMenu->addMenu("Avatar Size"); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::IncreaseAvatarSize, Qt::Key_Plus, appInstance->getAvatar(), SLOT(increaseSize())); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::DecreaseAvatarSize, Qt::Key_Minus, appInstance->getAvatar(), SLOT(decreaseSize())); addActionToQMenuAndActionHash(avatarSizeMenu, MenuOption::ResetAvatarSize, Qt::Key_Equal, appInstance->getAvatar(), SLOT(resetSize())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MoveWithLean, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HeadMouse, 0, false); addDisabledActionAndSeparator(viewMenu, "Stats"); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Percent); addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, appInstance, SLOT(toggleLogDialog())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails())); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails())); QMenu* developerMenu = addMenu("Developer"); QMenu* renderOptionsMenu = developerMenu->addMenu("Rendering Options"); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true); addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::GlowMode, 0, appInstance->getGlowEffect(), SLOT(cycleRenderMode())); QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows"); QActionGroup* shadowGroup = new QActionGroup(shadowMenu); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::StringHair, 0, false); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true); addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools())); QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options"); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::Voxels, Qt::SHIFT | Qt::Key_V, true, appInstance, SLOT(setRenderVoxels(bool))); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges); addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DisableAutoAdjustLOD); QMenu* modelOptionsMenu = developerMenu->addMenu("Model Options"); addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::Models, 0, true); addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelBounds, 0, false); addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelElementProxy, 0, false); addCheckableActionToQMenuAndActionHash(modelOptionsMenu, MenuOption::DisplayModelElementChildProxies, 0, false); QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Avatars, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::AvatarsReceiveShadows, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderSkeletonCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderHeadCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::RenderBoundingCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::CollideAsRagdoll); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::LookAtVectors, 0, false); #ifdef HAVE_FACESHIFT addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Faceshift, 0, true, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); #endif #ifdef HAVE_FACEPLUS addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Faceplus, 0, true, appInstance->getFaceplus(), SLOT(updateEnabled())); #endif #ifdef HAVE_VISAGE addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::Visage, 0, false, appInstance->getVisage(), SLOT(updateEnabled())); #endif addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::GlowWhenSpeaking, 0, true); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::FocusIndicators, 0, false); QMenu* sixenseOptionsMenu = developerMenu->addMenu("Sixense Options"); addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true); addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseLasers, 0, true); QMenu* handOptionsMenu = developerMenu->addMenu("Hand Options"); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::FilterSixense, 0, true, appInstance->getSixenseManager(), SLOT(setFilter(bool))); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::LowVelocityFilter, 0, true, appInstance, SLOT(setLowVelocityFilter(bool))); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false); addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableNackPackets, 0, false); addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisableActivityLogger, 0, false, &UserActivityLogger::getInstance(), SLOT(disable(bool))); addActionToQMenuAndActionHash(developerMenu, MenuOption::WalletPrivateKey, 0, this, SLOT(changePrivateKey())); addDisabledActionAndSeparator(developerMenu, "Testing"); QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools"); QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer"); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMyAvatarSimulateTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandOtherAvatarTiming, 0, false); addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::TestPing, 0, true); addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer); addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, this, SLOT(runTests())); QMenu* frustumMenu = developerMenu->addMenu("View Frustum Debugging Tools"); addCheckableActionToQMenuAndActionHash(frustumMenu, MenuOption::DisplayFrustum, Qt::SHIFT | Qt::Key_F); addActionToQMenuAndActionHash(frustumMenu, MenuOption::FrustumRenderMode, Qt::SHIFT | Qt::Key_R, this, SLOT(cycleFrustumRenderMode())); updateFrustumRenderModeAction(); QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools"); addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings); addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings); QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools"); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, 0, true, appInstance->getAudio(), SLOT(toggleAudioNoiseReduction())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false, appInstance->getAudio(), SLOT(toggleStereoInput())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteAudio, Qt::CTRL | Qt::Key_M, false, appInstance->getAudio(), SLOT(toggleMute())); addActionToQMenuAndActionHash(audioDebugMenu, MenuOption::MuteEnvironment, 0, this,