From 2815cb0fef65fc19fcb87dd4976cd8ccfcfa934b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sat, 12 Dec 2015 14:51:27 -0800 Subject: [PATCH] first cut at adding advanced and developer menu groupings --- examples/edit.js | 64 +++-- interface/resources/qml/VrMenuItem.qml | 7 +- interface/src/Menu.cpp | 224 +++++++++++++----- interface/src/Menu.h | 33 ++- .../script-engine/src/MenuItemProperties.cpp | 1 + .../script-engine/src/MenuItemProperties.h | 2 + libraries/ui/src/VrMenu.cpp | 20 +- 7 files changed, 250 insertions(+), 101 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 5d5d642f47..59b6ae3e7d 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1002,7 +1002,8 @@ function setupModelMenus() { menuName: "Edit", menuItemName: "Models", isSeparator: true, - beforeItem: "Physics" + beforeItem: "Physics", + grouping: "Advanced" }); if (!Menu.menuItemExists("Edit", "Delete")) { print("no delete... adding ours"); @@ -1012,7 +1013,8 @@ function setupModelMenus() { shortcutKeyEvent: { text: "backspace" }, - afterItem: "Models" + afterItem: "Models", + grouping: "Advanced" }); modelMenuAddedDelete = true; } else { @@ -1023,7 +1025,8 @@ function setupModelMenus() { menuName: "Edit", menuItemName: "Entity List...", shortcutKey: "CTRL+META+L", - afterItem: "Models" + afterItem: "Models", + grouping: "Advanced" }); Menu.addMenuItem({ menuName: "Edit", @@ -1031,7 +1034,8 @@ function setupModelMenus() { shortcutKey: "CTRL+META+L", afterItem: "Entity List...", isCheckable: true, - isChecked: true + isChecked: true, + grouping: "Advanced" }); Menu.addMenuItem({ menuName: "Edit", @@ -1039,79 +1043,91 @@ function setupModelMenus() { shortcutKey: "CTRL+META+S", afterItem: "Allow Selecting of Large Models", isCheckable: true, - isChecked: true + isChecked: true, + grouping: "Advanced" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", afterItem: "Allow Selecting of Small Models", - isCheckable: true + isCheckable: true, + grouping: "Advanced" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Select All Entities In Box", shortcutKey: "CTRL+SHIFT+META+A", - afterItem: "Allow Selecting of Lights" + afterItem: "Allow Selecting of Lights", + grouping: "Advanced" }); Menu.addMenuItem({ menuName: "Edit", menuItemName: "Select All Entities Touching Box", shortcutKey: "CTRL+SHIFT+META+T", - afterItem: "Select All Entities In Box" + afterItem: "Select All Entities In Box", + grouping: "Advanced" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Models", isSeparator: true, - beforeItem: "Settings" + beforeItem: "Settings", + grouping: "Advanced" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Export Entities", shortcutKey: "CTRL+META+E", - afterItem: "Models" + afterItem: "Models", + grouping: "Advanced" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities", shortcutKey: "CTRL+META+I", - afterItem: "Export Entities" + afterItem: "Export Entities", + grouping: "Advanced" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities from URL", shortcutKey: "CTRL+META+U", - afterItem: "Import Entities" + afterItem: "Import Entities", + grouping: "Advanced" }); Menu.addMenuItem({ - menuName: "View", + menuName: "Edit", menuItemName: MENU_AUTO_FOCUS_ON_SELECT, isCheckable: true, - isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) == "true" + isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) == "true", + grouping: "Advanced" }); Menu.addMenuItem({ - menuName: "View", + menuName: "Edit", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_AUTO_FOCUS_ON_SELECT, isCheckable: true, - isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" + isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true", + grouping: "Advanced" }); Menu.addMenuItem({ - menuName: "View", + menuName: "Edit", menuItemName: MENU_SHOW_LIGHTS_IN_EDIT_MODE, afterItem: MENU_EASE_ON_FOCUS, isCheckable: true, - isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE) == "true" + isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE) == "true", + grouping: "Advanced" }); Menu.addMenuItem({ - menuName: "View", + menuName: "Edit", menuItemName: MENU_SHOW_ZONES_IN_EDIT_MODE, afterItem: MENU_SHOW_LIGHTS_IN_EDIT_MODE, isCheckable: true, - isChecked: Settings.getValue(SETTING_SHOW_ZONES_IN_EDIT_MODE) == "true" + isChecked: Settings.getValue(SETTING_SHOW_ZONES_IN_EDIT_MODE) == "true", + grouping: "Advanced" }); Entities.setLightsArePickable(false); @@ -1138,10 +1154,10 @@ function cleanupModelMenus() { Menu.removeMenuItem("File", "Import Entities"); Menu.removeMenuItem("File", "Import Entities from URL"); - Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT); - Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS); - Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE); - Menu.removeMenuItem("View", MENU_SHOW_ZONES_IN_EDIT_MODE); + Menu.removeMenuItem("Edit", MENU_AUTO_FOCUS_ON_SELECT); + Menu.removeMenuItem("Edit", MENU_EASE_ON_FOCUS); + Menu.removeMenuItem("Edit", MENU_SHOW_LIGHTS_IN_EDIT_MODE); + Menu.removeMenuItem("Edit", MENU_SHOW_ZONES_IN_EDIT_MODE); } Script.scriptEnding.connect(function() { diff --git a/interface/resources/qml/VrMenuItem.qml b/interface/resources/qml/VrMenuItem.qml index 7a351cec85..fbde35059d 100644 --- a/interface/resources/qml/VrMenuItem.qml +++ b/interface/resources/qml/VrMenuItem.qml @@ -47,8 +47,9 @@ Item { } } - implicitHeight: label.implicitHeight * 1.5 + implicitHeight: source.visible ? label.implicitHeight * 1.5 : 0 implicitWidth: label.implicitWidth + label.height * 2.5 + visible: source.visible Timer { id: timer @@ -66,6 +67,7 @@ Item { color: label.color text: checkText() size: label.height + visible: source.visible font.pixelSize: size function checkText() { if (!source || source.type != 1 || !source.checkable) { @@ -89,6 +91,7 @@ Item { verticalAlignment: Text.AlignVCenter color: source.enabled ? hifi.colors.text : hifi.colors.disabledText enabled: source.enabled && source.visible + visible: source.visible function typedText() { if (source) { switch (source.type) { @@ -109,7 +112,7 @@ Item { x: listView.width - width - 4 size: label.height width: implicitWidth - visible: source.type == 2 + visible: source.visible && (source.type == 2) text: "\uF0DA" anchors.verticalCenter: parent.verticalCenter color: label.color diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 86b3987af1..b03e223c07 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -68,16 +68,22 @@ Menu::Menu() { dialogsManager.data(), &DialogsManager::toggleLoginDialog); } - addDisabledActionAndSeparator(fileMenu, "Scripts"); + // File Menu > Scripts section -- "Advanced" grouping + addDisabledActionAndSeparator(fileMenu, "Scripts", UNSPECIFIED_POSITION, "Advanced"); addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, - qApp, SLOT(loadDialog())); + qApp, SLOT(loadDialog()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL, - Qt::CTRL | Qt::SHIFT | Qt::Key_O, qApp, SLOT(loadScriptURLDialog())); - addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, qApp, SLOT(stopAllScripts())); + Qt::CTRL | Qt::SHIFT | Qt::Key_O, qApp, SLOT(loadScriptURLDialog()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, qApp, SLOT(stopAllScripts()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, Qt::CTRL | Qt::Key_R, - qApp, SLOT(reloadAllScripts())); + qApp, SLOT(reloadAllScripts()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J, - qApp, SLOT(toggleRunningScriptsWidget())); + qApp, SLOT(toggleRunningScriptsWidget()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); auto addressManager = DependencyManager::get(); @@ -112,9 +118,11 @@ Menu::Menu() { dialogsManager.data(), SLOT(toggleAddressBar())); addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyAddress, 0, - addressManager.data(), SLOT(copyAddress())); + addressManager.data(), SLOT(copyAddress()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyPath, 0, - addressManager.data(), SLOT(copyPath())); + addressManager.data(), SLOT(copyPath()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, @@ -143,11 +151,13 @@ Menu::Menu() { QAction::PreferencesRole); addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0, - dialogsManager.data(), SLOT(editAttachments())); + dialogsManager.data(), SLOT(editAttachments()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); MenuWrapper* toolsMenu = addMenu("Tools"); addActionToQMenuAndActionHash(toolsMenu, MenuOption::ScriptEditor, Qt::ALT | Qt::Key_S, - dialogsManager.data(), SLOT(showScriptEditor())); + dialogsManager.data(), SLOT(showScriptEditor()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); #if defined(Q_OS_MAC) || defined(Q_OS_WIN) auto speechRecognizer = DependencyManager::get(); @@ -155,13 +165,16 @@ Menu::Menu() { Qt::CTRL | Qt::SHIFT | Qt::Key_C, speechRecognizer->getEnabled(), speechRecognizer.data(), - SLOT(setEnabled(bool))); + SLOT(setEnabled(bool)), + UNSPECIFIED_POSITION, "Advanced"); connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool))); #endif addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, 0, // QML Qt::Key_Backslash, - dialogsManager.data(), SLOT(showIRCLink())); + dialogsManager.data(), SLOT(showIRCLink()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); + addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0, qApp, SLOT(showFriendsWindow())); @@ -193,22 +206,26 @@ Menu::Menu() { MenuOption::ToolWindow, Qt::CTRL | Qt::ALT | Qt::Key_T, dialogsManager.data(), - SLOT(toggleToolWindow())); + SLOT(toggleToolWindow()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); addActionToQMenuAndActionHash(toolsMenu, MenuOption::Console, Qt::CTRL | Qt::ALT | Qt::Key_J, DependencyManager::get().data(), - SLOT(toggleConsole())); + SLOT(toggleConsole()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); addActionToQMenuAndActionHash(toolsMenu, MenuOption::ResetSensors, 0, // QML Qt::Key_Apostrophe, qApp, - SLOT(resetSensors())); + SLOT(resetSensors()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); addActionToQMenuAndActionHash(toolsMenu, MenuOption::PackageModel, 0, - qApp, SLOT(packageModel())); + qApp, SLOT(packageModel()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); addMenu(DisplayPlugin::MENU_PATH()); { @@ -220,7 +237,7 @@ Menu::Menu() { MenuWrapper* avatarMenu = addMenu("Avatar"); QObject* avatar = DependencyManager::get()->getMyAvatar(); - MenuWrapper* inputModeMenu = addMenu(MenuOption::InputMenu); + MenuWrapper* inputModeMenu = addMenu(MenuOption::InputMenu, "Advanced"); QActionGroup* inputModeGroup = new QActionGroup(inputModeMenu); inputModeGroup->setExclusive(false); @@ -241,17 +258,15 @@ Menu::Menu() { avatar, SLOT(resetSize())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::KeyboardMotorControl, - Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehaviorFromMenu())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ScriptedMotorControl, 0, true, - avatar, SLOT(updateMotionBehaviorFromMenu())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true, - avatar, SLOT(updateMotionBehaviorFromMenu())); + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true, + NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); + + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true, + NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); MenuWrapper* viewMenu = addMenu("View"); - addActionToQMenuAndActionHash(viewMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches())); + addActionToQMenuAndActionHash(viewMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), + QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); MenuWrapper* cameraModeMenu = viewMenu->addMenu("Camera Mode"); QActionGroup* cameraModeGroup = new QActionGroup(cameraModeMenu); @@ -275,30 +290,29 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, 0, //QML Qt::SHIFT | Qt::Key_H, true); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, - 0, // QML Qt::Key_H, - false, qApp, SLOT(cameraMenuChanged())); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::CenterPlayerInView, - 0, false, qApp, SLOT(rotationModeChanged())); + 0, false, qApp, SLOT(rotationModeChanged()), + UNSPECIFIED_POSITION, "Advanced"); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::WorldAxes); - - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::WorldAxes, 0, false, NULL, NULL, UNSPECIFIED_POSITION, "Developer"); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, 0, false, NULL, NULL, UNSPECIFIED_POSITION, "Developer"); addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, - Qt::CTRL | Qt::SHIFT | Qt::Key_L, - qApp, SLOT(toggleLogDialog())); + Qt::CTRL | Qt::SHIFT | Qt::Key_L, + qApp, SLOT(toggleLogDialog()), QAction::NoRole, UNSPECIFIED_POSITION, "Developer"); + addActionToQMenuAndActionHash(viewMenu, MenuOption::AudioNetworkStats, 0, - dialogsManager.data(), SLOT(audioStatsDetails())); + dialogsManager.data(), SLOT(audioStatsDetails()), QAction::NoRole, UNSPECIFIED_POSITION, "Developer"); + addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, - dialogsManager.data(), SLOT(bandwidthDetails())); + dialogsManager.data(), SLOT(bandwidthDetails()), QAction::NoRole, UNSPECIFIED_POSITION, "Developer"); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, - dialogsManager.data(), SLOT(octreeStatsDetails())); + dialogsManager.data(), SLOT(octreeStatsDetails()), QAction::NoRole, UNSPECIFIED_POSITION, "Developer"); + addCheckableActionToQMenuAndActionHash(viewMenu, "Advanced Menus", 0, false, this, SLOT(toggleAdvancedMenus())); + addCheckableActionToQMenuAndActionHash(viewMenu, "Developer Menus", 0, false, this, SLOT(toggleDeveloperMenus())); - MenuWrapper* developerMenu = addMenu("Developer"); + MenuWrapper* developerMenu = addMenu("Developer", "Developer"); MenuWrapper* renderOptionsMenu = developerMenu->addMenu("Render"); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, @@ -447,9 +461,23 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::MeshVisible, 0, true, avatar, SLOT(setEnableMeshVisible(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false); - + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::TurnWithHead, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ComfortMode, 0, true); + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::KeyboardMotorControl, + Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehaviorFromMenu()), + UNSPECIFIED_POSITION, "Developer"); + + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ScriptedMotorControl, 0, true, + avatar, SLOT(updateMotionBehaviorFromMenu()), + UNSPECIFIED_POSITION, "Developer"); + + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableCharacterController, 0, true, + avatar, SLOT(updateMotionBehaviorFromMenu()), + UNSPECIFIED_POSITION, "Developer"); + + + MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands"); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::EnableHandMouseInput, 0, false); @@ -573,6 +601,14 @@ Menu::Menu() { #endif } +void Menu::toggleAdvancedMenus() { + setGroupingIsVisible("Advanced", !getGroupingIsVisible("Advanced")); +} + +void Menu::toggleDeveloperMenus() { + setGroupingIsVisible("Developer", !getGroupingIsVisible("Developer")); +} + void Menu::loadSettings() { scanMenuBar(&Menu::loadAction); } @@ -610,23 +646,36 @@ void Menu::scanMenu(QMenu& menu, settingsAction modifySetting, Settings& setting settings.endGroup(); } -void Menu::addDisabledActionAndSeparator(MenuWrapper* destinationMenu, const QString& actionName, int menuItemLocation) { +void Menu::addDisabledActionAndSeparator(MenuWrapper* destinationMenu, const QString& actionName, + int menuItemLocation, const QString& grouping) { QAction* actionBefore = NULL; + QAction* separator; + QAction* separatorText; + if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) { actionBefore = destinationMenu->actions()[menuItemLocation]; } if (actionBefore) { - QAction* separator = new QAction("",destinationMenu); + separator = new QAction("",destinationMenu); destinationMenu->insertAction(actionBefore, separator); separator->setSeparator(true); - QAction* separatorText = new QAction(actionName,destinationMenu); + separatorText = new QAction(actionName,destinationMenu); separatorText->setEnabled(false); destinationMenu->insertAction(actionBefore, separatorText); } else { - destinationMenu->addSeparator(); - (destinationMenu->addAction(actionName))->setEnabled(false); + separator = destinationMenu->addSeparator(); + separatorText = destinationMenu->addAction(actionName); + separatorText->setEnabled(false); + } + + if (isValidGrouping(grouping)) { + _groupingActions[grouping] << separator; + _groupingActions[grouping] << separatorText; + bool isVisible = getGroupingIsVisible(grouping); + separator->setVisible(isVisible); + separatorText->setVisible(isVisible); } } @@ -636,7 +685,8 @@ QAction* Menu::addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, const QObject* receiver, const char* member, QAction::MenuRole role, - int menuItemLocation) { + int menuItemLocation, + const QString& grouping) { QAction* action = NULL; QAction* actionBefore = NULL; @@ -664,6 +714,11 @@ QAction* Menu::addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, _actionHash.insert(actionName, action); + if (isValidGrouping(grouping)) { + _groupingActions[grouping] << action; + action->setVisible(getGroupingIsVisible(grouping)); + } + return action; } @@ -672,7 +727,8 @@ QAction* Menu::addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, const QString& actionName, const QKeySequence& shortcut, QAction::MenuRole role, - int menuItemLocation) { + int menuItemLocation, + const QString& grouping) { QAction* actionBefore = NULL; if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) { @@ -699,6 +755,11 @@ QAction* Menu::addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, _actionHash.insert(action->text(), action); + if (isValidGrouping(grouping)) { + _groupingActions[grouping] << action; + action->setVisible(getGroupingIsVisible(grouping)); + } + return action; } @@ -708,19 +769,29 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(MenuWrapper* destinationMe const bool checked, const QObject* receiver, const char* member, - int menuItemLocation) { + int menuItemLocation, + const QString& grouping) { QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member, QAction::NoRole, menuItemLocation); action->setCheckable(true); action->setChecked(checked); + if (isValidGrouping(grouping)) { + _groupingActions[grouping] << action; + action->setVisible(getGroupingIsVisible(grouping)); + } + return action; } void Menu::removeAction(MenuWrapper* menu, const QString& actionName) { - menu->removeAction(_actionHash.value(actionName)); + auto action = _actionHash.value(actionName); + menu->removeAction(action); _actionHash.remove(actionName); + for (auto& grouping : _groupingActions) { + grouping.remove(action); + } } void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) { @@ -850,7 +921,7 @@ int Menu::positionBeforeSeparatorIfNeeded(MenuWrapper* menu, int requestedPositi } -MenuWrapper* Menu::addMenu(const QString& menuName) { +MenuWrapper* Menu::addMenu(const QString& menuName, const QString& grouping) { QStringList menuTree = menuName.split(">"); MenuWrapper* addTo = NULL; MenuWrapper* menu = NULL; @@ -866,6 +937,14 @@ MenuWrapper* Menu::addMenu(const QString& menuName) { addTo = menu; } + if (isValidGrouping(grouping)) { + auto action = getMenuAction(menuName); + if (action) { + _groupingActions[grouping] << action; + action->setVisible(getGroupingIsVisible(grouping)); + } + } + QMenuBar::repaint(); return menu; } @@ -897,7 +976,7 @@ bool Menu::menuExists(const QString& menuName) { return false; } -void Menu::addSeparator(const QString& menuName, const QString& separatorName) { +void Menu::addSeparator(const QString& menuName, const QString& separatorName, const QString& grouping) { MenuWrapper* menuObj = getMenu(menuName); if (menuObj) { addDisabledActionAndSeparator(menuObj, separatorName); @@ -952,15 +1031,16 @@ void Menu::addMenuItem(const MenuItemProperties& properties) { QAction* menuItemAction = NULL; if (properties.isSeparator) { - addDisabledActionAndSeparator(menuObj, properties.menuItemName, requestedPosition); + addDisabledActionAndSeparator(menuObj, properties.menuItemName, requestedPosition, properties.grouping); } else if (properties.isCheckable) { menuItemAction = addCheckableActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence, properties.isChecked, - MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), requestedPosition); + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), + requestedPosition, properties.grouping); } else { menuItemAction = addActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence, MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), - QAction::NoRole, requestedPosition); + QAction::NoRole, requestedPosition, properties.grouping); } if (shortcut && menuItemAction) { connect(shortcut, SIGNAL(activated()), menuItemAction, SLOT(trigger())); @@ -975,7 +1055,7 @@ void Menu::removeMenuItem(const QString& menu, const QString& menuitem) { removeAction(menuObj, menuitem); QMenuBar::repaint(); } -}; +} bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { QAction* menuItemAction = _actionHash.value(menuitem); @@ -983,7 +1063,31 @@ bool Menu::menuItemExists(const QString& menu, const QString& menuitem) { return (getMenu(menu) != NULL); } return false; -}; +} + +bool Menu::getGroupingIsVisible(const QString& grouping) { + if (grouping.isEmpty() || grouping.isNull()) { + return true; + } + if (_groupingVisible.contains(grouping)) { + return _groupingVisible[grouping]; + } + return false; +} + +void Menu::setGroupingIsVisible(const QString& grouping, bool isVisible) { + // NOTE: Default grouping always visible + if (grouping.isEmpty() || grouping.isNull()) { + return; + } + _groupingVisible[grouping] = isVisible; + + for (auto action: _groupingActions[grouping]) { + action->setVisible(isVisible); + } + + QMenuBar::repaint(); +} MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) { @@ -1005,8 +1109,8 @@ void MenuWrapper::setEnabled(bool enabled) { _realMenu->setEnabled(enabled); } -void MenuWrapper::addSeparator() { - _realMenu->addSeparator(); +QAction* MenuWrapper::addSeparator() { + return _realMenu->addSeparator(); } void MenuWrapper::addAction(QAction* action) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 3ff0b149f4..d6047bf711 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -30,7 +30,7 @@ public: QList actions(); MenuWrapper* addMenu(const QString& menuName); void setEnabled(bool enabled = true); - void addSeparator(); + QAction* addSeparator(); void addAction(QAction* action); QAction* addAction(const QString& menuName); @@ -74,28 +74,33 @@ public: const QObject* receiver = NULL, const char* member = NULL, QAction::MenuRole role = QAction::NoRole, - int menuItemLocation = UNSPECIFIED_POSITION); + int menuItemLocation = UNSPECIFIED_POSITION, + const QString& grouping = QString()); + QAction* addActionToQMenuAndActionHash(MenuWrapper* destinationMenu, QAction* action, const QString& actionName = QString(), const QKeySequence& shortcut = 0, QAction::MenuRole role = QAction::NoRole, - int menuItemLocation = UNSPECIFIED_POSITION); + int menuItemLocation = UNSPECIFIED_POSITION, + const QString& grouping = QString()); + QAction* addCheckableActionToQMenuAndActionHash(MenuWrapper* destinationMenu, const QString& actionName, const QKeySequence& shortcut = 0, const bool checked = false, const QObject* receiver = NULL, const char* member = NULL, - int menuItemLocation = UNSPECIFIED_POSITION); + int menuItemLocation = UNSPECIFIED_POSITION, + const QString& grouping = QString()); void removeAction(MenuWrapper* menu, const QString& actionName); public slots: - MenuWrapper* addMenu(const QString& menuName); + MenuWrapper* addMenu(const QString& menuName, const QString& grouping = QString()); void removeMenu(const QString& menuName); bool menuExists(const QString& menuName); - void addSeparator(const QString& menuName, const QString& separatorName); + void addSeparator(const QString& menuName, const QString& separatorName, const QString& grouping = QString()); void removeSeparator(const QString& menuName, const QString& separatorName); void addMenuItem(const MenuItemProperties& properties); void removeMenuItem(const QString& menuName, const QString& menuitem); @@ -103,6 +108,12 @@ public slots: bool isOptionChecked(const QString& menuOption) const; void setIsOptionChecked(const QString& menuOption, bool isChecked); + bool getGroupingIsVisible(const QString& grouping); + void setGroupingIsVisible(const QString& grouping, bool isVisible); /// NOTE: the "" grouping is always visible + + void toggleDeveloperMenus(); + void toggleAdvancedMenus(); + private: typedef void(*settingsAction)(Settings&, QAction&); static void loadAction(Settings& settings, QAction& action); @@ -111,8 +122,10 @@ private: void scanMenu(QMenu& menu, settingsAction modifySetting, Settings& settings); /// helper method to have separators with labels that are also compatible with OS X - void addDisabledActionAndSeparator(MenuWrapper* destinationMenu, const QString& actionName, - int menuItemLocation = UNSPECIFIED_POSITION); + void addDisabledActionAndSeparator(MenuWrapper* destinationMenu, + const QString& actionName, + int menuItemLocation = UNSPECIFIED_POSITION, + const QString& grouping = QString()); QAction* getActionFromName(const QString& menuName, MenuWrapper* menu); MenuWrapper* getSubMenuFromName(const QString& menuName, MenuWrapper* menu); @@ -123,6 +136,10 @@ private: int positionBeforeSeparatorIfNeeded(MenuWrapper* menu, int requestedPosition); QHash _actionHash; + + bool isValidGrouping(const QString& grouping) const { return grouping == "Advanced" || grouping == "Developer"; } + QHash _groupingVisible; + QHash> _groupingActions; }; namespace MenuOption { diff --git a/libraries/script-engine/src/MenuItemProperties.cpp b/libraries/script-engine/src/MenuItemProperties.cpp index 04c467c3b6..c5f037eba8 100644 --- a/libraries/script-engine/src/MenuItemProperties.cpp +++ b/libraries/script-engine/src/MenuItemProperties.cpp @@ -95,6 +95,7 @@ void menuItemPropertiesFromScriptValue(const QScriptValue& object, MenuItemPrope } properties.beforeItem = object.property("beforeItem").toVariant().toString(); properties.afterItem = object.property("afterItem").toVariant().toString(); + properties.grouping = object.property("grouping").toVariant().toString(); } diff --git a/libraries/script-engine/src/MenuItemProperties.h b/libraries/script-engine/src/MenuItemProperties.h index e58ebe2afb..68fd32a6fa 100644 --- a/libraries/script-engine/src/MenuItemProperties.h +++ b/libraries/script-engine/src/MenuItemProperties.h @@ -43,6 +43,8 @@ public: bool isCheckable; bool isChecked; bool isSeparator; + + QString grouping; /// Either: "", "Advanced", or "Developer" }; Q_DECLARE_METATYPE(MenuItemProperties) QScriptValue menuItemPropertiesToScriptValue(QScriptEngine* engine, const MenuItemProperties& props); diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index 41cf27efb2..2d9dd57ba9 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -95,6 +95,14 @@ void VrMenu::setRootMenu(QObject* rootMenu) { _rootMenu = rootMenu; } +void updateQmlItemFromAction(QObject* target, QAction* source) { + target->setProperty("checkable", source->isCheckable()); + target->setProperty("enabled", source->isEnabled()); + target->setProperty("text", source->text()); + target->setProperty("checked", source->isChecked()); + target->setProperty("visible", source->isVisible()); +} + void VrMenu::addMenu(QMenu* menu) { Q_ASSERT(!MenuUserData::forObject(menu)); QObject* parent = menu->parent(); @@ -119,14 +127,12 @@ void VrMenu::addMenu(QMenu* menu) { // Bind the QML and Widget together new MenuUserData(menu, result); -} + auto menuAction = menu->menuAction(); + updateQmlItemFromAction(result, menuAction); + QObject::connect(menuAction, &QAction::changed, [=] { + updateQmlItemFromAction(result, menuAction); + }); -void updateQmlItemFromAction(QObject* target, QAction* source) { - target->setProperty("checkable", source->isCheckable()); - target->setProperty("enabled", source->isEnabled()); - target->setProperty("visible", source->isVisible()); - target->setProperty("text", source->text()); - target->setProperty("checked", source->isChecked()); } void bindActionToQmlAction(QObject* qmlAction, QAction* action) {