From 03f8885cad56ad25bbb15722664b20bfb7289ef2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 24 Feb 2014 19:09:22 -0800 Subject: [PATCH 01/13] first cut at menus JS --- examples/menuExample.js | 35 ++++++++++ interface/src/Application.cpp | 2 + interface/src/Application.h | 1 + interface/src/Menu.cpp | 118 +++++++++++++++++++++++++++++++++- interface/src/Menu.h | 42 ++++++++++++ 5 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 examples/menuExample.js diff --git a/examples/menuExample.js b/examples/menuExample.js new file mode 100644 index 0000000000..2fc0ab6661 --- /dev/null +++ b/examples/menuExample.js @@ -0,0 +1,35 @@ +// +// menuExample.js +// hifi +// +// Created by Brad Hefta-Gaub on 2/24/14 +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// +// This is an example script that demonstrates use of the Menu object +// + + +function setupMenus() { + Menu.addTopMenu("Foo"); + Menu.addMenuItem("Foo","Foo item 1", { text: "F", isControl: true} ); + Menu.addMenuItem("Foo","Foo item 2"); + Menu.addTopMenu("Bar"); +} + +function scriptEnding() { + print("SCRIPT ENDNG!!!\n"); + + Menu.removeTopMenu("Foo"); + Menu.removeTopMenu("Bar"); +} + +function menuItemEvent(menuItem) { + print("menuItemEvent() in JS... menuItem=" + menuItem); +} + +setupMenus(); + +// register our scriptEnding callback +Script.scriptEnding.connect(scriptEnding); + +Menu.menuItemEvent.connect(menuItemEvent); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 99e3f5be12..28cd232bd3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -346,6 +346,7 @@ Application::~Application() { VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown Menu::getInstance()->deleteLater(); + MenuScriptingInterface::deleteLaterIfExists(); _myAvatar = NULL; @@ -4267,6 +4268,7 @@ void Application::loadScript(const QString& fileNameString) { connect(scriptEngine, SIGNAL(finished(const QString&)), clipboardScriptable, SLOT(deleteLater())); scriptEngine->registerGlobalObject("Overlays", &_overlays); + scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); QThread* workerThread = new QThread(this); diff --git a/interface/src/Application.h b/interface/src/Application.h index f3f4f3dbb2..c2cb73d9a2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -36,6 +36,7 @@ #include "DatagramProcessor.h" #include "Environment.h" #include "GLCanvas.h" +#include "Menu.h" #include "MetavoxelSystem.h" #include "PacketHeaders.h" #include "PieMenu.h" diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 7e5fe63524..5fdc48dd85 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -493,7 +493,6 @@ Menu::Menu() : QAction* helpAction = helpMenu->addAction(MenuOption::AboutApp); connect(helpAction, SIGNAL(triggered()), this, SLOT(aboutApp())); #endif - } Menu::~Menu() { @@ -1115,7 +1114,6 @@ void Menu::showMetavoxelEditor() { _MetavoxelEditor = new MetavoxelEditor(); } _MetavoxelEditor->raise(); - _MetavoxelEditor->activateWindow(); } void Menu::audioMuteToggled() { @@ -1286,3 +1284,119 @@ QString Menu::replaceLastOccurrence(QChar search, QChar replace, QString string) return string; } + +void Menu::addTopMenu(const QString& menu) { + QMenu* newMenu = addMenu(menu); + //newMenu->setVisible(true); + //addDisabledActionAndSeparator(newMenu, "testing"); + + QMenuBar::repaint(); + + QList topLevelMenus = actions(); + foreach (QAction* topLevelMenuAction, topLevelMenus) { + qDebug() << "menu:" << topLevelMenuAction->text(); + } +} + +void Menu::removeTopMenu(const QString& menu) { + QList topLevelMenus = actions(); + foreach (QAction* topLevelMenuAction, topLevelMenus) { + if (topLevelMenuAction->text() == menu) { + QMenuBar::removeAction(topLevelMenuAction); + } + } +} + +void Menu::addMenuItem(const QString& menu, const QString& menuitem) { + KeyEvent noKey; + addMenuItem(menu, menuitem, noKey); +} + +void Menu::addMenuItem(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey) { + const QKeySequence& shortcut = 0; + + QList topLevelMenus = actions(); + foreach (QAction* topLevelMenuAction, topLevelMenus) { + if (topLevelMenuAction->text() == menu) { + // add the menu item here... + QMenu* menuObj = topLevelMenuAction->menu(); + if (menuObj) { + addActionToQMenuAndActionHash(menuObj, menuitem, shortcut, + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); + } + } + } + QMenuBar::repaint(); +} + +void Menu::removeMenuItem(const QString& menu, const QString& menuitem) { +}; + + + +MenuScriptingInterface* MenuScriptingInterface::_instance = NULL; +QMutex MenuScriptingInterface::_instanceMutex; + + +MenuScriptingInterface* MenuScriptingInterface::getInstance() { + // lock the menu instance mutex to make sure we don't race and create two menus and crash + _instanceMutex.lock(); + + if (!_instance) { + qDebug("First call to MenuScriptingInterface::getInstance() - initing menu."); + + _instance = new MenuScriptingInterface(); + } + + _instanceMutex.unlock(); + + return _instance; +} + +void MenuScriptingInterface::deleteLaterIfExists() { + _instanceMutex.lock(); + if (_instance) { + _instance->deleteLater(); + _instance = NULL; + } + _instanceMutex.unlock(); +} + +void MenuScriptingInterface::menuItemTriggered() { + QAction* menuItemAction = dynamic_cast(sender()); + if (menuItemAction) { + qDebug() << "menu selected:" << menuItemAction->text(); + + // emit the event + emit menuItemEvent(menuItemAction->text()); + } +} + + + +void MenuScriptingInterface::addTopMenu(const QString& menu) { + QMetaObject::invokeMethod(Menu::getInstance(), "addTopMenu", Q_ARG(const QString&, menu)); +} + +void MenuScriptingInterface::removeTopMenu(const QString& menu) { + QMetaObject::invokeMethod(Menu::getInstance(), "removeTopMenu", Q_ARG(const QString&, menu)); +} + +void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem), + Q_ARG(const KeyEvent&, shortcutKey)); +} + +void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem)); +} + +void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& menuitem) { + QMetaObject::invokeMethod(Menu::getInstance(), "removeMenuItem", + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem)); +}; diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 262b618526..379606f235 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -15,6 +15,7 @@ #include #include +#include const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; @@ -112,6 +113,13 @@ public slots: void goTo(); void pasteToVoxel(); + void addTopMenu(const QString& menu); + void removeTopMenu(const QString& menu); + void addMenuItem(const QString& menu, const QString& menuitem); + void addMenuItem(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey); + void removeMenuItem(const QString& menu, const QString& menuitem); + + private slots: void aboutApp(); void login(); @@ -301,4 +309,38 @@ namespace MenuOption { const QString VoxelTextures = "Voxel Textures"; } + +class MenuScriptingInterface : public QObject { + Q_OBJECT + MenuScriptingInterface() { }; +public: + static MenuScriptingInterface* getInstance(); + static void deleteLaterIfExists(); +public slots: + void addTopMenu(const QString& topMenuName); + void removeTopMenu(const QString& topMenuName); + + // TODO: how should we expose general nested sub menus to JS + // we could use a string qualifier, like "Developer > Voxel Options" but that has the side effect of + // preventing use of whatever stop character we pick. + // + // we could use a string array, but that makes things a little harder for the JS user + // + //void addSubMenu(const QString& topMenuName, const QString& menuitem); + //void removeSubMenu(const QString& topMenuName, const QString& menuitem); + + void addMenuItem(const QString& topMenuName, const QString& menuitem, const KeyEvent& shortcutKey); + void addMenuItem(const QString& topMenuName, const QString& menuitem); + void removeMenuItem(const QString& topMenuName, const QString& menuitem); + void menuItemTriggered(); + +signals: + //void keyPressEvent(const KeyEvent& event); + void menuItemEvent(const QString& menuItem); + +private: + static QMutex _instanceMutex; + static MenuScriptingInterface* _instance; +}; + #endif /* defined(__hifi__Menu__) */ From a3d0c20516c831cf8eec4a8783e500c9dfadc729 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 24 Feb 2014 20:49:06 -0800 Subject: [PATCH 02/13] better support for shortcuts --- examples/menuExample.js | 8 +++-- interface/src/Menu.cpp | 40 +++++++++++++--------- interface/src/Menu.h | 5 ++- libraries/script-engine/src/EventTypes.cpp | 24 +++++++++++++ libraries/script-engine/src/EventTypes.h | 2 ++ 5 files changed, 60 insertions(+), 19 deletions(-) diff --git a/examples/menuExample.js b/examples/menuExample.js index 2fc0ab6661..d58e3d9ac9 100644 --- a/examples/menuExample.js +++ b/examples/menuExample.js @@ -11,9 +11,13 @@ function setupMenus() { Menu.addTopMenu("Foo"); - Menu.addMenuItem("Foo","Foo item 1", { text: "F", isControl: true} ); - Menu.addMenuItem("Foo","Foo item 2"); + Menu.addMenuItem("Foo","Foo item 1", "SHIFT+CTRL+F" ); + Menu.addMenuItem("Foo","Foo item 2", "SHIFT+F" ); + Menu.addMenuItem("Foo","Foo item 3", "META+F" ); + Menu.addMenuItem("Foo","Foo item 4", "ALT+F" ); Menu.addTopMenu("Bar"); + Menu.addMenuItemWithKeyEvent("Bar","Bar item 1", { text: "b" } ); + Menu.addMenuItemWithKeyEvent("Bar","Bar item 2", { text: "B", isControl: true } ); } function scriptEnding() { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5fdc48dd85..c7a3fa5115 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1286,9 +1287,7 @@ QString Menu::replaceLastOccurrence(QChar search, QChar replace, QString string) } void Menu::addTopMenu(const QString& menu) { - QMenu* newMenu = addMenu(menu); - //newMenu->setVisible(true); - //addDisabledActionAndSeparator(newMenu, "testing"); + addMenu(menu); QMenuBar::repaint(); @@ -1313,16 +1312,27 @@ void Menu::addMenuItem(const QString& menu, const QString& menuitem) { } void Menu::addMenuItem(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey) { - const QKeySequence& shortcut = 0; - + QKeySequence shortcut(shortcutKey); + addMenuItem(menu, menuitem, shortcut); +} + +void Menu::addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey) { + QKeySequence shortcut(shortcutKey); + addMenuItem(menu, menuitem, shortcut); +} + +void Menu::addMenuItem(const QString& menu, const QString& menuitem, const QKeySequence& shortcutKey) { QList topLevelMenus = actions(); foreach (QAction* topLevelMenuAction, topLevelMenus) { if (topLevelMenuAction->text() == menu) { // add the menu item here... QMenu* menuObj = topLevelMenuAction->menu(); if (menuObj) { - addActionToQMenuAndActionHash(menuObj, menuitem, shortcut, + QShortcut* shortcut = new QShortcut(shortcutKey, this); + QAction* menuItemAction = addActionToQMenuAndActionHash(menuObj, menuitem, shortcutKey, MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); + + connect(shortcut, SIGNAL(activated()), menuItemAction, SLOT(trigger())); } } } @@ -1333,23 +1343,16 @@ void Menu::removeMenuItem(const QString& menu, const QString& menuitem) { }; - MenuScriptingInterface* MenuScriptingInterface::_instance = NULL; QMutex MenuScriptingInterface::_instanceMutex; - MenuScriptingInterface* MenuScriptingInterface::getInstance() { // lock the menu instance mutex to make sure we don't race and create two menus and crash _instanceMutex.lock(); - if (!_instance) { - qDebug("First call to MenuScriptingInterface::getInstance() - initing menu."); - _instance = new MenuScriptingInterface(); } - _instanceMutex.unlock(); - return _instance; } @@ -1365,8 +1368,6 @@ void MenuScriptingInterface::deleteLaterIfExists() { void MenuScriptingInterface::menuItemTriggered() { QAction* menuItemAction = dynamic_cast(sender()); if (menuItemAction) { - qDebug() << "menu selected:" << menuItemAction->text(); - // emit the event emit menuItemEvent(menuItemAction->text()); } @@ -1382,13 +1383,20 @@ void MenuScriptingInterface::removeTopMenu(const QString& menu) { QMetaObject::invokeMethod(Menu::getInstance(), "removeTopMenu", Q_ARG(const QString&, menu)); } -void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey) { +void MenuScriptingInterface::addMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey) { QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const QString&, menu), Q_ARG(const QString&, menuitem), Q_ARG(const KeyEvent&, shortcutKey)); } +void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem), + Q_ARG(const QString&, shortcutKey)); +} + void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem) { QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const QString&, menu), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 379606f235..ad6d81ada4 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -117,6 +117,8 @@ public slots: void removeTopMenu(const QString& menu); void addMenuItem(const QString& menu, const QString& menuitem); void addMenuItem(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey); + void addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey); + void addMenuItem(const QString& topMenuName, const QString& menuitem, const QKeySequence& shortcutKey); void removeMenuItem(const QString& menu, const QString& menuitem); @@ -329,7 +331,8 @@ public slots: //void addSubMenu(const QString& topMenuName, const QString& menuitem); //void removeSubMenu(const QString& topMenuName, const QString& menuitem); - void addMenuItem(const QString& topMenuName, const QString& menuitem, const KeyEvent& shortcutKey); + void addMenuItemWithKeyEvent(const QString& topMenuName, const QString& menuitem, const KeyEvent& shortcutKey); + void addMenuItem(const QString& topMenuName, const QString& menuitem, const QString& shortcutKey); void addMenuItem(const QString& topMenuName, const QString& menuitem); void removeMenuItem(const QString& topMenuName, const QString& menuitem); void menuItemTriggered(); diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index c8451d84a7..6e7297b720 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -126,6 +126,30 @@ bool KeyEvent::operator==(const KeyEvent& other) const { && other.isKeypad == isKeypad; } + +KeyEvent::operator QKeySequence() const { + int resultCode = 0; + if (text >= "a" && text <= "z") { + resultCode = text.toUpper().at(0).unicode(); + } else { + resultCode = key; + } + + if (isMeta) { + resultCode |= Qt::META; + } + if (isAlt) { + resultCode |= Qt::ALT; + } + if (isControl) { + resultCode |= Qt::CTRL; + } + if (isShifted) { + resultCode |= Qt::SHIFT; + } + return QKeySequence(resultCode); +} + QScriptValue keyEventToScriptValue(QScriptEngine* engine, const KeyEvent& event) { QScriptValue obj = engine->newObject(); obj.setProperty("key", event.key); diff --git a/libraries/script-engine/src/EventTypes.h b/libraries/script-engine/src/EventTypes.h index a416747a85..5cd31f190c 100644 --- a/libraries/script-engine/src/EventTypes.h +++ b/libraries/script-engine/src/EventTypes.h @@ -24,6 +24,8 @@ public: KeyEvent(); KeyEvent(const QKeyEvent& event); bool operator==(const KeyEvent& other) const; + operator QKeySequence() const; + int key; QString text; bool isShifted; From 374b12980b92dfb43ca5ffdc8115331c09476991 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 24 Feb 2014 23:42:05 -0800 Subject: [PATCH 03/13] added checkable menus and sub menus --- examples/menuExample.js | 29 ++++- interface/src/Menu.cpp | 229 ++++++++++++++++++++++++++++++++-------- interface/src/Menu.h | 56 ++++++---- 3 files changed, 240 insertions(+), 74 deletions(-) diff --git a/examples/menuExample.js b/examples/menuExample.js index d58e3d9ac9..5d8f8f22f2 100644 --- a/examples/menuExample.js +++ b/examples/menuExample.js @@ -10,25 +10,44 @@ function setupMenus() { - Menu.addTopMenu("Foo"); + Menu.addMenu("Foo"); Menu.addMenuItem("Foo","Foo item 1", "SHIFT+CTRL+F" ); Menu.addMenuItem("Foo","Foo item 2", "SHIFT+F" ); Menu.addMenuItem("Foo","Foo item 3", "META+F" ); - Menu.addMenuItem("Foo","Foo item 4", "ALT+F" ); - Menu.addTopMenu("Bar"); + Menu.addCheckableMenuItem("Foo","Foo item 4", "ALT+F", true); + Menu.addMenuItem("Foo","Remove Foo item 4"); + Menu.addMenuItem("Foo","Remove Foo"); + Menu.addMenu("Bar"); Menu.addMenuItemWithKeyEvent("Bar","Bar item 1", { text: "b" } ); Menu.addMenuItemWithKeyEvent("Bar","Bar item 2", { text: "B", isControl: true } ); + Menu.addMenu("Bar > Spam"); + Menu.addMenuItem("Bar > Spam","Spam item 1"); + Menu.addCheckableMenuItem("Bar > Spam","Spam item 2",false); + Menu.addMenuItem("Bar > Spam","Remove Spam item 2"); + Menu.addMenuItem("Foo","Remove Spam item 2"); } function scriptEnding() { print("SCRIPT ENDNG!!!\n"); - Menu.removeTopMenu("Foo"); - Menu.removeTopMenu("Bar"); + Menu.removeMenu("Foo"); + Menu.removeMenu("Bar"); } function menuItemEvent(menuItem) { print("menuItemEvent() in JS... menuItem=" + menuItem); + if (menuItem == "Foo item 4") { + print(" checked=" + Menu.isOptionChecked("Foo item 4")); + } + if (menuItem == "Remove Foo item 4") { + Menu.removeMenuItem("Foo", "Foo item 4"); + } + if (menuItem == "Remove Foo") { + Menu.removeMenu("Foo"); + } + if (menuItem == "Remove Spam item 2") { + Menu.removeMenuItem("Bar > Spam", "Spam item 2"); + } } setupMenus(); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c7a3fa5115..5f616826f0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1286,63 +1286,162 @@ QString Menu::replaceLastOccurrence(QChar search, QChar replace, QString string) return string; } -void Menu::addTopMenu(const QString& menu) { - addMenu(menu); - - QMenuBar::repaint(); - - QList topLevelMenus = actions(); - foreach (QAction* topLevelMenuAction, topLevelMenus) { - qDebug() << "menu:" << topLevelMenuAction->text(); +QAction* Menu::getActionFromName(const QString& menuName, QMenu* menu) { + QList menuActions; + if (menu) { + menuActions = menu->actions(); + } else { + menuActions = actions(); } -} - -void Menu::removeTopMenu(const QString& menu) { - QList topLevelMenus = actions(); - foreach (QAction* topLevelMenuAction, topLevelMenus) { - if (topLevelMenuAction->text() == menu) { - QMenuBar::removeAction(topLevelMenuAction); + + foreach (QAction* menuAction, menuActions) { + if (menuName == menuAction->text()) { + return menuAction; } } + return NULL; } -void Menu::addMenuItem(const QString& menu, const QString& menuitem) { - KeyEvent noKey; - addMenuItem(menu, menuitem, noKey); +QMenu* Menu::getSubMenuFromName(const QString& menuName, QMenu* menu) { + QAction* action = getActionFromName(menuName, menu); + if (action) { + return action->menu(); + } + return NULL; } -void Menu::addMenuItem(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey) { - QKeySequence shortcut(shortcutKey); - addMenuItem(menu, menuitem, shortcut); +QMenu* Menu::getMenuParent(const QString& menuName, QString& finalMenuPart) { + QStringList menuTree = menuName.split(">"); + QMenu* parent = NULL; + QMenu* menu = NULL; + foreach (QString menuTreePart, menuTree) { + parent = menu; + finalMenuPart = menuTreePart.trimmed(); + menu = getSubMenuFromName(finalMenuPart, parent); + if (!menu) { + break; + } + } + return parent; } -void Menu::addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey) { - QKeySequence shortcut(shortcutKey); - addMenuItem(menu, menuitem, shortcut); +QMenu* Menu::getMenu(const QString& menuName) { + QStringList menuTree = menuName.split(">"); + QMenu* parent = NULL; + QMenu* menu = NULL; + int item = 0; + foreach (QString menuTreePart, menuTree) { + menu = getSubMenuFromName(menuTreePart.trimmed(), parent); + if (!menu) { + break; + } + parent = menu; + item++; + } + return menu; } -void Menu::addMenuItem(const QString& menu, const QString& menuitem, const QKeySequence& shortcutKey) { - QList topLevelMenus = actions(); - foreach (QAction* topLevelMenuAction, topLevelMenus) { - if (topLevelMenuAction->text() == menu) { - // add the menu item here... - QMenu* menuObj = topLevelMenuAction->menu(); - if (menuObj) { - QShortcut* shortcut = new QShortcut(shortcutKey, this); - QAction* menuItemAction = addActionToQMenuAndActionHash(menuObj, menuitem, shortcutKey, - MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); +QAction* Menu::getMenuAction(const QString& menuName) { + QStringList menuTree = menuName.split(">"); + QMenu* parent = NULL; + QAction* action = NULL; + foreach (QString menuTreePart, menuTree) { + action = getActionFromName(menuTreePart.trimmed(), parent); + if (!action) { + break; + } + parent = action->menu(); + } + return action; +} - connect(shortcut, SIGNAL(activated()), menuItemAction, SLOT(trigger())); +QMenu* Menu::addMenu(const QString& menuName) { + QStringList menuTree = menuName.split(">"); + QMenu* addTo = NULL; + QMenu* menu = NULL; + foreach (QString menuTreePart, menuTree) { + menu = getSubMenuFromName(menuTreePart.trimmed(), addTo); + if (!menu) { + if (!addTo) { + menu = QMenuBar::addMenu(menuTreePart.trimmed()); + } else { + menu = addTo->addMenu(menuTreePart.trimmed()); } } + addTo = menu; } + QMenuBar::repaint(); + return menu; +} + +void Menu::removeMenu(const QString& menuName) { + QAction* action = getMenuAction(menuName); + + // only proceed if the menu actually exists + if (action) { + QString finalMenuPart; + QMenu* parent = getMenuParent(menuName, finalMenuPart); + + if (parent) { + removeAction(parent, finalMenuPart); + } else { + QMenuBar::removeAction(action); + } + + QMenuBar::repaint(); + } +} + +void Menu::addMenuItem(const QString& menuName, const QString& menuitem, bool checkable, bool checked) { + QMenu* menuObj = getMenu(menuName); + if (menuObj) { + if (checkable) { + addCheckableActionToQMenuAndActionHash(menuObj, menuitem, 0, checked, + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); + } else { + addActionToQMenuAndActionHash(menuObj, menuitem, 0, + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); + } + QMenuBar::repaint(); + } +} + +void Menu::addMenuItem(const QString& menuName, const QString& menuitem, const KeyEvent& shortcutKey, bool checkable, bool checked) { + QKeySequence shortcut(shortcutKey); + addMenuItem(menuName, menuitem, shortcut, checkable, checked); +} + +void Menu::addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey, bool checkable, bool checked) { + QKeySequence shortcut(shortcutKey); + addMenuItem(menuName, menuitem, shortcut, checkable, checked); +} + +void Menu::addMenuItem(const QString& menuName, const QString& menuitem, const QKeySequence& shortcutKey, bool checkable, bool checked) { + QMenu* menuObj = getMenu(menuName); + if (menuObj) { + QShortcut* shortcut = new QShortcut(shortcutKey, this); + QAction* menuItemAction; + if (checkable) { + menuItemAction = addCheckableActionToQMenuAndActionHash(menuObj, menuitem, shortcutKey, checked, + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); + } else { + menuItemAction = addActionToQMenuAndActionHash(menuObj, menuitem, shortcutKey, + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); + } + connect(shortcut, SIGNAL(activated()), menuItemAction, SLOT(trigger())); + QMenuBar::repaint(); + } } void Menu::removeMenuItem(const QString& menu, const QString& menuitem) { + QMenu* menuObj = getMenu(menu); + if (menuObj) { + removeAction(menuObj, menuitem); + } + QMenuBar::repaint(); }; - MenuScriptingInterface* MenuScriptingInterface::_instance = NULL; QMutex MenuScriptingInterface::_instanceMutex; @@ -1373,34 +1472,64 @@ void MenuScriptingInterface::menuItemTriggered() { } } - - -void MenuScriptingInterface::addTopMenu(const QString& menu) { - QMetaObject::invokeMethod(Menu::getInstance(), "addTopMenu", Q_ARG(const QString&, menu)); +void MenuScriptingInterface::addMenu(const QString& menu) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenu", Q_ARG(const QString&, menu)); } -void MenuScriptingInterface::removeTopMenu(const QString& menu) { - QMetaObject::invokeMethod(Menu::getInstance(), "removeTopMenu", Q_ARG(const QString&, menu)); +void MenuScriptingInterface::removeMenu(const QString& menu) { + QMetaObject::invokeMethod(Menu::getInstance(), "removeMenu", Q_ARG(const QString&, menu)); } void MenuScriptingInterface::addMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const QString&, menu), Q_ARG(const QString&, menuitem), - Q_ARG(const KeyEvent&, shortcutKey)); + Q_ARG(const KeyEvent&, shortcutKey), + Q_ARG(bool, false), + Q_ARG(bool, false)); } void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey) { QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const QString&, menu), Q_ARG(const QString&, menuitem), - Q_ARG(const QString&, shortcutKey)); + Q_ARG(const QString&, shortcutKey), + Q_ARG(bool, false), + Q_ARG(bool, false)); } void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem) { QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem)); + Q_ARG(const QString&, menuitem), + Q_ARG(bool, false), + Q_ARG(bool, false)); +} + +void MenuScriptingInterface::addCheckableMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey, bool checked) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem), + Q_ARG(const KeyEvent&, shortcutKey), + Q_ARG(bool, true), + Q_ARG(bool, checked)); +} + +void MenuScriptingInterface::addCheckableMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey, bool checked) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem), + Q_ARG(const QString&, shortcutKey), + Q_ARG(bool, true), + Q_ARG(bool, checked)); +} + +void MenuScriptingInterface::addCheckableMenuItem(const QString& menu, const QString& menuitem, bool checked) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem), + Q_ARG(bool, true), + Q_ARG(bool, checked)); } void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& menuitem) { @@ -1408,3 +1537,11 @@ void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& Q_ARG(const QString&, menu), Q_ARG(const QString&, menuitem)); }; + +bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { + return Menu::getInstance()->isOptionChecked(menuOption); +} + +void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool isChecked) { + return Menu::getInstance()->setIsOptionChecked(menuOption, isChecked); +} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index ad6d81ada4..421d61c052 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -113,12 +113,12 @@ public slots: void goTo(); void pasteToVoxel(); - void addTopMenu(const QString& menu); - void removeTopMenu(const QString& menu); - void addMenuItem(const QString& menu, const QString& menuitem); - void addMenuItem(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey); - void addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey); - void addMenuItem(const QString& topMenuName, const QString& menuitem, const QKeySequence& shortcutKey); + QMenu* addMenu(const QString& menu); + void removeMenu(const QString& menu); + void addMenuItem(const QString& menu, const QString& menuitem, bool checkable, bool checked); + void addMenuItem(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey, bool checkable, bool checked); + void addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey, bool checkable, bool checked); + void addMenuItem(const QString& topMenuName, const QString& menuitem, const QKeySequence& shortcutKey, bool checkable, bool checked); void removeMenuItem(const QString& menu, const QString& menuitem); @@ -164,6 +164,14 @@ private: void addAvatarCollisionSubMenu(QMenu* overMenu); + QAction* getActionFromName(const QString& menuName, QMenu* menu); + QMenu* getSubMenuFromName(const QString& menuName, QMenu* menu); + QMenu* getMenuParent(const QString& menuName, QString& finalMenuPart); + + QAction* getMenuAction(const QString& menuName); + QMenu* getMenu(const QString& menuName); + + QHash _actionHash; int _audioJitterBufferSamples; /// number of extra samples to wait before starting audio playback BandwidthDialog* _bandwidthDialog; @@ -318,27 +326,29 @@ class MenuScriptingInterface : public QObject { public: static MenuScriptingInterface* getInstance(); static void deleteLaterIfExists(); -public slots: - void addTopMenu(const QString& topMenuName); - void removeTopMenu(const QString& topMenuName); - // TODO: how should we expose general nested sub menus to JS - // we could use a string qualifier, like "Developer > Voxel Options" but that has the side effect of - // preventing use of whatever stop character we pick. - // - // we could use a string array, but that makes things a little harder for the JS user - // - //void addSubMenu(const QString& topMenuName, const QString& menuitem); - //void removeSubMenu(const QString& topMenuName, const QString& menuitem); - - void addMenuItemWithKeyEvent(const QString& topMenuName, const QString& menuitem, const KeyEvent& shortcutKey); - void addMenuItem(const QString& topMenuName, const QString& menuitem, const QString& shortcutKey); - void addMenuItem(const QString& topMenuName, const QString& menuitem); - void removeMenuItem(const QString& topMenuName, const QString& menuitem); +private slots: + friend class Menu; void menuItemTriggered(); + +public slots: + void addMenu(const QString& menuName); + void removeMenu(const QString& menuName); + + void addMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey); + void addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey); + void addMenuItem(const QString& menuName, const QString& menuitem); + + void addCheckableMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey, bool checked); + void addCheckableMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey, bool checked); + void addCheckableMenuItem(const QString& menuName, const QString& menuitem, bool checked); + + void removeMenuItem(const QString& menuName, const QString& menuitem); + + bool isOptionChecked(const QString& menuOption); + void setIsOptionChecked(const QString& menuOption, bool isChecked); signals: - //void keyPressEvent(const KeyEvent& event); void menuItemEvent(const QString& menuItem); private: From cb01c1ee1040b51002b956408f7b0b634d918d19 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 24 Feb 2014 23:53:26 -0800 Subject: [PATCH 04/13] add separator support --- examples/menuExample.js | 2 ++ interface/src/Menu.cpp | 14 ++++++++++++++ interface/src/Menu.h | 17 ++++++++++------- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/examples/menuExample.js b/examples/menuExample.js index 5d8f8f22f2..c62e4616ec 100644 --- a/examples/menuExample.js +++ b/examples/menuExample.js @@ -15,6 +15,7 @@ function setupMenus() { Menu.addMenuItem("Foo","Foo item 2", "SHIFT+F" ); Menu.addMenuItem("Foo","Foo item 3", "META+F" ); Menu.addCheckableMenuItem("Foo","Foo item 4", "ALT+F", true); + Menu.addSeparator("Foo","Removable Tools"); Menu.addMenuItem("Foo","Remove Foo item 4"); Menu.addMenuItem("Foo","Remove Foo"); Menu.addMenu("Bar"); @@ -23,6 +24,7 @@ function setupMenus() { Menu.addMenu("Bar > Spam"); Menu.addMenuItem("Bar > Spam","Spam item 1"); Menu.addCheckableMenuItem("Bar > Spam","Spam item 2",false); + Menu.addSeparator("Bar > Spam","Other Items"); Menu.addMenuItem("Bar > Spam","Remove Spam item 2"); Menu.addMenuItem("Foo","Remove Spam item 2"); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5f616826f0..c7d12dd80d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1393,6 +1393,14 @@ void Menu::removeMenu(const QString& menuName) { } } +void Menu::addSeparator(const QString& menuName, const QString& separatorName) { + QMenu* menuObj = getMenu(menuName); + if (menuObj) { + addDisabledActionAndSeparator(menuObj, separatorName); + } +} + + void Menu::addMenuItem(const QString& menuName, const QString& menuitem, bool checkable, bool checked) { QMenu* menuObj = getMenu(menuName); if (menuObj) { @@ -1480,6 +1488,12 @@ void MenuScriptingInterface::removeMenu(const QString& menu) { QMetaObject::invokeMethod(Menu::getInstance(), "removeMenu", Q_ARG(const QString&, menu)); } +void MenuScriptingInterface::addSeparator(const QString& menuName, const QString& separatorName) { + QMetaObject::invokeMethod(Menu::getInstance(), "addSeparator", + Q_ARG(const QString&, menuName), + Q_ARG(const QString&, separatorName)); +} + void MenuScriptingInterface::addMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey) { QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const QString&, menu), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 421d61c052..8fe49a3ac2 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -113,13 +113,14 @@ public slots: void goTo(); void pasteToVoxel(); - QMenu* addMenu(const QString& menu); - void removeMenu(const QString& menu); - void addMenuItem(const QString& menu, const QString& menuitem, bool checkable, bool checked); - void addMenuItem(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey, bool checkable, bool checked); - void addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey, bool checkable, bool checked); - void addMenuItem(const QString& topMenuName, const QString& menuitem, const QKeySequence& shortcutKey, bool checkable, bool checked); - void removeMenuItem(const QString& menu, const QString& menuitem); + QMenu* addMenu(const QString& menuName); + void removeMenu(const QString& menuName); + void addSeparator(const QString& menuName, const QString& separatorName); + void addMenuItem(const QString& menuName, const QString& menuitem, bool checkable, bool checked); + void addMenuItem(const QString& menuName, const QString& menuitem, const KeyEvent& shortcutKey, bool checkable, bool checked); + void addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey, bool checkable, bool checked); + void addMenuItem(const QString& menuName, const QString& menuitem, const QKeySequence& shortcutKey, bool checkable, bool checked); + void removeMenuItem(const QString& menuName, const QString& menuitem); private slots: @@ -335,6 +336,8 @@ public slots: void addMenu(const QString& menuName); void removeMenu(const QString& menuName); + void addSeparator(const QString& menuName, const QString& separatorName); + void addMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey); void addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey); void addMenuItem(const QString& menuName, const QString& menuitem); From 74d48ab2395bbeb26f80c986fd5bf21ef7cdb2d2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 25 Feb 2014 10:23:59 -0800 Subject: [PATCH 05/13] added support for MenuItemProperties for addMenuItem, removed some cruft, beginning support for menu item placement --- examples/menuExample.js | 28 ++++- interface/src/Menu.cpp | 119 +++++++------------ interface/src/Menu.h | 21 ++-- libraries/script-engine/src/MenuTypes.cpp | 107 +++++++++++++++++ libraries/script-engine/src/MenuTypes.h | 48 ++++++++ libraries/script-engine/src/ScriptEngine.cpp | 3 +- libraries/shared/src/AbstractMenuInterface.h | 3 +- 7 files changed, 239 insertions(+), 90 deletions(-) create mode 100644 libraries/script-engine/src/MenuTypes.cpp create mode 100644 libraries/script-engine/src/MenuTypes.h diff --git a/examples/menuExample.js b/examples/menuExample.js index c62e4616ec..fc4b9c828d 100644 --- a/examples/menuExample.js +++ b/examples/menuExample.js @@ -14,19 +14,41 @@ function setupMenus() { Menu.addMenuItem("Foo","Foo item 1", "SHIFT+CTRL+F" ); Menu.addMenuItem("Foo","Foo item 2", "SHIFT+F" ); Menu.addMenuItem("Foo","Foo item 3", "META+F" ); - Menu.addCheckableMenuItem("Foo","Foo item 4", "ALT+F", true); + + Menu.addCheckableMenuItem("Foo","Foo item 4", true); + + Menu.addMenuItem({ + menuName: "Foo", + menuItemName: "Foo item 5", + shortcutKey: "ALT+F", + isCheckable: true, + isChecked: true + }); + + Menu.addSeparator("Foo","Removable Tools"); Menu.addMenuItem("Foo","Remove Foo item 4"); Menu.addMenuItem("Foo","Remove Foo"); Menu.addMenu("Bar"); - Menu.addMenuItemWithKeyEvent("Bar","Bar item 1", { text: "b" } ); - Menu.addMenuItemWithKeyEvent("Bar","Bar item 2", { text: "B", isControl: true } ); + + Menu.addMenuItem("Bar","Bar item 1", "b"); + Menu.addMenuItem({ + menuName: "Bar", + menuItemName: "Bar item 2", + shortcutKeyEvent: { text: "B", isControl: true } + }); + Menu.addMenu("Bar > Spam"); Menu.addMenuItem("Bar > Spam","Spam item 1"); Menu.addCheckableMenuItem("Bar > Spam","Spam item 2",false); Menu.addSeparator("Bar > Spam","Other Items"); Menu.addMenuItem("Bar > Spam","Remove Spam item 2"); Menu.addMenuItem("Foo","Remove Spam item 2"); + + Menu.addMenuItem({ menuName: "Foo", + menuItemName: "Remove Spam item 2" + }); + } function scriptEnding() { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index c7d12dd80d..d32aba7ab5 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -171,6 +171,13 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::ClickToFly); addAvatarCollisionSubMenu(editMenu); + + /** + // test insert in middle of edit... + QAction* physics = getMenuAction("Edit>Physics"); + QAction* testHack = new QAction("test", editMenu); + editMenu->insertAction(physics, testHack); + **/ QMenu* toolsMenu = addMenu("Tools"); @@ -681,7 +688,8 @@ QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu, const QKeySequence& shortcut, const QObject* receiver, const char* member, - QAction::MenuRole role) { + QAction::MenuRole role, + int menuItemLocation) { QAction* action; if (receiver && member) { @@ -702,8 +710,11 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu, const QKeySequence& shortcut, const bool checked, const QObject* receiver, - const char* member) { - QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member); + const char* member, + int menuItemLocation) { + + QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member, + QAction::NoRole, menuItemLocation); action->setCheckable(true); action->setChecked(checked); @@ -1400,44 +1411,33 @@ void Menu::addSeparator(const QString& menuName, const QString& separatorName) { } } - -void Menu::addMenuItem(const QString& menuName, const QString& menuitem, bool checkable, bool checked) { - QMenu* menuObj = getMenu(menuName); +void Menu::addMenuItem(const MenuItemProperties& properties) { + QMenu* menuObj = getMenu(properties.menuName); if (menuObj) { - if (checkable) { - addCheckableActionToQMenuAndActionHash(menuObj, menuitem, 0, checked, - MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); - } else { - addActionToQMenuAndActionHash(menuObj, menuitem, 0, - MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); + QShortcut* shortcut = NULL; + if (!properties.shortcutKeySequence.isEmpty()) { + shortcut = new QShortcut(properties.shortcutKey, this); } - QMenuBar::repaint(); - } -} - -void Menu::addMenuItem(const QString& menuName, const QString& menuitem, const KeyEvent& shortcutKey, bool checkable, bool checked) { - QKeySequence shortcut(shortcutKey); - addMenuItem(menuName, menuitem, shortcut, checkable, checked); -} - -void Menu::addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey, bool checkable, bool checked) { - QKeySequence shortcut(shortcutKey); - addMenuItem(menuName, menuitem, shortcut, checkable, checked); -} - -void Menu::addMenuItem(const QString& menuName, const QString& menuitem, const QKeySequence& shortcutKey, bool checkable, bool checked) { - QMenu* menuObj = getMenu(menuName); - if (menuObj) { - QShortcut* shortcut = new QShortcut(shortcutKey, this); + + /** + // test insert in middle of menu... + QAction* physics = getMenuAction("Edit>Physics"); + QAction* testHack = new QAction("test", editMenu); + editMenu->insertAction(gravity, testHack); + **/ + QAction* menuItemAction; - if (checkable) { - menuItemAction = addCheckableActionToQMenuAndActionHash(menuObj, menuitem, shortcutKey, checked, + if (properties.isCheckable) { + menuItemAction = addCheckableActionToQMenuAndActionHash(menuObj, properties.menuItemName, + properties.shortcutKeySequence, properties.isChecked, MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); } else { - menuItemAction = addActionToQMenuAndActionHash(menuObj, menuitem, shortcutKey, + menuItemAction = addActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence, MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); } - connect(shortcut, SIGNAL(activated()), menuItemAction, SLOT(trigger())); + if (shortcut) { + connect(shortcut, SIGNAL(activated()), menuItemAction, SLOT(trigger())); + } QMenuBar::repaint(); } } @@ -1494,56 +1494,29 @@ void MenuScriptingInterface::addSeparator(const QString& menuName, const QString Q_ARG(const QString&, separatorName)); } -void MenuScriptingInterface::addMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem), - Q_ARG(const KeyEvent&, shortcutKey), - Q_ARG(bool, false), - Q_ARG(bool, false)); +void MenuScriptingInterface::addMenuItem(const MenuItemProperties& properties) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); } void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem), - Q_ARG(const QString&, shortcutKey), - Q_ARG(bool, false), - Q_ARG(bool, false)); + MenuItemProperties properties(menu, menuitem, shortcutKey); + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); } void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem), - Q_ARG(bool, false), - Q_ARG(bool, false)); + MenuItemProperties properties(menu, menuitem); + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); } -void MenuScriptingInterface::addCheckableMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey, bool checked) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem), - Q_ARG(const KeyEvent&, shortcutKey), - Q_ARG(bool, true), - Q_ARG(bool, checked)); -} - -void MenuScriptingInterface::addCheckableMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey, bool checked) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem), - Q_ARG(const QString&, shortcutKey), - Q_ARG(bool, true), - Q_ARG(bool, checked)); +void MenuScriptingInterface::addCheckableMenuItem(const QString& menu, const QString& menuitem, + const QString& shortcutKey, bool checked) { + MenuItemProperties properties(menu, menuitem, shortcutKey, true, checked); + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); } void MenuScriptingInterface::addCheckableMenuItem(const QString& menu, const QString& menuitem, bool checked) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem), - Q_ARG(bool, true), - Q_ARG(bool, checked)); + MenuItemProperties properties(menu, menuitem, "", true, checked); + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); } void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& menuitem) { diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 8fe49a3ac2..963f17a572 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -16,6 +16,7 @@ #include #include +#include const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; @@ -53,6 +54,7 @@ class BandwidthDialog; class LodToolsDialog; class MetavoxelEditor; class VoxelStatsDialog; +class MenuItemProperties; class Menu : public QMenuBar, public AbstractMenuInterface { Q_OBJECT @@ -96,7 +98,8 @@ public: const QKeySequence& shortcut = 0, const QObject* receiver = NULL, const char* member = NULL, - QAction::MenuRole role = QAction::NoRole); + QAction::MenuRole role = QAction::NoRole, + int menuItemLocation = -1); virtual void removeAction(QMenu* menu, const QString& actionName); bool goToDestination(QString destination); void goToOrientation(QString orientation); @@ -116,13 +119,9 @@ public slots: QMenu* addMenu(const QString& menuName); void removeMenu(const QString& menuName); void addSeparator(const QString& menuName, const QString& separatorName); - void addMenuItem(const QString& menuName, const QString& menuitem, bool checkable, bool checked); - void addMenuItem(const QString& menuName, const QString& menuitem, const KeyEvent& shortcutKey, bool checkable, bool checked); - void addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey, bool checkable, bool checked); - void addMenuItem(const QString& menuName, const QString& menuitem, const QKeySequence& shortcutKey, bool checkable, bool checked); + void addMenuItem(const MenuItemProperties& properties); void removeMenuItem(const QString& menuName, const QString& menuitem); - private slots: void aboutApp(); void login(); @@ -159,7 +158,8 @@ private: const QKeySequence& shortcut = 0, const bool checked = false, const QObject* receiver = NULL, - const char* member = NULL); + const char* member = NULL, + int menuItemLocation = -1); void updateFrustumRenderModeAction(); @@ -320,7 +320,6 @@ namespace MenuOption { const QString VoxelTextures = "Voxel Textures"; } - class MenuScriptingInterface : public QObject { Q_OBJECT MenuScriptingInterface() { }; @@ -337,12 +336,10 @@ public slots: void removeMenu(const QString& menuName); void addSeparator(const QString& menuName, const QString& separatorName); - - void addMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey); + + void addMenuItem(const MenuItemProperties& properties); void addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey); void addMenuItem(const QString& menuName, const QString& menuitem); - - void addCheckableMenuItemWithKeyEvent(const QString& menu, const QString& menuitem, const KeyEvent& shortcutKey, bool checked); void addCheckableMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey, bool checked); void addCheckableMenuItem(const QString& menuName, const QString& menuitem, bool checked); diff --git a/libraries/script-engine/src/MenuTypes.cpp b/libraries/script-engine/src/MenuTypes.cpp new file mode 100644 index 0000000000..aaf205c939 --- /dev/null +++ b/libraries/script-engine/src/MenuTypes.cpp @@ -0,0 +1,107 @@ +// +// MenuTypes.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 1/28/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// +// Used to register meta-types with Qt for very various event types so that they can be exposed to our +// scripting engine + +#include +#include +#include "MenuTypes.h" + + +MenuItemProperties::MenuItemProperties() : + menuName(""), + menuItemName(""), + shortcutKey(""), + shortcutKeyEvent(), + shortcutKeySequence(), + position(-1), + beforeItem(""), + afterItem(""), + isCheckable(false), + isChecked(false) +{ +}; + +MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& menuItemName, + const QString& shortcutKey, bool checkable, bool checked) : + menuName(menuName), + menuItemName(menuItemName), + shortcutKey(shortcutKey), + shortcutKeyEvent(), + shortcutKeySequence(shortcutKey), + position(-1), + beforeItem(""), + afterItem(""), + isCheckable(checkable), + isChecked(checked) +{ +} + +MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& menuItemName, + const KeyEvent& shortcutKeyEvent, bool checkable, bool checked) : + menuName(menuName), + menuItemName(menuItemName), + shortcutKey(""), + shortcutKeyEvent(shortcutKeyEvent), + shortcutKeySequence(shortcutKeyEvent), + position(-1), + beforeItem(""), + afterItem(""), + isCheckable(checkable), + isChecked(checked) +{ +qDebug() << "MenuItemProperties::MenuItemProperties(... KeyEvent... )"; +qDebug() << "shortcutKeyEvent.text=" << shortcutKeyEvent.text; +qDebug() << "shortcutKeyEvent.key=" << shortcutKeyEvent.key; +qDebug() << "shortcutKeyEvent.isControl=" << shortcutKeyEvent.isControl; +qDebug() << "shortcutKeySequence=" << shortcutKeySequence; +} + +void registerMenuTypes(QScriptEngine* engine) { + qScriptRegisterMetaType(engine, menuItemPropertiesToScriptValue, menuItemPropertiesFromScriptValue); +} + +QScriptValue menuItemPropertiesToScriptValue(QScriptEngine* engine, const MenuItemProperties& properties) { + QScriptValue obj = engine->newObject(); + // not supported + return obj; +} + +void menuItemPropertiesFromScriptValue(const QScriptValue& object, MenuItemProperties& properties) { + properties.menuName = object.property("menuName").toVariant().toString(); + properties.menuItemName = object.property("menuItemName").toVariant().toString(); + properties.isCheckable = object.property("isCheckable").toVariant().toBool(); + properties.isChecked = object.property("isChecked").toVariant().toBool(); + + // handle the shortcut key options in order... + QScriptValue shortcutKeyValue = object.property("shortcutKey"); + if (shortcutKeyValue.isValid()) { +qDebug() << "got shortcutKey..."; + properties.shortcutKey = shortcutKeyValue.toVariant().toString(); + properties.shortcutKeySequence = properties.shortcutKey; + } else { +qDebug() << "testing shortcutKeyEvent..."; + QScriptValue shortcutKeyEventValue = object.property("shortcutKeyEvent"); + if (shortcutKeyEventValue.isValid()) { +qDebug() << "got shortcutKeyEvent..."; + keyEventFromScriptValue(shortcutKeyEventValue, properties.shortcutKeyEvent); +qDebug() << "shortcutKeyEvent.text=" << properties.shortcutKeyEvent.text; +qDebug() << "shortcutKeyEvent.key=" << properties.shortcutKeyEvent.key; +qDebug() << "shortcutKeyEvent.isControl=" << properties.shortcutKeyEvent.isControl; + + properties.shortcutKeySequence = properties.shortcutKeyEvent; +qDebug() << "shortcutKeySequence=" << properties.shortcutKeySequence; + } + } + + properties.position = object.property("position").toVariant().toInt(); + properties.beforeItem = object.property("beforeItem").toVariant().toString(); + properties.afterItem = object.property("afterItem").toVariant().toString(); +} + + diff --git a/libraries/script-engine/src/MenuTypes.h b/libraries/script-engine/src/MenuTypes.h new file mode 100644 index 0000000000..731bd2c5e5 --- /dev/null +++ b/libraries/script-engine/src/MenuTypes.h @@ -0,0 +1,48 @@ +// +// MenuTypes.h +// hifi +// +// Created by Brad Hefta-Gaub on 1/28/14. +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi_MenuTypes_h__ +#define __hifi_MenuTypes_h__ + +#include + +#include "EventTypes.h" + +class MenuItemProperties { +public: + MenuItemProperties(); + MenuItemProperties(const QString& menuName, const QString& menuItemName, + const QString& shortcutKey = QString(""), bool checkable = false, bool checked = false); + MenuItemProperties(const QString& menuName, const QString& menuItemName, + const KeyEvent& shortcutKeyEvent, bool checkable = false, bool checked = false); + + QString menuName; + QString menuItemName; + + // Shortcut key items: in order of priority + QString shortcutKey; + KeyEvent shortcutKeyEvent; + QKeySequence shortcutKeySequence; // this is what we actually use, it's set from one of the above + + // location related items: in order of priority + int position; + QString beforeItem; + QString afterItem; + + // other properties + bool isCheckable; + bool isChecked; +}; +Q_DECLARE_METATYPE(MenuItemProperties) +QScriptValue menuItemPropertiesToScriptValue(QScriptEngine* engine, const MenuItemProperties& props); +void menuItemPropertiesFromScriptValue(const QScriptValue& object, MenuItemProperties& props); +void registerMenuTypes(QScriptEngine* engine); + + + +#endif // __hifi_MenuTypes_h__ diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 076f941222..2a70521a13 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -24,6 +24,7 @@ #include +#include "MenuTypes.h" #include "ScriptEngine.h" const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; @@ -136,8 +137,8 @@ void ScriptEngine::init() { // register various meta-types registerMetaTypes(&_engine); registerVoxelMetaTypes(&_engine); - //registerParticleMetaTypes(&_engine); registerEventTypes(&_engine); + registerMenuTypes(&_engine); qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue); diff --git a/libraries/shared/src/AbstractMenuInterface.h b/libraries/shared/src/AbstractMenuInterface.h index 66083e4ed4..b64422a4eb 100644 --- a/libraries/shared/src/AbstractMenuInterface.h +++ b/libraries/shared/src/AbstractMenuInterface.h @@ -25,7 +25,8 @@ public: const QKeySequence& shortcut = 0, const QObject* receiver = NULL, const char* member = NULL, - QAction::MenuRole role = QAction::NoRole) = 0; + QAction::MenuRole role = QAction::NoRole, + int menuItemLocation = -1) = 0; virtual void removeAction(QMenu* menu, const QString& actionName) = 0; }; From 0b6e81b8a6f9a08aeb3a2a6a2ac58f6ba6bddcab Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 25 Feb 2014 10:31:29 -0800 Subject: [PATCH 06/13] remove more cruft --- examples/menuExample.js | 24 ++++++++++++++++------- interface/src/Menu.cpp | 11 ----------- interface/src/Menu.h | 2 -- libraries/script-engine/src/MenuTypes.cpp | 13 ------------ 4 files changed, 17 insertions(+), 33 deletions(-) diff --git a/examples/menuExample.js b/examples/menuExample.js index fc4b9c828d..1710a368c5 100644 --- a/examples/menuExample.js +++ b/examples/menuExample.js @@ -14,15 +14,18 @@ function setupMenus() { Menu.addMenuItem("Foo","Foo item 1", "SHIFT+CTRL+F" ); Menu.addMenuItem("Foo","Foo item 2", "SHIFT+F" ); Menu.addMenuItem("Foo","Foo item 3", "META+F" ); - - Menu.addCheckableMenuItem("Foo","Foo item 4", true); + Menu.addMenuItem({ + menuName: "Foo", + menuItemName: "Foo item 4", + isCheckable: true, + isChecked: true + }); Menu.addMenuItem({ menuName: "Foo", menuItemName: "Foo item 5", shortcutKey: "ALT+F", - isCheckable: true, - isChecked: true + isCheckable: true }); @@ -40,13 +43,20 @@ function setupMenus() { Menu.addMenu("Bar > Spam"); Menu.addMenuItem("Bar > Spam","Spam item 1"); - Menu.addCheckableMenuItem("Bar > Spam","Spam item 2",false); + Menu.addMenuItem({ + menuName: "Bar > Spam", + menuItemName: "Spam item 2", + isCheckable: true, + isChecked: false + }); + Menu.addSeparator("Bar > Spam","Other Items"); Menu.addMenuItem("Bar > Spam","Remove Spam item 2"); Menu.addMenuItem("Foo","Remove Spam item 2"); - Menu.addMenuItem({ menuName: "Foo", - menuItemName: "Remove Spam item 2" + Menu.addMenuItem({ + menuName: "Foo", + menuItemName: "Remove Spam item 2" }); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d32aba7ab5..647e2e27d9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1508,17 +1508,6 @@ void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& men QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); } -void MenuScriptingInterface::addCheckableMenuItem(const QString& menu, const QString& menuitem, - const QString& shortcutKey, bool checked) { - MenuItemProperties properties(menu, menuitem, shortcutKey, true, checked); - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); -} - -void MenuScriptingInterface::addCheckableMenuItem(const QString& menu, const QString& menuitem, bool checked) { - MenuItemProperties properties(menu, menuitem, "", true, checked); - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); -} - void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& menuitem) { QMetaObject::invokeMethod(Menu::getInstance(), "removeMenuItem", Q_ARG(const QString&, menu), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 963f17a572..94f520c3bb 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -340,8 +340,6 @@ public slots: void addMenuItem(const MenuItemProperties& properties); void addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey); void addMenuItem(const QString& menuName, const QString& menuitem); - void addCheckableMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey, bool checked); - void addCheckableMenuItem(const QString& menuName, const QString& menuitem, bool checked); void removeMenuItem(const QString& menuName, const QString& menuitem); diff --git a/libraries/script-engine/src/MenuTypes.cpp b/libraries/script-engine/src/MenuTypes.cpp index aaf205c939..d428821071 100644 --- a/libraries/script-engine/src/MenuTypes.cpp +++ b/libraries/script-engine/src/MenuTypes.cpp @@ -55,11 +55,6 @@ MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& m isCheckable(checkable), isChecked(checked) { -qDebug() << "MenuItemProperties::MenuItemProperties(... KeyEvent... )"; -qDebug() << "shortcutKeyEvent.text=" << shortcutKeyEvent.text; -qDebug() << "shortcutKeyEvent.key=" << shortcutKeyEvent.key; -qDebug() << "shortcutKeyEvent.isControl=" << shortcutKeyEvent.isControl; -qDebug() << "shortcutKeySequence=" << shortcutKeySequence; } void registerMenuTypes(QScriptEngine* engine) { @@ -81,21 +76,13 @@ void menuItemPropertiesFromScriptValue(const QScriptValue& object, MenuItemPrope // handle the shortcut key options in order... QScriptValue shortcutKeyValue = object.property("shortcutKey"); if (shortcutKeyValue.isValid()) { -qDebug() << "got shortcutKey..."; properties.shortcutKey = shortcutKeyValue.toVariant().toString(); properties.shortcutKeySequence = properties.shortcutKey; } else { -qDebug() << "testing shortcutKeyEvent..."; QScriptValue shortcutKeyEventValue = object.property("shortcutKeyEvent"); if (shortcutKeyEventValue.isValid()) { -qDebug() << "got shortcutKeyEvent..."; keyEventFromScriptValue(shortcutKeyEventValue, properties.shortcutKeyEvent); -qDebug() << "shortcutKeyEvent.text=" << properties.shortcutKeyEvent.text; -qDebug() << "shortcutKeyEvent.key=" << properties.shortcutKeyEvent.key; -qDebug() << "shortcutKeyEvent.isControl=" << properties.shortcutKeyEvent.isControl; - properties.shortcutKeySequence = properties.shortcutKeyEvent; -qDebug() << "shortcutKeySequence=" << properties.shortcutKeySequence; } } From 0048099ff5df61708cbf310bea0e5d5ac81382bc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 25 Feb 2014 12:19:30 -0800 Subject: [PATCH 07/13] implement support for menu item positioning --- examples/clipboardExample.js | 78 ++++++++++--------- examples/menuExample.js | 12 +++ interface/src/ClipboardScriptingInterface.cpp | 4 +- interface/src/Menu.cpp | 58 ++++++++++---- interface/src/Menu.h | 5 +- libraries/script-engine/src/EventTypes.cpp | 2 +- libraries/script-engine/src/MenuTypes.cpp | 11 +-- libraries/script-engine/src/MenuTypes.h | 2 + 8 files changed, 111 insertions(+), 61 deletions(-) diff --git a/examples/clipboardExample.js b/examples/clipboardExample.js index 81f0daae10..4972505dfe 100644 --- a/examples/clipboardExample.js +++ b/examples/clipboardExample.js @@ -12,67 +12,67 @@ var selectedVoxel = { x: 0, y: 0, z: 0, s: 0 }; var selectedSize = 4; -function printKeyEvent(eventName, event) { - print(eventName); - print(" event.key=" + event.key); - print(" event.text=" + event.text); - print(" event.isShifted=" + event.isShifted); - print(" event.isControl=" + event.isControl); - print(" event.isMeta=" + event.isMeta); - print(" event.isAlt=" + event.isAlt); - print(" event.isKeypad=" + event.isKeypad); +function setupMenus() { + // hook up menus + Menu.menuItemEvent.connect(menuItemEvent); + + // delete the standard application menu item + Menu.removeMenuItem("Edit", "Cut"); + Menu.removeMenuItem("Edit", "Copy"); + Menu.removeMenuItem("Edit", "Paste"); + Menu.removeMenuItem("Edit", "Delete"); + Menu.removeMenuItem("Edit", "Nudge"); + Menu.removeMenuItem("File", "Export Voxels"); + Menu.removeMenuItem("File", "Import Voxels"); + + // delete the standard application menu item + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Cut", shortcutKey: "CTRL+X", afterItem: "Voxels" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Copy", shortcutKey: "CTRL+C", afterItem: "Cut" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste", shortcutKey: "CTRL+V", afterItem: "Copy" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Nudge", shortcutKey: "CTRL+N", afterItem: "Paste" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Nudge" }); + Menu.addMenuItem({ menuName: "File", menuItemName: "Export Voxels", shortcutKey: "CTRL+E", afterItem: "Voxels" }); + Menu.addMenuItem({ menuName: "File", menuItemName: "Import Voxels", shortcutKey: "CTRL+I", afterItem: "Export Voxels" }); } - -function keyPressEvent(event) { - var debug = false; +function menuItemEvent(menuItem) { + var debug = true; if (debug) { - printKeyEvent("keyPressEvent", event); - } -} - -function keyReleaseEvent(event) { - var debug = false; - if (debug) { - printKeyEvent("keyReleaseEvent", event); + print("menuItemEvent " + menuItem); } // Note: this sample uses Alt+ as the key codes for these clipboard items - if ((event.key == 199 || event.key == 67 || event.text == "C" || event.text == "c") && event.isAlt) { - print("the Alt+C key was pressed"); + if (menuItem == "Copy") { + print("copying..."); Clipboard.copyVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } - if ((event.key == 8776 || event.key == 88 || event.text == "X" || event.text == "x") && event.isAlt) { - print("the Alt+X key was pressed"); + if (menuItem == "Cut") { + print("cutting..."); Clipboard.cutVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } - if ((event.key == 8730 || event.key == 86 || event.text == "V" || event.text == "v") && event.isAlt) { - print("the Alt+V key was pressed"); + if (menuItem == "Paste") { + print("pasting..."); Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } - if (event.text == "DELETE" || event.text == "BACKSPACE") { - print("the DELETE/BACKSPACE key was pressed"); + if (menuItem == "Delete") { + print("deleting..."); Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } - if ((event.text == "E" || event.text == "e") && event.isMeta) { - print("the Ctl+E key was pressed"); + if (menuItem == "Export Voxels") { + print("export"); Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } - if ((event.text == "I" || event.text == "i") && event.isMeta) { - print("the Ctl+I key was pressed"); + if (menuItem == "Import Voxels") { + print("import"); Clipboard.importVoxels(); } - if ((event.key == 78 || event.text == "N" || event.text == "n") && event.isMeta) { - print("the Ctl+N key was pressed, nudging to left 1 meter"); + if (menuItem == "Nudge") { + print("nudge"); Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 }); } } -// Map keyPress and mouse move events to our callbacks -Controller.keyPressEvent.connect(keyPressEvent); -Controller.keyReleaseEvent.connect(keyReleaseEvent); - var selectCube = Overlays.addOverlay("cube", { position: { x: 0, y: 0, z: 0}, size: selectedSize, @@ -149,3 +149,5 @@ function scriptEnding() { } Script.scriptEnding.connect(scriptEnding); + +setupMenus(); \ No newline at end of file diff --git a/examples/menuExample.js b/examples/menuExample.js index 1710a368c5..3b18021302 100644 --- a/examples/menuExample.js +++ b/examples/menuExample.js @@ -59,6 +59,18 @@ function setupMenus() { menuItemName: "Remove Spam item 2" }); + Menu.addMenuItem({ + menuName: "Edit", + menuItemName: "before Cut", + beforeItem: "Cut" + }); + + Menu.addMenuItem({ + menuName: "Edit", + menuItemName: "after Nudge", + afterItem: "Nudge" + }); + } function scriptEnding() { diff --git a/interface/src/ClipboardScriptingInterface.cpp b/interface/src/ClipboardScriptingInterface.cpp index 644ea84cdb..c669b465ad 100644 --- a/interface/src/ClipboardScriptingInterface.cpp +++ b/interface/src/ClipboardScriptingInterface.cpp @@ -70,8 +70,8 @@ void ClipboardScriptingInterface::exportVoxel(float x, float y, float z, float s z / (float)TREE_SCALE, s / (float)TREE_SCALE }; - // TODO: should we be calling invokeMethod() in all these cases? - Application::getInstance()->exportVoxels(sourceVoxel); + QMetaObject::invokeMethod(Application::getInstance(), "exportVoxels", + Q_ARG(const VoxelDetail&, sourceVoxel)); } void ClipboardScriptingInterface::importVoxels() { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 647e2e27d9..1c00860574 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -690,13 +690,28 @@ QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu, const char* member, QAction::MenuRole role, int menuItemLocation) { - QAction* action; + QAction* action = NULL; + QAction* actionBefore = NULL; - if (receiver && member) { - action = destinationMenu->addAction(actionName, receiver, member, shortcut); + if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) { + actionBefore = destinationMenu->actions()[menuItemLocation]; + } + + if (!actionBefore) { + if (receiver && member) { + action = destinationMenu->addAction(actionName, receiver, member, shortcut); + } else { + action = destinationMenu->addAction(actionName); + action->setShortcut(shortcut); + } } else { - action = destinationMenu->addAction(actionName); + action = new QAction(actionName, destinationMenu); action->setShortcut(shortcut); + destinationMenu->insertAction(actionBefore, action); + + if (receiver && member) { + connect(action, SIGNAL(triggered()), receiver, member); + } } action->setMenuRole(role); @@ -1366,6 +1381,17 @@ QAction* Menu::getMenuAction(const QString& menuName) { return action; } +int Menu::findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem) { + int position = 0; + foreach(QAction* action, menu->actions()) { + if (action->text() == searchMenuItem) { + return position; + } + position++; + } + return UNSPECIFIED_POSITION; // not found +} + QMenu* Menu::addMenu(const QString& menuName) { QStringList menuTree = menuName.split(">"); QMenu* addTo = NULL; @@ -1416,24 +1442,30 @@ void Menu::addMenuItem(const MenuItemProperties& properties) { if (menuObj) { QShortcut* shortcut = NULL; if (!properties.shortcutKeySequence.isEmpty()) { - shortcut = new QShortcut(properties.shortcutKey, this); + shortcut = new QShortcut(properties.shortcutKeySequence, this); } - /** - // test insert in middle of menu... - QAction* physics = getMenuAction("Edit>Physics"); - QAction* testHack = new QAction("test", editMenu); - editMenu->insertAction(gravity, testHack); - **/ + // check for positioning requests + int requestedPosition = properties.position; + if (requestedPosition == UNSPECIFIED_POSITION && !properties.beforeItem.isEmpty()) { + requestedPosition = findPositionOfMenuItem(menuObj, properties.beforeItem); + } + if (requestedPosition == UNSPECIFIED_POSITION && !properties.afterItem.isEmpty()) { + int afterPosition = findPositionOfMenuItem(menuObj, properties.afterItem); + if (afterPosition != UNSPECIFIED_POSITION) { + requestedPosition = afterPosition + 1; + } + } QAction* menuItemAction; if (properties.isCheckable) { menuItemAction = addCheckableActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence, properties.isChecked, - MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), requestedPosition); } else { menuItemAction = addActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence, - MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered())); + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), + QAction::NoRole, requestedPosition); } if (shortcut) { connect(shortcut, SIGNAL(activated()), menuItemAction, SLOT(trigger())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 94f520c3bb..8d20ec4bdd 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -99,7 +99,7 @@ public: const QObject* receiver = NULL, const char* member = NULL, QAction::MenuRole role = QAction::NoRole, - int menuItemLocation = -1); + int menuItemLocation = UNSPECIFIED_POSITION); virtual void removeAction(QMenu* menu, const QString& actionName); bool goToDestination(QString destination); void goToOrientation(QString orientation); @@ -159,7 +159,7 @@ private: const bool checked = false, const QObject* receiver = NULL, const char* member = NULL, - int menuItemLocation = -1); + int menuItemLocation = UNSPECIFIED_POSITION); void updateFrustumRenderModeAction(); @@ -170,6 +170,7 @@ private: QMenu* getMenuParent(const QString& menuName, QString& finalMenuPart); QAction* getMenuAction(const QString& menuName); + int findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem); QMenu* getMenu(const QString& menuName); diff --git a/libraries/script-engine/src/EventTypes.cpp b/libraries/script-engine/src/EventTypes.cpp index 6e7297b720..d016dc6fc4 100644 --- a/libraries/script-engine/src/EventTypes.cpp +++ b/libraries/script-engine/src/EventTypes.cpp @@ -129,7 +129,7 @@ bool KeyEvent::operator==(const KeyEvent& other) const { KeyEvent::operator QKeySequence() const { int resultCode = 0; - if (text >= "a" && text <= "z") { + if (text.size() == 1 && text >= "a" && text <= "z") { resultCode = text.toUpper().at(0).unicode(); } else { resultCode = key; diff --git a/libraries/script-engine/src/MenuTypes.cpp b/libraries/script-engine/src/MenuTypes.cpp index d428821071..e467c9d23a 100644 --- a/libraries/script-engine/src/MenuTypes.cpp +++ b/libraries/script-engine/src/MenuTypes.cpp @@ -12,14 +12,13 @@ #include #include "MenuTypes.h" - MenuItemProperties::MenuItemProperties() : menuName(""), menuItemName(""), shortcutKey(""), shortcutKeyEvent(), shortcutKeySequence(), - position(-1), + position(UNSPECIFIED_POSITION), beforeItem(""), afterItem(""), isCheckable(false), @@ -34,7 +33,7 @@ MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& m shortcutKey(shortcutKey), shortcutKeyEvent(), shortcutKeySequence(shortcutKey), - position(-1), + position(UNSPECIFIED_POSITION), beforeItem(""), afterItem(""), isCheckable(checkable), @@ -49,7 +48,7 @@ MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& m shortcutKey(""), shortcutKeyEvent(shortcutKeyEvent), shortcutKeySequence(shortcutKeyEvent), - position(-1), + position(UNSPECIFIED_POSITION), beforeItem(""), afterItem(""), isCheckable(checkable), @@ -86,7 +85,9 @@ void menuItemPropertiesFromScriptValue(const QScriptValue& object, MenuItemPrope } } - properties.position = object.property("position").toVariant().toInt(); + if (object.property("position").isValid()) { + properties.position = object.property("position").toVariant().toInt(); + } properties.beforeItem = object.property("beforeItem").toVariant().toString(); properties.afterItem = object.property("afterItem").toVariant().toString(); } diff --git a/libraries/script-engine/src/MenuTypes.h b/libraries/script-engine/src/MenuTypes.h index 731bd2c5e5..ef92225288 100644 --- a/libraries/script-engine/src/MenuTypes.h +++ b/libraries/script-engine/src/MenuTypes.h @@ -13,6 +13,8 @@ #include "EventTypes.h" +const int UNSPECIFIED_POSITION = -1; + class MenuItemProperties { public: MenuItemProperties(); From e12d7910972dfe5dd48bca1bfc7e36077e06a6bf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 25 Feb 2014 12:37:49 -0800 Subject: [PATCH 08/13] remove dead code --- interface/src/Menu.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d746984da7..e467ce0130 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -173,13 +173,6 @@ Menu::Menu() : addAvatarCollisionSubMenu(editMenu); - /** - // test insert in middle of edit... - QAction* physics = getMenuAction("Edit>Physics"); - QAction* testHack = new QAction("test", editMenu); - editMenu->insertAction(physics, testHack); - **/ - QMenu* toolsMenu = addMenu("Tools"); _voxelModeActionsGroup = new QActionGroup(this); From 4d0a25b6ea0e3ff41e1561013b960e9b81622913 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 25 Feb 2014 13:05:58 -0800 Subject: [PATCH 09/13] add menus to editVoxels.js --- examples/editVoxels.js | 103 +++++++++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 35 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 53d3869075..949de2e852 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -1012,43 +1012,78 @@ function keyReleaseEvent(event) { // handle clipboard items if (selectToolSelected) { - var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); - var intersection = Voxels.findRayIntersection(pickRay); - selectedVoxel = calculateVoxelFromIntersection(intersection,"select"); - - // Note: this sample uses Alt+ as the key codes for these clipboard items - if ((event.key == 199 || event.key == 67 || event.text == "C" || event.text == "c") && event.isAlt) { - print("the Alt+C key was pressed... copy"); - Clipboard.copyVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); - } - if ((event.key == 8776 || event.key == 88 || event.text == "X" || event.text == "x") && event.isAlt) { - print("the Alt+X key was pressed... cut"); - Clipboard.cutVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); - } - if ((event.key == 8730 || event.key == 86 || event.text == "V" || event.text == "v") && event.isAlt) { - print("the Alt+V key was pressed... paste"); - Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); - } - if (event.text == "DELETE" || event.text == "BACKSPACE") { - print("the DELETE/BACKSPACE key was pressed... delete"); + // menu tied to BACKSPACE, so we handle DELETE key here... + if (event.text == "DELETE") { + var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); + var intersection = Voxels.findRayIntersection(pickRay); + selectedVoxel = calculateVoxelFromIntersection(intersection,"select"); + print("the DELETE key was pressed... delete"); Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); } - - if ((event.text == "E" || event.text == "e") && event.isMeta) { - print("the Ctl+E key was pressed... export"); - Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); - } - if ((event.text == "I" || event.text == "i") && event.isMeta) { - print("the Ctl+I key was pressed... import"); - Clipboard.importVoxels(); - } - if ((event.key == 78 || event.text == "N" || event.text == "n") && event.isMeta) { - print("the Ctl+N key was pressed, nudging to left 1 meter... nudge"); - Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 }); - } } } +function setupMenus() { + // hook up menus + Menu.menuItemEvent.connect(menuItemEvent); + + // delete the standard application menu item + Menu.removeMenuItem("Edit", "Cut"); + Menu.removeMenuItem("Edit", "Copy"); + Menu.removeMenuItem("Edit", "Paste"); + Menu.removeMenuItem("Edit", "Delete"); + Menu.removeMenuItem("Edit", "Nudge"); + Menu.removeMenuItem("File", "Export Voxels"); + Menu.removeMenuItem("File", "Import Voxels"); + + // delete the standard application menu item + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Cut", shortcutKey: "CTRL+X", afterItem: "Voxels" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Copy", shortcutKey: "CTRL+C", afterItem: "Cut" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste", shortcutKey: "CTRL+V", afterItem: "Copy" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Nudge", shortcutKey: "CTRL+N", afterItem: "Paste" }); + Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Nudge" }); + Menu.addMenuItem({ menuName: "File", menuItemName: "Export Voxels", shortcutKey: "CTRL+E", afterItem: "Voxels" }); + Menu.addMenuItem({ menuName: "File", menuItemName: "Import Voxels", shortcutKey: "CTRL+I", afterItem: "Export Voxels" }); +} + +function menuItemEvent(menuItem) { + + // handle clipboard items + if (selectToolSelected) { + var pickRay = Camera.computePickRay(trackLastMouseX, trackLastMouseY); + var intersection = Voxels.findRayIntersection(pickRay); + selectedVoxel = calculateVoxelFromIntersection(intersection,"select"); + if (menuItem == "Copy") { + print("copying..."); + Clipboard.copyVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } + if (menuItem == "Cut") { + print("cutting..."); + Clipboard.cutVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } + if (menuItem == "Paste") { + print("pasting..."); + Clipboard.pasteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } + if (menuItem == "Delete") { + print("deleting..."); + Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } + + if (menuItem == "Export Voxels") { + print("export"); + Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); + } + if (menuItem == "Import Voxels") { + print("import"); + Clipboard.importVoxels(); + } + if (menuItem == "Nudge") { + print("nudge"); + Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 }); + } + } +} function mouseMoveEvent(event) { if (!editToolsOn) { @@ -1403,8 +1438,6 @@ function scriptEnding() { } Script.scriptEnding.connect(scriptEnding); - Script.willSendVisualDataCallback.connect(update); - - +setupMenus(); From 73b0a5b3594f5f0e7116e77fd7536f651259f11e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 25 Feb 2014 13:32:09 -0800 Subject: [PATCH 10/13] switch to numbered swatches --- examples/editVoxels.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 949de2e852..24f2e10067 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -164,7 +164,7 @@ for (s = 0; s < numColors; s++) { width: swatchWidth, height: swatchHeight, subImage: { x: imageFromX, y: imageFromY, width: (swatchWidth - 1), height: swatchHeight }, - imageURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/testing-swatches.svg", + imageURL: "http://highfidelity-public.s3-us-west-1.amazonaws.com/images/swatches.svg", color: colors[s], alpha: 1, visible: editToolsOn From e03c7be5ef9ca3ecbf21675dd8d05d9fc750bb83 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 25 Feb 2014 14:33:37 -0800 Subject: [PATCH 11/13] moved MenuScriptingInterface to own files --- interface/src/Application.cpp | 1 + interface/src/Menu.cpp | 72 +------------------- interface/src/Menu.h | 36 +--------- interface/src/MenuScriptingInterface.cpp | 84 ++++++++++++++++++++++++ interface/src/MenuScriptingInterface.h | 53 +++++++++++++++ 5 files changed, 141 insertions(+), 105 deletions(-) create mode 100644 interface/src/MenuScriptingInterface.cpp create mode 100644 interface/src/MenuScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d37fd3cf2e..1d4599e90a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -65,6 +65,7 @@ #include "ClipboardScriptingInterface.h" #include "InterfaceVersion.h" #include "Menu.h" +#include "MenuScriptingInterface.h" #include "Swatch.h" #include "Util.h" #include "devices/OculusManager.h" diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e467ce0130..3dbe2f0a96 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -30,6 +30,7 @@ #include "Application.h" #include "Menu.h" +#include "MenuScriptingInterface.h" #include "Util.h" #include "InfoView.h" #include "ui/MetavoxelEditor.h" @@ -1508,74 +1509,3 @@ void Menu::removeMenuItem(const QString& menu, const QString& menuitem) { QMenuBar::repaint(); }; -MenuScriptingInterface* MenuScriptingInterface::_instance = NULL; -QMutex MenuScriptingInterface::_instanceMutex; - -MenuScriptingInterface* MenuScriptingInterface::getInstance() { - // lock the menu instance mutex to make sure we don't race and create two menus and crash - _instanceMutex.lock(); - if (!_instance) { - _instance = new MenuScriptingInterface(); - } - _instanceMutex.unlock(); - return _instance; -} - -void MenuScriptingInterface::deleteLaterIfExists() { - _instanceMutex.lock(); - if (_instance) { - _instance->deleteLater(); - _instance = NULL; - } - _instanceMutex.unlock(); -} - -void MenuScriptingInterface::menuItemTriggered() { - QAction* menuItemAction = dynamic_cast(sender()); - if (menuItemAction) { - // emit the event - emit menuItemEvent(menuItemAction->text()); - } -} - -void MenuScriptingInterface::addMenu(const QString& menu) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenu", Q_ARG(const QString&, menu)); -} - -void MenuScriptingInterface::removeMenu(const QString& menu) { - QMetaObject::invokeMethod(Menu::getInstance(), "removeMenu", Q_ARG(const QString&, menu)); -} - -void MenuScriptingInterface::addSeparator(const QString& menuName, const QString& separatorName) { - QMetaObject::invokeMethod(Menu::getInstance(), "addSeparator", - Q_ARG(const QString&, menuName), - Q_ARG(const QString&, separatorName)); -} - -void MenuScriptingInterface::addMenuItem(const MenuItemProperties& properties) { - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); -} - -void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey) { - MenuItemProperties properties(menu, menuitem, shortcutKey); - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); -} - -void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem) { - MenuItemProperties properties(menu, menuitem); - QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); -} - -void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& menuitem) { - QMetaObject::invokeMethod(Menu::getInstance(), "removeMenuItem", - Q_ARG(const QString&, menu), - Q_ARG(const QString&, menuitem)); -}; - -bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { - return Menu::getInstance()->isOptionChecked(menuOption); -} - -void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool isChecked) { - return Menu::getInstance()->setIsOptionChecked(menuOption, isChecked); -} diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 38f0a265dc..f0dcb993e6 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -17,6 +17,8 @@ #include #include #include +#include +//#include const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; @@ -326,38 +328,4 @@ namespace MenuOption { const QString VoxelTextures = "Voxel Textures"; } -class MenuScriptingInterface : public QObject { - Q_OBJECT - MenuScriptingInterface() { }; -public: - static MenuScriptingInterface* getInstance(); - static void deleteLaterIfExists(); - -private slots: - friend class Menu; - void menuItemTriggered(); - -public slots: - void addMenu(const QString& menuName); - void removeMenu(const QString& menuName); - - void addSeparator(const QString& menuName, const QString& separatorName); - - void addMenuItem(const MenuItemProperties& properties); - void addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey); - void addMenuItem(const QString& menuName, const QString& menuitem); - - void removeMenuItem(const QString& menuName, const QString& menuitem); - - bool isOptionChecked(const QString& menuOption); - void setIsOptionChecked(const QString& menuOption, bool isChecked); - -signals: - void menuItemEvent(const QString& menuItem); - -private: - static QMutex _instanceMutex; - static MenuScriptingInterface* _instance; -}; - #endif /* defined(__hifi__Menu__) */ diff --git a/interface/src/MenuScriptingInterface.cpp b/interface/src/MenuScriptingInterface.cpp new file mode 100644 index 0000000000..090c306bea --- /dev/null +++ b/interface/src/MenuScriptingInterface.cpp @@ -0,0 +1,84 @@ +// +// MenuScriptingInterface.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 2/25/14 +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// + +#include "Application.h" + +#include "MenuScriptingInterface.h" + + +MenuScriptingInterface* MenuScriptingInterface::_instance = NULL; +QMutex MenuScriptingInterface::_instanceMutex; + +MenuScriptingInterface* MenuScriptingInterface::getInstance() { + // lock the menu instance mutex to make sure we don't race and create two menus and crash + _instanceMutex.lock(); + if (!_instance) { + _instance = new MenuScriptingInterface(); + } + _instanceMutex.unlock(); + return _instance; +} + +void MenuScriptingInterface::deleteLaterIfExists() { + _instanceMutex.lock(); + if (_instance) { + _instance->deleteLater(); + _instance = NULL; + } + _instanceMutex.unlock(); +} + +void MenuScriptingInterface::menuItemTriggered() { + QAction* menuItemAction = dynamic_cast(sender()); + if (menuItemAction) { + // emit the event + emit menuItemEvent(menuItemAction->text()); + } +} + +void MenuScriptingInterface::addMenu(const QString& menu) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenu", Q_ARG(const QString&, menu)); +} + +void MenuScriptingInterface::removeMenu(const QString& menu) { + QMetaObject::invokeMethod(Menu::getInstance(), "removeMenu", Q_ARG(const QString&, menu)); +} + +void MenuScriptingInterface::addSeparator(const QString& menuName, const QString& separatorName) { + QMetaObject::invokeMethod(Menu::getInstance(), "addSeparator", + Q_ARG(const QString&, menuName), + Q_ARG(const QString&, separatorName)); +} + +void MenuScriptingInterface::addMenuItem(const MenuItemProperties& properties) { + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); +} + +void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem, const QString& shortcutKey) { + MenuItemProperties properties(menu, menuitem, shortcutKey); + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); +} + +void MenuScriptingInterface::addMenuItem(const QString& menu, const QString& menuitem) { + MenuItemProperties properties(menu, menuitem); + QMetaObject::invokeMethod(Menu::getInstance(), "addMenuItem", Q_ARG(const MenuItemProperties&, properties)); +} + +void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString& menuitem) { + QMetaObject::invokeMethod(Menu::getInstance(), "removeMenuItem", + Q_ARG(const QString&, menu), + Q_ARG(const QString&, menuitem)); +}; + +bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) { + return Menu::getInstance()->isOptionChecked(menuOption); +} + +void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool isChecked) { + return Menu::getInstance()->setIsOptionChecked(menuOption, isChecked); +} diff --git a/interface/src/MenuScriptingInterface.h b/interface/src/MenuScriptingInterface.h new file mode 100644 index 0000000000..7359a35380 --- /dev/null +++ b/interface/src/MenuScriptingInterface.h @@ -0,0 +1,53 @@ +// +// MenuScriptingInterface.h +// hifi +// +// Created by Brad Hefta-Gaub on 2/25/14 +// Copyright (c) 2014 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__MenuScriptingInterface__ +#define __hifi__MenuScriptingInterface__ + +#include +#include +#include + +#include "Menu.h" +#include + +class MenuScriptingInterface : public QObject { + Q_OBJECT + MenuScriptingInterface() { }; +public: + static MenuScriptingInterface* getInstance(); + static void deleteLaterIfExists(); + +private slots: + friend class Menu; + void menuItemTriggered(); + +public slots: + void addMenu(const QString& menuName); + void removeMenu(const QString& menuName); + + void addSeparator(const QString& menuName, const QString& separatorName); + + void addMenuItem(const MenuItemProperties& properties); + void addMenuItem(const QString& menuName, const QString& menuitem, const QString& shortcutKey); + void addMenuItem(const QString& menuName, const QString& menuitem); + + void removeMenuItem(const QString& menuName, const QString& menuitem); + + bool isOptionChecked(const QString& menuOption); + void setIsOptionChecked(const QString& menuOption, bool isChecked); + +signals: + void menuItemEvent(const QString& menuItem); + +private: + static QMutex _instanceMutex; + static MenuScriptingInterface* _instance; +}; + +#endif /* defined(__hifi__MenuScriptingInterface__) */ From 81bff606456ccd972c21fc8ef37268381fe694c7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 25 Feb 2014 14:53:57 -0800 Subject: [PATCH 12/13] change singleton approach to not require delete --- interface/src/Application.cpp | 1 - interface/src/MenuScriptingInterface.cpp | 21 ++------------------- interface/src/MenuScriptingInterface.h | 6 +----- 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1d4599e90a..79b1fc0361 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -360,7 +360,6 @@ Application::~Application() { VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown Menu::getInstance()->deleteLater(); - MenuScriptingInterface::deleteLaterIfExists(); _myAvatar = NULL; diff --git a/interface/src/MenuScriptingInterface.cpp b/interface/src/MenuScriptingInterface.cpp index 090c306bea..f1a44422b3 100644 --- a/interface/src/MenuScriptingInterface.cpp +++ b/interface/src/MenuScriptingInterface.cpp @@ -11,26 +11,9 @@ #include "MenuScriptingInterface.h" -MenuScriptingInterface* MenuScriptingInterface::_instance = NULL; -QMutex MenuScriptingInterface::_instanceMutex; - MenuScriptingInterface* MenuScriptingInterface::getInstance() { - // lock the menu instance mutex to make sure we don't race and create two menus and crash - _instanceMutex.lock(); - if (!_instance) { - _instance = new MenuScriptingInterface(); - } - _instanceMutex.unlock(); - return _instance; -} - -void MenuScriptingInterface::deleteLaterIfExists() { - _instanceMutex.lock(); - if (_instance) { - _instance->deleteLater(); - _instance = NULL; - } - _instanceMutex.unlock(); + static MenuScriptingInterface sharedInstance; + return &sharedInstance; } void MenuScriptingInterface::menuItemTriggered() { diff --git a/interface/src/MenuScriptingInterface.h b/interface/src/MenuScriptingInterface.h index 7359a35380..837d7e3cf7 100644 --- a/interface/src/MenuScriptingInterface.h +++ b/interface/src/MenuScriptingInterface.h @@ -9,6 +9,7 @@ #ifndef __hifi__MenuScriptingInterface__ #define __hifi__MenuScriptingInterface__ +#include #include #include #include @@ -21,7 +22,6 @@ class MenuScriptingInterface : public QObject { MenuScriptingInterface() { }; public: static MenuScriptingInterface* getInstance(); - static void deleteLaterIfExists(); private slots: friend class Menu; @@ -44,10 +44,6 @@ public slots: signals: void menuItemEvent(const QString& menuItem); - -private: - static QMutex _instanceMutex; - static MenuScriptingInterface* _instance; }; #endif /* defined(__hifi__MenuScriptingInterface__) */ From 3943c49dccebbc0c8973549b22d95e8942e90801 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 25 Feb 2014 17:32:16 -0800 Subject: [PATCH 13/13] rename MenuType and other CR feedback --- interface/src/Menu.h | 3 +-- interface/src/MenuScriptingInterface.h | 2 +- .../src/{MenuTypes.cpp => MenuItemProperties.cpp} | 6 +++--- .../src/{MenuTypes.h => MenuItemProperties.h} | 10 +++++----- libraries/script-engine/src/ScriptEngine.cpp | 4 ++-- 5 files changed, 12 insertions(+), 13 deletions(-) rename libraries/script-engine/src/{MenuTypes.cpp => MenuItemProperties.cpp} (96%) rename libraries/script-engine/src/{MenuTypes.h => MenuItemProperties.h} (87%) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index f0dcb993e6..ffb2fdaf42 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -16,9 +16,8 @@ #include #include -#include +#include #include -//#include const float ADJUST_LOD_DOWN_FPS = 40.0; const float ADJUST_LOD_UP_FPS = 55.0; diff --git a/interface/src/MenuScriptingInterface.h b/interface/src/MenuScriptingInterface.h index 837d7e3cf7..7379f2c00b 100644 --- a/interface/src/MenuScriptingInterface.h +++ b/interface/src/MenuScriptingInterface.h @@ -15,7 +15,7 @@ #include #include "Menu.h" -#include +#include class MenuScriptingInterface : public QObject { Q_OBJECT diff --git a/libraries/script-engine/src/MenuTypes.cpp b/libraries/script-engine/src/MenuItemProperties.cpp similarity index 96% rename from libraries/script-engine/src/MenuTypes.cpp rename to libraries/script-engine/src/MenuItemProperties.cpp index e467c9d23a..fc1e94f40c 100644 --- a/libraries/script-engine/src/MenuTypes.cpp +++ b/libraries/script-engine/src/MenuItemProperties.cpp @@ -1,5 +1,5 @@ // -// MenuTypes.cpp +// MenuItemProperties.cpp // hifi // // Created by Brad Hefta-Gaub on 1/28/14. @@ -10,7 +10,7 @@ #include #include -#include "MenuTypes.h" +#include "MenuItemProperties.h" MenuItemProperties::MenuItemProperties() : menuName(""), @@ -56,7 +56,7 @@ MenuItemProperties::MenuItemProperties(const QString& menuName, const QString& m { } -void registerMenuTypes(QScriptEngine* engine) { +void registerMenuItemProperties(QScriptEngine* engine) { qScriptRegisterMetaType(engine, menuItemPropertiesToScriptValue, menuItemPropertiesFromScriptValue); } diff --git a/libraries/script-engine/src/MenuTypes.h b/libraries/script-engine/src/MenuItemProperties.h similarity index 87% rename from libraries/script-engine/src/MenuTypes.h rename to libraries/script-engine/src/MenuItemProperties.h index ef92225288..6e0b3309b1 100644 --- a/libraries/script-engine/src/MenuTypes.h +++ b/libraries/script-engine/src/MenuItemProperties.h @@ -1,13 +1,13 @@ // -// MenuTypes.h +// MenuItemProperties.h // hifi // // Created by Brad Hefta-Gaub on 1/28/14. // Copyright (c) 2014 HighFidelity, Inc. All rights reserved. // -#ifndef __hifi_MenuTypes_h__ -#define __hifi_MenuTypes_h__ +#ifndef __hifi_MenuItemProperties_h__ +#define __hifi_MenuItemProperties_h__ #include @@ -43,8 +43,8 @@ public: Q_DECLARE_METATYPE(MenuItemProperties) QScriptValue menuItemPropertiesToScriptValue(QScriptEngine* engine, const MenuItemProperties& props); void menuItemPropertiesFromScriptValue(const QScriptValue& object, MenuItemProperties& props); -void registerMenuTypes(QScriptEngine* engine); +void registerMenuItemProperties(QScriptEngine* engine); -#endif // __hifi_MenuTypes_h__ +#endif // __hifi_MenuItemProperties_h__ diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2a70521a13..06818f5355 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -24,7 +24,7 @@ #include -#include "MenuTypes.h" +#include "MenuItemProperties.h" #include "ScriptEngine.h" const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000; @@ -138,7 +138,7 @@ void ScriptEngine::init() { registerMetaTypes(&_engine); registerVoxelMetaTypes(&_engine); registerEventTypes(&_engine); - registerMenuTypes(&_engine); + registerMenuItemProperties(&_engine); qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue); qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue);