diff --git a/BUILD_WIN.md b/BUILD_WIN.md
index 39252ec4f2..80b8c35502 100644
--- a/BUILD_WIN.md
+++ b/BUILD_WIN.md
@@ -29,12 +29,12 @@ NOTE: Qt does not support 64-bit builds on Windows 7, so you must use the 32-bit
 
 * [Download the online installer](http://qt-project.org/downloads)
     * When it asks you to select components, ONLY select the following:
-        * Qt > Qt 5.3.2 > **msvc2013 32-bit OpenGL**
+        * Qt > Qt 5.4.1 > **msvc2013 32-bit OpenGL**
 
-* [Download the offline installer](http://download.qt-project.org/official_releases/qt/5.3/5.3.2/qt-opensource-windows-x86-msvc2013_opengl-5.3.2.exe)
+* [Download the offline installer](http://download.qt.io/official_releases/qt/5.4/5.4.1/qt-opensource-windows-x86-msvc2013_opengl-5.4.1.exe)
 
 Once Qt is installed, you need to manually configure the following:
-* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.3.2\msvc2013_opengl\lib\cmake` directory.
+* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.4.1\msvc2013_opengl\lib\cmake` directory.
   * You can set an environment variable from Control Panel > System > Advanced System Settings > Environment Variables > New
 
 ###External Libraries
diff --git a/interface/resources/qml/Root.qml b/interface/resources/qml/Root.qml
index 92ad922cce..b2db7d18bf 100644
--- a/interface/resources/qml/Root.qml
+++ b/interface/resources/qml/Root.qml
@@ -6,35 +6,5 @@ import QtQuick 2.3
 Root {
     id: root
     anchors.fill: parent
-    Item {
-        Menu {
-        	objectName: "rootMenu"
-    	    Menu {
-    	        title: "File"
-    			MenuItem { 
-    	        	text: "Test"
-    				checkable: true
-    			}
-    	    	MenuItem {
-    	        	text: "Quit"
-    			}
-    		}
-    	    Menu {
-    	        title: "Edit"
-    	        MenuItem { 
-    	            text: "Copy"
-    			}
-    	        MenuItem { 
-    	            text: "Cut"
-    			}
-    	        MenuItem { 
-    	            text: "Paste"
-    			}
-    	        MenuItem { 
-    	            text: "Undo"
-    			}
-    	    }
-        }
-    }
 }
 
diff --git a/interface/resources/qml/RootMenu.qml b/interface/resources/qml/RootMenu.qml
index 46cae2cf4a..dc2e36f89a 100644
--- a/interface/resources/qml/RootMenu.qml
+++ b/interface/resources/qml/RootMenu.qml
@@ -3,32 +3,7 @@ import QtQuick.Controls 1.3
 
 Item {
 	Menu {
-		id: rootMenuFooBar
+		id: root
 		objectName: "rootMenu"
-	    Menu {
-	        title: "File"
-			MenuItem { 
-	        	text: "Test"
-				checkable: true
-			}
-	    	MenuItem {
-	        	text: "Quit"
-			}
-		}
-	    Menu {
-	        title: "Edit"
-	        MenuItem { 
-	            text: "Copy"
-			}
-	        MenuItem { 
-	            text: "Cut"
-			}
-	        MenuItem { 
-	            text: "Paste"
-			}
-	        MenuItem { 
-	            text: "Undo"
-			}
-	    }
 	}
 }
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index c435ca2f0b..d281282fc8 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -786,6 +786,7 @@ void Application::initializeUi() {
     offscreenUi->setProxyWindow(_window->windowHandle());
     offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
     offscreenUi->load("Root.qml");
+    offscreenUi->load("RootMenu.qml");
     offscreenUi->setMouseTranslator([this](const QPointF& p){
         if (OculusManager::isConnected()) {
             glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p));
@@ -1079,9 +1080,11 @@ bool Application::eventFilter(QObject* object, QEvent* event) {
 }
 
 static bool _altPressed;
+static bool _ctrlPressed;
 
 void Application::keyPressEvent(QKeyEvent* event) {
     _altPressed = event->key() == Qt::Key_Alt;
+    _ctrlPressed = event->key() == Qt::Key_Control;
     _keysPressed.insert(event->key());
 
     _controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts
@@ -1336,6 +1339,12 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
     if (event->key() == Qt::Key_Alt && _altPressed) {
         Menu::toggle();
     }
+    if (event->key() == Qt::Key_Control && _ctrlPressed) {
+        auto offscreenUi = DependencyManager::get<OffscreenUi>();
+        auto rootMenu = offscreenUi->getRootItem()->findChild<QObject*>("rootMenu");
+        QMetaObject::invokeMethod(rootMenu, "popup");
+    }
+    _ctrlPressed = event->key() == Qt::Key_Control;
 
     _keysPressed.remove(event->key());
 
diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp
index 026af1442f..529fca5e66 100644
--- a/interface/src/Menu.cpp
+++ b/interface/src/Menu.cpp
@@ -12,7 +12,7 @@
 #include <QFileDialog>
 #include <QMenuBar>
 #include <QShortcut>
-#include <QmlContext>
+#include <QQmlContext>
 
 #include <AddressManager.h>
 #include <AudioClient.h>
@@ -52,34 +52,43 @@ HifiAction::HifiAction(const QString & menuOption) : _menuOption(menuOption) {
 //    qFatal("Not implemented");
 //}
 
-void HifiAction::setChecked(bool) {
-    qFatal("Not implemented");
+void HifiAction::setChecked(bool checked) {
+    Menu::getInstance()->setChecked(_menuOption, checked);
 }
 
-void HifiAction::setVisible(bool) {
-    qFatal("Not implemented");
+void HifiAction::setVisible(bool visible) {
+    QObject* result = Menu::getInstance()->findMenuObject(_menuOption);
+    if (result) {
+        result->setProperty("visible", visible);
+    }
 }
 
 const QString & HifiAction::shortcut() const {
-    qFatal("Not implemented");
-    return "";
+    static const QString NONE;
+    QObject* result = Menu::getInstance()->findMenuObject(_menuOption);
+    if (!result) {
+        return NONE;
+    }
+    QObject* shortcut = result->property("shortcut").value<QObject*>();
+    if (!shortcut) {
+        return NONE;
+    }
+    shortcut->dumpObjectInfo();
+    return NONE;
 }
 
-void HifiAction::setText(const QString &) {
-    qFatal("Not implemented");
+void HifiAction::setText(const QString & text) {
+    Menu::getInstance()->setText(_menuOption, text);
 }
 
 void HifiAction::setTriggerAction(std::function<void()> f) {
-    qFatal("Not implemented");
+    Menu::getInstance()->setTriggerAction(_menuOption, f);
 }
 
 void HifiAction::setToggleAction(std::function<void(bool)> f) {
-    qFatal("Not implemented");
+    Menu::getInstance()->setToggleAction(_menuOption, f);
 }
 
-HIFI_QML_DEF(Menu)
-
-
 Menu* Menu::_instance = nullptr;
 
 Menu* Menu::getInstance() {
@@ -88,15 +97,11 @@ Menu* Menu::getInstance() {
         static QMutex menuInstanceMutex;
         withLock(menuInstanceMutex, [] {
             if (!_instance) {
-                OffscreenUi * offscreenUi = DependencyManager::get<OffscreenUi>().data();
-                QQmlContext * qmlContext = offscreenUi->qmlContext();
-                qmlContext->setContextProperty("foo", QVariant::fromValue(foo));
-//                qmlContext->setContextProperty("presetsModel", QVariant::fromValue(dataList));
-
+                qmlRegisterType<Menu>("Hifi", 1, 0, NAME.toLocal8Bit().constData());
                 qCDebug(interfaceapp, "First call to Menu::getInstance() - initing menu.");
-                load([&](QQmlContext *, QQuickItem* item) {
-                    _instance = dynamic_cast<Menu*>(item);
-                });
+                Menu::load();
+                auto uiRoot = DependencyManager::get<OffscreenUi>()->getRootItem();
+                _instance = uiRoot->findChild<Menu*>(NAME);
                 if (!_instance) {
                     qFatal("Could not load menu QML");
                 } else {
@@ -108,380 +113,362 @@ Menu* Menu::getInstance() {
     return _instance;
 }
 
-Menu::Menu(QQuickItem * parent) : QQuickItem(parent) {
+Menu::Menu(QQuickItem * parent) : HifiMenu(parent) {
 }
 
-QObject * _rootMenu;
-static const QString FILE_MENU{ "File" };
-static const QString EDIT_MENU{ "Edit" };
-static const QString TOOLS_MENU{ "Tools" };
-static const QString AVATAR_MENU{ "Avatar" };
-
-
-static const QString MENU_SUFFIX{ "__Menu" };
-
-QObject * addMenu(QObject * parent, const QString & text) {
-    // FIXME add more checking here to ensure no name conflicts
-    QVariant returnedValue;
-    QMetaObject::invokeMethod(parent, "addMenu",
-        Q_RETURN_ARG(QVariant, returnedValue),
-        Q_ARG(QVariant, text));
-    QObject * result = returnedValue.value<QObject*>();
-    if (result) {
-        result->setObjectName(text + MENU_SUFFIX);
-    }
-    return result;
-}
-
-class QQuickMenuItem;
-QObject * addItem(QObject * parent, const QString & text) {
-    // FIXME add more checking here to ensure no name conflicts
-    QQuickMenuItem* returnedValue;
-    QMetaObject::invokeMethod(parent, "addItem",
-        Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
-        Q_ARG(QString, text));
-    QObject* result = reinterpret_cast<QObject*>(returnedValue);
-    if (result) {
-        result->setObjectName(text + MENU_SUFFIX);
-    }
-    return result;
-}
 
 void Menu::init() {
-    _rootMenu = property("menu").value<QObject*>();
-    QObject * fileMenu = ::addMenu(_rootMenu, FILE_MENU);
-
     auto dialogsManager = DependencyManager::get<DialogsManager>();
     AccountManager& accountManager = AccountManager::getInstance();
-
+    static const QString ROOT_MENU;
     {
-        ::addItem(fileMenu, MenuOption::Login);
-
-        // connect to the appropriate signal of the AccountManager so that we can change the Login/Logout menu item
-        connect(&accountManager, &AccountManager::profileChanged,
-            dialogsManager.data(), &DialogsManager::toggleLoginDialog);
-        connect(&accountManager, &AccountManager::logoutComplete,
-            dialogsManager.data(), &DialogsManager::toggleLoginDialog);
-    }
-
+        static const QString FILE_MENU{ "File" };
+        addMenu(ROOT_MENU, FILE_MENU);
+        {
+            addMenuItem(FILE_MENU, MenuOption::Login);
+            // connect to the appropriate signal of the AccountManager so that we can change the Login/Logout menu item
+            connect(&accountManager, &AccountManager::profileChanged,
+                dialogsManager.data(), &DialogsManager::toggleLoginDialog);
+            connect(&accountManager, &AccountManager::logoutComplete,
+                dialogsManager.data(), &DialogsManager::toggleLoginDialog);
+        }
 
 #ifdef Q_OS_MAC
-    addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole);
+        addActionToQMenuAndActionHash(fileMenu, MenuOption::AboutApp, 0, qApp, SLOT(aboutApp()), QAction::AboutRole);
 #endif
 
-    {
-        static const QString SCRIPTS_MENU{ "Scripts" };
-        addMenu(FILE_MENU, SCRIPTS_MENU);
-        //Qt::CTRL | Qt::Key_O
-        addMenuItem(SCRIPTS_MENU, MenuOption::LoadScript, [=] {
-            qApp->loadDialog();
-        });
-        //Qt::CTRL | Qt::SHIFT | Qt::Key_O
-        addMenuItem(SCRIPTS_MENU, MenuOption::LoadScriptURL, [=] {
-            qApp->loadScriptURLDialog();
-        });
-        addMenuItem(SCRIPTS_MENU, MenuOption::StopAllScripts, [=] {
-            qApp->stopAllScripts();
-        });
-        //Qt::CTRL | Qt::Key_R,
-        addMenuItem(SCRIPTS_MENU, MenuOption::ReloadAllScripts, [=] {
-            qApp->reloadAllScripts();
-        });
-        // Qt::CTRL | Qt::Key_J,
-        addMenuItem(SCRIPTS_MENU, MenuOption::RunningScripts, [=] {
-            qApp->toggleRunningScriptsWidget();
+        {
+            static const QString SCRIPTS_MENU{ "Scripts" };
+            addMenu(FILE_MENU, SCRIPTS_MENU);
+            //Qt::CTRL | Qt::Key_O
+            addMenuItem(SCRIPTS_MENU, MenuOption::LoadScript, [=] {
+                qApp->loadDialog();
+            });
+            //Qt::CTRL | Qt::SHIFT | Qt::Key_O
+            addMenuItem(SCRIPTS_MENU, MenuOption::LoadScriptURL, [=] {
+                qApp->loadScriptURLDialog();
+            });
+            addMenuItem(SCRIPTS_MENU, MenuOption::StopAllScripts, [=] {
+                qApp->stopAllScripts();
+            });
+            //Qt::CTRL | Qt::Key_R,
+            addMenuItem(SCRIPTS_MENU, MenuOption::ReloadAllScripts, [=] {
+                qApp->reloadAllScripts();
+            });
+            // Qt::CTRL | Qt::Key_J,
+            addMenuItem(SCRIPTS_MENU, MenuOption::RunningScripts, [=] {
+                qApp->toggleRunningScriptsWidget();
+            });
+        }
+
+        {
+            static const QString LOCATION_MENU{ "Location" };
+            addMenu(FILE_MENU, LOCATION_MENU);
+            qApp->getBookmarks()->setupMenus(LOCATION_MENU);
+            //Qt::CTRL | Qt::Key_L
+            addMenuItem(LOCATION_MENU, MenuOption::AddressBar, [=] {
+                auto dialogsManager = DependencyManager::get<DialogsManager>();
+                dialogsManager->toggleAddressBar();
+            });
+            addMenuItem(LOCATION_MENU, MenuOption::CopyAddress, [=] {
+                auto addressManager = DependencyManager::get<AddressManager>();
+                addressManager->copyAddress();
+            });
+            addMenuItem(LOCATION_MENU, MenuOption::CopyPath, [=] {
+                auto addressManager = DependencyManager::get<AddressManager>();
+                addressManager->copyPath();
+            });
+        }
+
+        // Qt::CTRL | Qt::Key_Q
+        // QAction::QuitRole
+        addMenuItem(FILE_MENU, MenuOption::Quit, [=] {
+            qApp->quit();
         });
     }
 
+
     {
-        static const QString LOCATION_MENU{ "Location" };
-        addMenu(FILE_MENU, LOCATION_MENU);
-        qApp->getBookmarks()->setupMenus(LOCATION_MENU);
-        //Qt::CTRL | Qt::Key_L
-        addMenuItem(LOCATION_MENU, MenuOption::AddressBar, [=] {
-            auto dialogsManager = DependencyManager::get<DialogsManager>();
-            dialogsManager->toggleAddressBar();
-        });
-        addMenuItem(LOCATION_MENU, MenuOption::CopyAddress, [=] {
-            auto addressManager = DependencyManager::get<AddressManager>();
-            addressManager->copyAddress();
-        });
-        addMenuItem(LOCATION_MENU, MenuOption::CopyAddress, [=] {
-            auto addressManager = DependencyManager::get<AddressManager>();
-            addressManager->copyPath();
-        });
-    }
+        static const QString EDIT_MENU{ "Edit" };
+        addMenu(ROOT_MENU, EDIT_MENU);
 #if 0
-    
-    addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyAddress, 0,
-                                  addressManager.data(), SLOT(copyAddress()));
-    addActionToQMenuAndActionHash(fileMenu, MenuOption::CopyPath, 0,
-                                  addressManager.data(), SLOT(copyPath()));
+        QUndoStack* undoStack = qApp->getUndoStack();
+        QAction* undoAction = undoStack->createUndoAction(editMenu);
+        undoAction->setShortcut(Qt::CTRL | Qt::Key_Z);
+        addActionToQMenuAndActionHash(editMenu, undoAction);
 
-    addActionToQMenuAndActionHash(fileMenu,
-                                  MenuOption::Quit,
-                                  Qt::CTRL | Qt::Key_Q,
-                                  qApp,
-                                  SLOT(quit()),
-                                  QAction::QuitRole);
+        QAction* redoAction = undoStack->createRedoAction(editMenu);
+        redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z);
+        addActionToQMenuAndActionHash(editMenu, redoAction);
+#endif
 
+        // Qt::CTRL | Qt::Key_Comma
+        // QAction::PreferencesRole
+        addMenuItem(EDIT_MENU, MenuOption::Preferences, [=] {
+            dialogsManager->editPreferences();
+        });
+        addMenuItem(EDIT_MENU, MenuOption::Animations, [=] {
+            dialogsManager->editAnimations();
+        });
+    }
 
-    QMenu* editMenu = addMenu("Edit");
-
-    QUndoStack* undoStack = qApp->getUndoStack();
-    QAction* undoAction = undoStack->createUndoAction(editMenu);
-    undoAction->setShortcut(Qt::CTRL | Qt::Key_Z);
-    addActionToQMenuAndActionHash(editMenu, undoAction);
-
-    QAction* redoAction = undoStack->createRedoAction(editMenu);
-    redoAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_Z);
-    addActionToQMenuAndActionHash(editMenu, redoAction);
-
-    addActionToQMenuAndActionHash(editMenu,
-                                  MenuOption::Preferences,
-                                  Qt::CTRL | Qt::Key_Comma,
-                                  dialogsManager.data(),
-                                  SLOT(editPreferences()),
-                                  QAction::PreferencesRole);
-
-    addActionToQMenuAndActionHash(editMenu, MenuOption::Attachments, 0,
-                                  dialogsManager.data(), SLOT(editAttachments()));
-    addActionToQMenuAndActionHash(editMenu, MenuOption::Animations, 0,
-                                  dialogsManager.data(), SLOT(editAnimations()));
-
-    QMenu* toolsMenu = addMenu("Tools");
-    addActionToQMenuAndActionHash(toolsMenu, MenuOption::ScriptEditor,  Qt::ALT | Qt::Key_S,
-                                  dialogsManager.data(), SLOT(showScriptEditor()));
+    {
+        static const QString TOOLS_MENU{ "Tools" };
+        addMenu(ROOT_MENU, TOOLS_MENU);
 
 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
-    auto speechRecognizer = DependencyManager::get<SpeechRecognizer>();
-    QAction* speechRecognizerAction = addCheckableActionToQMenuAndActionHash(toolsMenu, MenuOption::ControlWithSpeech,
-                                                                             Qt::CTRL | Qt::SHIFT | Qt::Key_C,
-                                                                             speechRecognizer->getEnabled(),
-                                                                             speechRecognizer.data(),
-                                                                             SLOT(setEnabled(bool)));
-    connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool)));
+        auto speechRecognizer = DependencyManager::get<SpeechRecognizer>();
+        //Qt::CTRL | Qt::SHIFT | Qt::Key_C
+        addMenuItem(TOOLS_MENU, MenuOption::ControlWithSpeech);
+        setChecked(MenuOption::ControlWithSpeech, speechRecognizer->getEnabled());
+        connect(speechRecognizer.data(), &SpeechRecognizer::enabledUpdated, [=] {
+            setChecked(MenuOption::ControlWithSpeech, speechRecognizer->getEnabled());
+        });
 #endif
-    
-    addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, 
-                                  0, // QML Qt::Key_Backslash,
-                                  dialogsManager.data(), SLOT(showIRCLink()));
-    addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0,
-                                  qApp, SLOT(showFriendsWindow()));
+        // Qt::ALT | Qt::Key_S,
+        addMenuItem(TOOLS_MENU, MenuOption::ScriptEditor, [=] {
+            dialogsManager->showScriptEditor();
+        });
+        // QML Qt::Key_Backslash,
+        addMenuItem(TOOLS_MENU, MenuOption::Chat, [=] {
+            dialogsManager->showIRCLink();
+        });
+        addMenuItem(TOOLS_MENU, MenuOption::AddRemoveFriends, [=] {
+            qApp->showFriendsWindow();
+        });
 
-    QMenu* visibilityMenu = toolsMenu->addMenu("I Am Visible To");
-    {
-        QActionGroup* visibilityGroup = new QActionGroup(toolsMenu);
-        auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
+#if 0
+        QMenu* visibilityMenu = toolsMenu->addMenu("I Am Visible To");
+        {
+            QActionGroup* visibilityGroup = new QActionGroup(toolsMenu);
+            auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>();
 
-        QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone,
-            0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All,
-            discoverabilityManager.data(), SLOT(setVisibility()));
-        visibilityGroup->addAction(visibleToEveryone);
+            QAction* visibleToEveryone = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToEveryone,
+                0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::All,
+                discoverabilityManager.data(), SLOT(setVisibility()));
+            visibilityGroup->addAction(visibleToEveryone);
 
-        QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends,
-            0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends,
-            discoverabilityManager.data(), SLOT(setVisibility()));
-        visibilityGroup->addAction(visibleToFriends);
+            QAction* visibleToFriends = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToFriends,
+                0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::Friends,
+                discoverabilityManager.data(), SLOT(setVisibility()));
+            visibilityGroup->addAction(visibleToFriends);
 
-        QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne,
-            0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None,
-            discoverabilityManager.data(), SLOT(setVisibility()));
-        visibilityGroup->addAction(visibleToNoOne);
+            QAction* visibleToNoOne = addCheckableActionToQMenuAndActionHash(visibilityMenu, MenuOption::VisibleToNoOne,
+                0, discoverabilityManager->getDiscoverabilityMode() == Discoverability::None,
+                discoverabilityManager.data(), SLOT(setVisibility()));
+            visibilityGroup->addAction(visibleToNoOne);
 
-        connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged, 
-            discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged);
+            connect(discoverabilityManager.data(), &DiscoverabilityManager::discoverabilityModeChanged,
+                discoverabilityManager.data(), &DiscoverabilityManager::visibilityChanged);
+        }
+#endif
+        //Qt::CTRL | Qt::ALT | Qt::Key_T,
+        addMenuItem(TOOLS_MENU, MenuOption::ToolWindow, [=] {
+//            dialogsManager->toggleToolWindow();
+        });
+
+        //Qt::CTRL | Qt::ALT | Qt::Key_J,
+        addMenuItem(TOOLS_MENU, MenuOption::Console, [=] {
+            DependencyManager::get<StandAloneJSConsole>()->toggleConsole();
+        });
+
+        // QML Qt::Key_Apostrophe,
+        addMenuItem(TOOLS_MENU, MenuOption::ResetSensors, [=] {
+            qApp->resetSensors();
+        });
+
+        addMenuItem(TOOLS_MENU, MenuOption::PackageModel, [=] {
+            qApp->packageModel();
+        });
     }
 
-    addActionToQMenuAndActionHash(toolsMenu,
-                                  MenuOption::ToolWindow,
-                                  Qt::CTRL | Qt::ALT | Qt::Key_T,
-                                  dialogsManager.data(),
-                                  SLOT(toggleToolWindow()));
-
-    addActionToQMenuAndActionHash(toolsMenu,
-                                  MenuOption::Console,
-                                  Qt::CTRL | Qt::ALT | Qt::Key_J,
-                                  DependencyManager::get<StandAloneJSConsole>().data(),
-                                  SLOT(toggleConsole()));
-
-    addActionToQMenuAndActionHash(toolsMenu,
-                                  MenuOption::ResetSensors,
-                                  0, // QML Qt::Key_Apostrophe,
-                                  qApp,
-                                  SLOT(resetSensors()));
-    
-    addActionToQMenuAndActionHash(toolsMenu, MenuOption::PackageModel, 0,
-                                  qApp, SLOT(packageModel()));
-
-    QMenu* avatarMenu = addMenu("Avatar");
-    QObject* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
-
-    QMenu* avatarSizeMenu = avatarMenu->addMenu("Size");
-    addActionToQMenuAndActionHash(avatarSizeMenu,
-                                  MenuOption::IncreaseAvatarSize,
-                                  0, // QML Qt::Key_Plus,
-                                  avatar,
-                                  SLOT(increaseSize()));
-    addActionToQMenuAndActionHash(avatarSizeMenu,
-                                  MenuOption::DecreaseAvatarSize,
-                                  0, // QML Qt::Key_Minus,
-                                  avatar,
-                                  SLOT(decreaseSize()));
-    addActionToQMenuAndActionHash(avatarSizeMenu,
-                                  MenuOption::ResetAvatarSize,
-                                  0, // QML Qt::Key_Equal,
-                                  avatar,
-                                  SLOT(resetSize()));
-
-    addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::KeyboardMotorControl,
-            Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehavior()));
-    addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ScriptedMotorControl, 0, true,
-            avatar, SLOT(updateMotionBehavior()));
-    addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true);
-    addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true);
-    addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true);
-    addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true,
-            avatar, SLOT(updateMotionBehavior()));
-    addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false,
-            avatar, SLOT(updateMotionBehavior()));
-
-    QMenu* viewMenu = addMenu("View");
-
-    addCheckableActionToQMenuAndActionHash(viewMenu,
-                                           MenuOption::Fullscreen,
-#ifdef Q_OS_MAC
-                                           Qt::CTRL | Qt::META | Qt::Key_F,
-#else
-                                           Qt::CTRL | Qt::Key_F,
-#endif
-                                           false,
-                                           qApp,
-                                           SLOT(setFullscreen(bool)));
-
-    addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, 
-        0, // QML Qt::Key_P, 
-        true, qApp, SLOT(cameraMenuChanged()));
-    addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, 
-        0, //QML Qt::SHIFT | Qt::Key_H, 
-        true);
-    addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, 
-        0, // QML Qt::Key_H, 
-        false, qApp, SLOT(cameraMenuChanged()));
-
-    addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, 
-#ifdef Q_OS_MAC
-                                           Qt::META | Qt::Key_H,
-#else
-                                           Qt::CTRL | Qt::Key_H,
-#endif
-                                           false,
-                                           dialogsManager.data(),
-                                           SLOT(hmdTools(bool)));
-
-    addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::EnableVRMode, 0,
-                                           false,
-                                           qApp,
-                                           SLOT(setEnableVRMode(bool)));
-
-    addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0,
-                                           false,
-                                           qApp,
-                                           SLOT(setEnable3DTVMode(bool)));
-
-
-    QMenu* nodeBordersMenu = viewMenu->addMenu("Server Borders");
-    NodeBounds& nodeBounds = qApp->getNodeBoundsDisplay();
-    addCheckableActionToQMenuAndActionHash(nodeBordersMenu, MenuOption::ShowBordersEntityNodes,
-                                           Qt::CTRL | Qt::SHIFT | Qt::Key_1, false,
-                                           &nodeBounds, SLOT(setShowEntityNodes(bool)));
-
-    addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::OffAxisProjection, 0, false);
-    addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false);
-
-
-    addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats,
-        0); // QML Qt::Key_Slash);
-    addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats);
-    addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, 
-        Qt::CTRL | Qt::SHIFT | Qt::Key_L, 
-        qApp, SLOT(toggleLogDialog()));
-    addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0,
-                                  dialogsManager.data(), SLOT(bandwidthDetails()));
-    addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0,
-                                  dialogsManager.data(), SLOT(octreeStatsDetails()));
-
-
-    QMenu* developerMenu = addMenu("Developer");
-
-    QMenu* renderOptionsMenu = developerMenu->addMenu("Render");
-    addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, 
-        0, // QML Qt::SHIFT | Qt::Key_A, 
-        true);
-    addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion);
-    addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges);
-
-    QMenu* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight);
-    QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu);
-    ambientLightGroup->setExclusive(true);
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLightGlobal, 0, true));
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight0, 0, false));
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight1, 0, false));
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight2, 0, false));
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight3, 0, false));
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight4, 0, false));
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight5, 0, false));
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight6, 0, false));
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight7, 0, false));
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight8, 0, false));
-    ambientLightGroup->addAction(addCheckableActionToQMenuAndActionHash(ambientLightMenu, MenuOption::RenderAmbientLight9, 0, false));
-    
-    QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows");
-    QActionGroup* shadowGroup = new QActionGroup(shadowMenu);
-    shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true));
-    shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false));
-    shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false));
-
     {
-        QMenu* framerateMenu = renderOptionsMenu->addMenu(MenuOption::RenderTargetFramerate);
-        QActionGroup* framerateGroup = new QActionGroup(framerateMenu);
-        framerateGroup->setExclusive(true);
-        framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerateUnlimited, 0, true));
-        framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate60, 0, false));
-        framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate50, 0, false));
-        framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate40, 0, false));
-        framerateGroup->addAction(addCheckableActionToQMenuAndActionHash(framerateMenu, MenuOption::RenderTargetFramerate30, 0, false));
+        static const QString AVATAR_MENU{ "Avatar" };
+        addMenu(ROOT_MENU, AVATAR_MENU);
+        auto avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
+        {
+            static const QString SIZE_MENU{ "Size" };
+            addMenu(AVATAR_MENU, SIZE_MENU);
+            // QML Qt::Key_Plus,
+            addMenuItem(SIZE_MENU, MenuOption::IncreaseAvatarSize, [=] {
+                avatar->increaseSize();
+            });
+            // QML Qt::Key_Minus,
+            addMenuItem(SIZE_MENU, MenuOption::DecreaseAvatarSize, [=] {
+                avatar->decreaseSize();
+            });
+            // QML Qt::Key_Equal,
+            addMenuItem(SIZE_MENU, MenuOption::ResetAvatarSize, [=] {
+                avatar->resetSize();
+            });
 
-#if defined(Q_OS_MAC)
-#else
-        addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::RenderTargetFramerateVSyncOn, 0, true,
-                                               qApp, SLOT(setVSyncEnabled()));
-#endif
+            addMenuItem(SIZE_MENU, MenuOption::ResetAvatarSize, [=] {
+                avatar->resetSize();
+            });
+        }
+
+        //Qt::CTRL | Qt::SHIFT | Qt::Key_K
+        addCheckableMenuItem(AVATAR_MENU, MenuOption::KeyboardMotorControl, true, [=](bool) {
+            avatar->updateMotionBehavior();
+        });
+        addCheckableMenuItem(AVATAR_MENU, MenuOption::ScriptedMotorControl, true);
+        addCheckableMenuItem(AVATAR_MENU, MenuOption::NamesAboveHeads, true);
+        addCheckableMenuItem(AVATAR_MENU, MenuOption::GlowWhenSpeaking, true);
+        addCheckableMenuItem(AVATAR_MENU, MenuOption::BlueSpeechSphere, true);
+        addCheckableMenuItem(AVATAR_MENU, MenuOption::EnableCharacterController, true, [=](bool) {
+            avatar->updateMotionBehavior();
+        });
+        addCheckableMenuItem(AVATAR_MENU, MenuOption::ShiftHipsForIdleAnimations, false, [=](bool) {
+            avatar->updateMotionBehavior();
+        });
     }
 
+    {
+        static const QString VIEW_MENU{ "View" };
+        addMenu(ROOT_MENU, VIEW_MENU);
 
-    QMenu* resolutionMenu = renderOptionsMenu->addMenu(MenuOption::RenderResolution);
-    QActionGroup* resolutionGroup = new QActionGroup(resolutionMenu);
-    resolutionGroup->setExclusive(true);
-    resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionOne, 0, true));
-    resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionTwoThird, 0, false));
-    resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionHalf, 0, false));
-    resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false));
-    resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false));
+        // Mac Qt::CTRL | Qt::META | Qt::Key_F,
+        // Win32/Linux Qt::CTRL | Qt::Key_F,
+        addCheckableMenuItem(VIEW_MENU, MenuOption::Fullscreen, false, [=](bool checked) {
+//            qApp->setFullscreen(checked);
+        });
+        // QML Qt::Key_P, 
+        addCheckableMenuItem(VIEW_MENU, MenuOption::FirstPerson, true, [=](bool checked) {
+//            qApp->cameraMenuChanged();
+        });
+        //QML Qt::SHIFT | Qt::Key_H, 
+        addCheckableMenuItem(VIEW_MENU, MenuOption::Mirror, true);
 
-    addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, 
-        0, // QML Qt::Key_Asterisk,
-        true);
-    addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true, 
-                                            DependencyManager::get<GlowEffect>().data(), SLOT(toggleGlowEffect(bool)));
+        // QML Qt::Key_H, 
+        addCheckableMenuItem(VIEW_MENU, MenuOption::FullscreenMirror, true, [=](bool checked) {
+//            qApp->cameraMenuChanged();
+        });
 
-    addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Wireframe, Qt::ALT | Qt::Key_W, false);
-    addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, 
-        0, // QML Qt::SHIFT | Qt::Key_L,
-        dialogsManager.data(), SLOT(lodTools()));
+        // Mac Qt::META | Qt::Key_H,
+        // Win32/Linux Qt::CTRL | Qt::Key_H,
+        addCheckableMenuItem(VIEW_MENU, MenuOption::HMDTools, false, [=](bool checked) {
+            dialogsManager->hmdTools(checked);
+        });
+        addCheckableMenuItem(VIEW_MENU, MenuOption::EnableVRMode, false, [=](bool checked) {
+//            qApp->setEnableVRMode(checked);
+        });
+        addCheckableMenuItem(VIEW_MENU, MenuOption::Enable3DTVMode, false, [=](bool checked) {
+//            qApp->setEnable3DTVMode(checked);
+        });
 
-    QMenu* avatarDebugMenu = developerMenu->addMenu("Avatar");
+        {
+            static const QString BORDER_MENU{ "View" };
+            addMenu(VIEW_MENU, BORDER_MENU);
+            // Qt::CTRL | Qt::SHIFT | Qt::Key_1
+            addCheckableMenuItem(BORDER_MENU, MenuOption::ShowBordersEntityNodes, false, [=](bool checked) {
+                qApp->getNodeBoundsDisplay().setShowEntityNodes(checked);
+            });
+        }
+        addCheckableMenuItem(VIEW_MENU, MenuOption::OffAxisProjection, false);
+        addCheckableMenuItem(VIEW_MENU, MenuOption::TurnWithHead, false);
+        // QML Qt::Key_Slash
+        addCheckableMenuItem(VIEW_MENU, MenuOption::Stats, false);
 
+        // Qt::CTRL | Qt::SHIFT | Qt::Key_L
+        addMenuItem(VIEW_MENU, MenuOption::Log, [=] {
+            qApp->toggleLogDialog();
+        });
+        addMenuItem(VIEW_MENU, MenuOption::BandwidthDetails, [=] {
+            dialogsManager->bandwidthDetails();
+        });
+        addMenuItem(VIEW_MENU, MenuOption::OctreeStats, [=] {
+            dialogsManager->octreeStatsDetails();
+        });
+    }
+
+    {
+        static const QString DEV_MENU{ "Developer" };
+        addMenu(ROOT_MENU, DEV_MENU);
+        {
+            static const QString RENDER_MENU{ "Render" };
+            addMenu(DEV_MENU, RENDER_MENU);
+            // QML Qt::SHIFT | Qt::Key_A, 
+            addCheckableMenuItem(RENDER_MENU, MenuOption::Atmosphere, true);
+            addCheckableMenuItem(RENDER_MENU, MenuOption::AmbientOcclusion);
+            addCheckableMenuItem(RENDER_MENU, MenuOption::DontFadeOnOctreeServerChanges);
+            {
+                static const QString LIGHT_MENU{ MenuOption::RenderAmbientLight };
+                addMenu(RENDER_MENU, LIGHT_MENU);
+                static QStringList LIGHTS{
+                    MenuOption::RenderAmbientLightGlobal,
+                    MenuOption::RenderAmbientLight0,
+                    MenuOption::RenderAmbientLight1,
+                    MenuOption::RenderAmbientLight2,
+                    MenuOption::RenderAmbientLight3,
+                    MenuOption::RenderAmbientLight4,
+                    MenuOption::RenderAmbientLight5,
+                    MenuOption::RenderAmbientLight6,
+                    MenuOption::RenderAmbientLight7,
+                    MenuOption::RenderAmbientLight8,
+                    MenuOption::RenderAmbientLight9,
+                };
+                foreach(QString option, LIGHTS) {
+                    addCheckableMenuItem(LIGHT_MENU, option);
+                    // FIXME
+                    // setExclusiveGroup()
+                }
+                setChecked(MenuOption::RenderAmbientLightGlobal, true);
+            }
+            {
+                static const QString SHADOWS_MENU{ "Shadows" };
+                addMenu(RENDER_MENU, SHADOWS_MENU);
+                addCheckableMenuItem(SHADOWS_MENU, "No Shadows", true);
+                addCheckableMenuItem(SHADOWS_MENU, MenuOption::SimpleShadows);
+                addCheckableMenuItem(SHADOWS_MENU, MenuOption::CascadedShadows);
+            }
+            {
+                static const QString FRAMERATE_MENU{ MenuOption::RenderTargetFramerate };
+                addMenu(RENDER_MENU, FRAMERATE_MENU);
+                //framerateGroup->setExclusive(true);
+                addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerateUnlimited, true);
+                addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate60);
+                addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate50);
+                addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate40);
+                addCheckableMenuItem(FRAMERATE_MENU, MenuOption::RenderTargetFramerate30);
+            }
+#if !defined(Q_OS_MAC)
+            addCheckableMenuItem(RENDER_MENU, MenuOption::RenderTargetFramerateVSyncOn, true, [](bool checked) {
+                qApp->setVSyncEnabled();
+            });
+#endif
+            {
+                static const QString RES_MENU{ MenuOption::RenderResolution };
+                addMenu(RENDER_MENU, RES_MENU);
+                // resolutionGroup->setExclusive(true);
+                addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionOne, true);
+                addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionTwoThird);
+                addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionHalf);
+                addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionThird);
+                addCheckableMenuItem(RES_MENU, MenuOption::RenderResolutionQuarter);
+            }
+            // QML Qt::Key_Asterisk,
+            addCheckableMenuItem(RENDER_MENU, MenuOption::Stars, true);
+            addCheckableMenuItem(RENDER_MENU, MenuOption::EnableGlowEffect, true, [](bool checked){
+                DependencyManager::get<GlowEffect>()->toggleGlowEffect(checked);
+            });
+            //Qt::ALT | Qt::Key_W
+            addCheckableMenuItem(RENDER_MENU, MenuOption::Wireframe);
+            // QML Qt::SHIFT | Qt::Key_L,
+            addMenuItem(RENDER_MENU, MenuOption::LodTools, [=] {
+                dialogsManager->lodTools();
+            });
+        }
+
+        {
+            static const QString AVATAR_MENU{ "Avatar Dev" };
+            addMenu(DEV_MENU, AVATAR_MENU);
+            setText(AVATAR_MENU, "Avatar");
+            {
+            }
+        }
+    }
+
+#if 0
     QMenu* faceTrackingMenu = avatarDebugMenu->addMenu("Face Tracking");
     {
         QActionGroup* faceTrackerGroup = new QActionGroup(avatarDebugMenu);
@@ -730,362 +717,4 @@ void Menu::addDisabledActionAndSeparator(QMenu* destinationMenu, const QString&
     }
 }
 
-QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu,
-                                             const QString& actionName,
-                                             const QKeySequence& shortcut,
-                                             const QObject* receiver,
-                                             const char* member,
-                                             QAction::MenuRole role,
-                                             int menuItemLocation) {
-    QAction* action = NULL;
-    QAction* actionBefore = NULL;
-
-    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 = new QAction(actionName, destinationMenu);
-        action->setShortcut(shortcut);
-        destinationMenu->insertAction(actionBefore, action);
-
-        if (receiver && member) {
-            connect(action, SIGNAL(triggered()), receiver, member);
-        }
-    }
-    action->setMenuRole(role);
-
-    _actionHash.insert(actionName, action);
-
-    return action;
-}
-
-QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu,
-                                             QAction* action,
-                                             const QString& actionName,
-                                             const QKeySequence& shortcut,
-                                             QAction::MenuRole role,
-                                             int menuItemLocation) {
-    QAction* actionBefore = NULL;
-
-    if (menuItemLocation >= 0 && destinationMenu->actions().size() > menuItemLocation) {
-        actionBefore = destinationMenu->actions()[menuItemLocation];
-    }
-
-    if (!actionName.isEmpty()) {
-        action->setText(actionName);
-    }
-
-    if (shortcut != 0) {
-        action->setShortcut(shortcut);
-    }
-
-    if (role != QAction::NoRole) {
-        action->setMenuRole(role);
-    }
-
-    if (!actionBefore) {
-        destinationMenu->addAction(action);
-    } else {
-        destinationMenu->insertAction(actionBefore, action);
-    }
-
-    _actionHash.insert(action->text(), action);
-
-    return action;
-}
-
-QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
-                                                      const QString& actionName,
-                                                      const QKeySequence& shortcut,
-                                                      const bool checked,
-                                                      const QObject* receiver,
-                                                      const char* member,
-                                                      int menuItemLocation) {
-
-    QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member,
-                                                        QAction::NoRole, menuItemLocation);
-    action->setCheckable(true);
-    action->setChecked(checked);
-
-    return action;
-}
-
-void Menu::removeAction(QMenu* menu, const QString& actionName) {
-    menu->removeAction(_actionHash.value(actionName));
-    _actionHash.remove(actionName);
-}
-
 #endif
-
-void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) {
-}
-
-bool Menu::isOptionChecked(const QString& menuOption) const {
-    return false;
-}
-
-void Menu::triggerOption(const QString& menuOption) {
-}
-
-#if 0
-
-QAction* Menu::getActionForOption(const QString& menuOption) {
-    return _actionHash.value(menuOption);
-}
-
-QAction* Menu::getActionFromName(const QString& menuName, QMenu* menu) {
-    QList<QAction*> menuActions;
-    if (menu) {
-        menuActions = menu->actions();
-    } else {
-        menuActions = actions();
-    }
-    
-    foreach (QAction* menuAction, menuActions) {
-        if (menuName == menuAction->text()) {
-            return menuAction;
-        }
-    }
-    return NULL;
-}
-
-QMenu* Menu::getSubMenuFromName(const QString& menuName, QMenu* menu) {
-    QAction* action = getActionFromName(menuName, menu);
-    if (action) {
-        return action->menu();
-    }
-    return NULL;
-}
-
-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;
-}
-
-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;
-}
-
-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;
-}
-
-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
-}
-
-int Menu::positionBeforeSeparatorIfNeeded(QMenu* menu, int requestedPosition) {
-    QList<QAction*> menuActions = menu->actions();
-    if (requestedPosition > 1 && requestedPosition < menuActions.size()) {
-        QAction* beforeRequested = menuActions[requestedPosition - 1];
-        if (beforeRequested->isSeparator()) {
-            requestedPosition--;
-        }
-    }
-    return requestedPosition;
-}
-
-
-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) {
-            parent->removeAction(action);
-        } else {
-            QMenuBar::removeAction(action);
-        }
-        
-        QMenuBar::repaint();
-    }
-}
-
-bool Menu::menuExists(const QString& menuName) {
-    QAction* action = getMenuAction(menuName);
-    
-    // only proceed if the menu actually exists
-    if (action) {
-        return true;
-    }
-    return false;
-}
-
-void Menu::addSeparator(const QString& menuName, const QString& separatorName) {
-    QMenu* menuObj = getMenu(menuName);
-    if (menuObj) {
-        addDisabledActionAndSeparator(menuObj, separatorName);
-    }
-}
-
-void Menu::removeSeparator(const QString& menuName, const QString& separatorName) {
-    QMenu* menu = getMenu(menuName);
-    bool separatorRemoved = false;
-    if (menu) {
-        int textAt = findPositionOfMenuItem(menu, separatorName);
-        QList<QAction*> menuActions = menu->actions();
-        QAction* separatorText = menuActions[textAt];
-        if (textAt > 0 && textAt < menuActions.size()) {
-            QAction* separatorLine = menuActions[textAt - 1];
-            if (separatorLine) {
-                if (separatorLine->isSeparator()) {
-                    menu->removeAction(separatorText);
-                    menu->removeAction(separatorLine);
-                    separatorRemoved = true;
-                }
-            }
-        }
-    }
-    if (separatorRemoved) {
-        QMenuBar::repaint();
-    }
-}
-
-void Menu::addMenuItem(const MenuItemProperties& properties) {
-    QMenu* menuObj = getMenu(properties.menuName);
-    if (menuObj) {
-        QShortcut* shortcut = NULL;
-        if (!properties.shortcutKeySequence.isEmpty()) {
-            shortcut = new QShortcut(properties.shortcutKeySequence, this);
-        }
-        
-        // check for positioning requests
-        int requestedPosition = properties.position;
-        if (requestedPosition == UNSPECIFIED_POSITION && !properties.beforeItem.isEmpty()) {
-            requestedPosition = findPositionOfMenuItem(menuObj, properties.beforeItem);
-            // double check that the requested location wasn't a separator label
-            requestedPosition = positionBeforeSeparatorIfNeeded(menuObj, requestedPosition);
-        }
-        if (requestedPosition == UNSPECIFIED_POSITION && !properties.afterItem.isEmpty()) {
-            int afterPosition = findPositionOfMenuItem(menuObj, properties.afterItem);
-            if (afterPosition != UNSPECIFIED_POSITION) {
-                requestedPosition = afterPosition + 1;
-            }
-        }
-        
-        QAction* menuItemAction = NULL;
-        if (properties.isSeparator) {
-            addDisabledActionAndSeparator(menuObj, properties.menuItemName, requestedPosition);
-        } else if (properties.isCheckable) {
-            menuItemAction = addCheckableActionToQMenuAndActionHash(menuObj, properties.menuItemName,
-                                                                    properties.shortcutKeySequence, properties.isChecked,
-                                                                    MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), requestedPosition);
-        } else {
-            menuItemAction = addActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence,
-                                                           MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()),
-                                                           QAction::NoRole, requestedPosition);
-        }
-        if (shortcut && menuItemAction) {
-            connect(shortcut, SIGNAL(activated()), menuItemAction, SLOT(trigger()));
-        }
-        QMenuBar::repaint();
-    }
-}
-#endif
-
-void Menu::removeMenuItem(const QString& menuitem) {
-};
-
-#if 0
-bool Menu::menuItemExists(const QString& menu, const QString& menuitem) {
-    QAction* menuItemAction = _actionHash.value(menuitem);
-    if (menuItemAction) {
-        return (getMenu(menu) != NULL);
-    }
-    return false;
-};
-
-#endif
-
-void Menu::setOptionText(const QString& menuitem, const QString& text) {
-}
-
-void Menu::addMenu(const QString& parentMenu, const QString& text) {
-}
-
-void Menu::addMenuItem(const QString& parentMenu, const QString& menuItem) {
-}
-
-void Menu::addMenuItem(const QString& parentMenu, const QString& menuItem, std::function<void()> f) {
-    addMenuItem(parentMenu, menuItem);
-    setOptionTriggerAction(parentMenu, f);
-}
-
-void Menu::enableMenuItem(const QString& menuItem, bool enable) {
-}
-
-void Menu::setOptionTriggerAction(const QString& menuOption, std::function<void()> f) {
-    _triggerActions[menuOption] = f;
-}
-void Menu::setOptionToggleAction(const QString& menuOption, std::function<void(bool)> f) {
-    _toggleActions[menuOption] = f;
-}
diff --git a/interface/src/Menu.h b/interface/src/Menu.h
index 04275fcb32..e02dd7a789 100644
--- a/interface/src/Menu.h
+++ b/interface/src/Menu.h
@@ -24,6 +24,7 @@
 #include <OffscreenUi.h>
 
 #include "DiscoverabilityManager.h"
+#include <HifiMenu.h>
 
 class Settings;
 
@@ -41,46 +42,58 @@ public:
     void setToggleAction(std::function<void(bool)>);
 };
 
-class Menu : public QQuickItem {
+class Menu : public HifiMenu {
     Q_OBJECT
-    HIFI_QML_DECL
+
 public:
     Menu(QQuickItem * parent = 0);
     static Menu* getInstance();
-    
+
+    // Override the base type HifiMenu with this class instead
+    static void registerType() {
+        qmlRegisterType<Menu>("Hifi", 1, 0, NAME.toLocal8Bit().constData());
+    }
+
     void loadSettings();
     void saveSettings();
     HifiAction * getActionForOption(const QString& menuOption) {
         return new HifiAction(menuOption); 
     }
 //    QMenu* addMenu(const QString& menuName);
-    void removeMenu(const QString& menuName);
-    bool menuExists(const QString& menuName);
-    void addSeparator(const QString& menuName, const QString& separatorName);
-    void removeSeparator(const QString& menuName, const QString& separatorName);
-    void addMenuItem(const MenuItemProperties& properties);
-    void removeMenuItem(const QString& menuitem);
-    bool menuItemExists(const QString& menuName, const QString& menuitem);
-    bool isOptionChecked(const QString& menuOption) const;
-    void setIsOptionChecked(const QString& menuOption, bool isChecked);
-    void triggerOption(const QString& menuOption);
-    void setOptionText(const QString& menuOption, const QString & text);
-    void setOptionTriggerAction(const QString& menuOption, std::function<void()> f);
-    void setOptionToggleAction(const QString& menuOption, std::function<void(bool)> f);
-    void addMenuItem(const QString & parentMenu, const QString & menuOption, std::function<void()> f);
-    void addMenuItem(const QString & parentMenu, const QString & menuOption);
-    void addMenu(const QString & parentMenu, const QString & menuOption);
-    void enableMenuItem(const QString & menuOption, bool enabled = true);
+    //void removeMenu(const QString& menuName);
+    //bool menuExists(const QString& menuName);
+    //void addSeparator(const QString& menuName, const QString& separatorName);
+    //void removeSeparator(const QString& menuName, const QString& separatorName);
+    //void addMenuItem(const MenuItemProperties& properties);
+    //void removeMenuItem(const QString& menuitem);
+    //bool menuItemExists(const QString& menuName, const QString& menuitem);
+    bool isOptionChecked(const QString& menuOption) const {
+        return HifiMenu::isChecked(menuOption);
+    }
+    void setIsOptionChecked(const QString& menuOption, bool isChecked) {
+        HifiMenu::setChecked(menuOption, isChecked);
+    }
+    void triggerOption(const QString& menuOption) {
+        HifiMenu::triggerMenuItem(menuOption);
+    }
+    void setOptionText(const QString& menuOption, const QString & text) {
+        HifiMenu::setText(menuOption, text);
+    }
+    void setOptionTriggerAction(const QString& menuOption, std::function<void()> f) {
+        HifiMenu::setTriggerAction(menuOption, f);
+    }
+    //void setOptionToggleAction(const QString& menuOption, std::function<void(bool)> f);
+    //void addMenuItem(const QString & parentMenu, const QString & menuOption, std::function<void()> f);
+    //void addMenuItem(const QString & parentMenu, const QString & menuOption);
+    //void addMenu(const QString & parentMenu, const QString & menuOption);
+    //void enableMenuItem(const QString & menuOption, bool enabled = true);
 
 private:
     void init();
 
 private:
     static Menu* _instance;
-    
-    QHash<QString, std::function<void()>> _triggerActions;
-    QHash<QString, std::function<void(bool)>> _toggleActions;
-
+    friend class HifiAction;
 };
 
 namespace MenuOption {
diff --git a/libraries/ui/src/HifiMenu.cpp b/libraries/ui/src/HifiMenu.cpp
new file mode 100644
index 0000000000..6ca034522c
--- /dev/null
+++ b/libraries/ui/src/HifiMenu.cpp
@@ -0,0 +1,221 @@
+#include "HifiMenu.h"
+#include <QtQml>
+
+// FIXME can this be made a class member?
+static const QString MENU_SUFFIX{ "__Menu" };
+
+HIFI_QML_DEF_LAMBDA(HifiMenu, [=](QQmlContext* context, QObject* newItem) {
+    auto offscreenUi = DependencyManager::get<OffscreenUi>();
+    QObject * rootMenu = offscreenUi->getRootItem()->findChild<QObject*>("rootMenu");
+    Q_ASSERT(rootMenu);
+    static_cast<HifiMenu*>(newItem)->setRootMenu(rootMenu);
+    context->setContextProperty("rootMenu", rootMenu);
+});
+
+HifiMenu::HifiMenu(QQuickItem* parent) : QQuickItem(parent), _triggerMapper(this), _toggleMapper(this) {
+    this->setEnabled(false);
+    connect(&_triggerMapper, SIGNAL(mapped(QString)), this, SLOT(onTriggeredByName(const QString &)));
+    connect(&_toggleMapper, SIGNAL(mapped(QString)), this, SLOT(onToggledByName(const QString &)));
+}
+
+void HifiMenu::onTriggeredByName(const QString & name) {
+    qDebug() << name << " triggered";
+    if (_triggerActions.count(name)) {
+        _triggerActions[name]();
+    }
+}
+
+void HifiMenu::onToggledByName(const QString & name) {
+    qDebug() << name << " toggled";
+    if (_toggleActions.count(name)) {
+        QObject* menu = findMenuObject(name);
+        bool checked = menu->property("checked").toBool();
+        _toggleActions[name](checked);
+    }
+}
+
+void HifiMenu::setToggleAction(const QString & name, std::function<void(bool)> f) {
+    _toggleActions[name] = f;
+}
+
+void HifiMenu::setTriggerAction(const QString & name, std::function<void()> f) {
+    _triggerActions[name] = f;
+}
+
+QObject* addMenu(QObject* parent, const QString & text) {
+    // FIXME add more checking here to ensure no name conflicts
+    QVariant returnedValue;
+    QMetaObject::invokeMethod(parent, "addMenu",
+        Q_RETURN_ARG(QVariant, returnedValue),
+        Q_ARG(QVariant, text));
+    QObject* result = returnedValue.value<QObject*>();
+    if (result) {
+        result->setObjectName(text + MENU_SUFFIX);
+    }
+    return result;
+}
+
+class QQuickMenuItem;
+QObject* addItem(QObject* parent, const QString& text) {
+    // FIXME add more checking here to ensure no name conflicts
+    QQuickMenuItem* returnedValue{ nullptr };
+    bool invokeResult = QMetaObject::invokeMethod(parent, "addItem",
+        Q_RETURN_ARG(QQuickMenuItem*, returnedValue),
+        Q_ARG(QString, text));
+    Q_ASSERT(invokeResult);
+    QObject* result = reinterpret_cast<QObject*>(returnedValue);
+    return result;
+}
+
+const QObject* HifiMenu::findMenuObject(const QString & menuOption) const {
+    if (menuOption.isEmpty()) {
+        return _rootMenu;
+    }
+    const QObject* result = _rootMenu->findChild<QObject*>(menuOption + MENU_SUFFIX);
+    return result;
+}
+
+QObject* HifiMenu::findMenuObject(const QString & menuOption) {
+    if (menuOption.isEmpty()) {
+        return _rootMenu;
+    }
+    QObject* result = _rootMenu->findChild<QObject*>(menuOption + MENU_SUFFIX);
+    return result;
+}
+
+void HifiMenu::addMenu(const QString & parentMenu, const QString & menuOption) {
+    QObject* parent = findMenuObject(parentMenu);
+    QObject* result = ::addMenu(parent, menuOption);
+    Q_ASSERT(result);
+    result->setObjectName(menuOption + MENU_SUFFIX);
+    Q_ASSERT(findMenuObject(menuOption));
+}
+
+void HifiMenu::removeMenu(const QString& menuName) {
+    QObject* menu = findMenuObject(menuName);
+    Q_ASSERT(menu);
+    Q_ASSERT(menu != _rootMenu);
+    QMetaObject::invokeMethod(menu->parent(), "removeItem",
+        Q_ARG(QVariant, QVariant::fromValue(menu)));
+}
+
+bool HifiMenu::menuExists(const QString& menuName) const {
+    return findMenuObject(menuName);
+}
+
+void HifiMenu::addSeparator(const QString& parentMenu, const QString& separatorName) {
+    // FIXME 'add sep'
+//    addMenu(parentMenu, separatorName);
+//    setEnabled()
+}
+
+void HifiMenu::removeSeparator(const QString& parentMenu, const QString& separatorName) {
+}
+
+void HifiMenu::addMenuItem(const QString & parentMenu, const QString & menuOption) {
+    QObject* parent = findMenuObject(parentMenu);
+    Q_ASSERT(parent);
+    QObject* result = ::addItem(parent, menuOption);
+    Q_ASSERT(result);
+    result->setObjectName(menuOption + MENU_SUFFIX);
+    Q_ASSERT(findMenuObject(menuOption));
+
+    _triggerMapper.setMapping(result, menuOption);
+    connect(result, SIGNAL(triggered()), &_triggerMapper, SLOT(map()));
+
+    _toggleMapper.setMapping(result, menuOption);
+    connect(result, SIGNAL(toggled(bool)), &_toggleMapper, SLOT(map()));
+}
+
+void HifiMenu::addMenuItem(const QString & parentMenu, const QString & menuOption, std::function<void()> f) {
+    setTriggerAction(menuOption, f);
+    addMenuItem(parentMenu, menuOption);
+}
+
+void HifiMenu::removeMenuItem(const QString& menuOption) {
+    removeMenu(menuOption);
+}
+
+bool HifiMenu::menuItemExists(const QString& menuName, const QString& menuitem) const {
+    return findMenuObject(menuName);
+}
+
+void HifiMenu::triggerMenuItem(const QString& menuOption) {
+    QObject* menuItem = findMenuObject(menuOption);
+    Q_ASSERT(menuItem);
+    Q_ASSERT(menuItem != _rootMenu);
+    QMetaObject::invokeMethod(menuItem, "trigger");
+}
+
+QHash<QString, QString> warned;
+void warn(const QString & menuOption) {
+    if (!warned.contains(menuOption)) {
+        warned[menuOption] = menuOption;
+        qWarning() << "No menu item: " << menuOption;
+    }
+}
+
+bool HifiMenu::isChecked(const QString& menuOption) const {
+    const QObject* menuItem = findMenuObject(menuOption);
+    if (!menuItem) {
+        warn(menuOption); 
+        return false;
+    }
+    return menuItem->property("checked").toBool();
+}
+
+void HifiMenu::setChecked(const QString& menuOption, bool isChecked) {
+    QObject* menuItem = findMenuObject(menuOption);
+    if (!menuItem) {
+        warn(menuOption);
+        return;
+    }
+    menuItem->setProperty("checked", QVariant::fromValue(isChecked));
+    Q_ASSERT(menuItem->property("checked").toBool() == isChecked);
+}
+
+void HifiMenu::setCheckable(const QString& menuOption, bool checkable) {
+    QObject* menuItem = findMenuObject(menuOption);
+    if (!menuItem) {
+        warn(menuOption);
+        return;
+    }
+    
+    menuItem->setProperty("checkable", QVariant::fromValue(checkable));
+    Q_ASSERT(menuItem->property("checkable").toBool() == checkable);
+}
+
+void HifiMenu::setText(const QString& menuOption, const QString & text) {
+    QObject* menuItem = findMenuObject(menuOption);
+    if (!menuItem) {
+        warn(menuOption);
+        return;
+    }
+    menuItem->setProperty("text", QVariant::fromValue(text));
+}
+
+void HifiMenu::setRootMenu(QObject* rootMenu) {
+    _rootMenu = rootMenu;
+}
+
+void HifiMenu::enableMenuItem(const QString & menuOption, bool enabled) {
+    QObject* menuItem = findMenuObject(menuOption);
+    if (!menuItem) {
+        warn(menuOption);
+        return;
+    }
+    menuItem->setProperty("enabled", QVariant::fromValue(enabled));
+}
+
+void HifiMenu::addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked) {
+    addMenuItem(parentMenu, menuOption);
+    setCheckable(menuOption);
+    if (checked) {
+        setChecked(menuOption, checked);
+    }
+}
+
+void HifiMenu::addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function<void(bool)> f) {
+    setToggleAction(menuOption, f);
+    addCheckableMenuItem(parentMenu, menuOption, checked);
+}
diff --git a/libraries/ui/src/HifiMenu.h b/libraries/ui/src/HifiMenu.h
new file mode 100644
index 0000000000..4d7d860224
--- /dev/null
+++ b/libraries/ui/src/HifiMenu.h
@@ -0,0 +1,72 @@
+//
+//  MenuConstants.h
+//
+//  Created by Bradley Austin Davis on 2015/04/21
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+#ifndef hifi_MenuContants_h
+#define hifi_MenuConstants_h
+
+#include <QQuickItem>
+#include <QHash>
+#include <QList>
+#include <QSignalMapper>
+#include "OffscreenUi.h"
+
+class HifiMenu : public QQuickItem {
+    Q_OBJECT
+    HIFI_QML_DECL_LAMBDA
+
+public:
+    HifiMenu(QQuickItem* parent = nullptr);
+
+    void setToggleAction(const QString& name, std::function<void(bool)> f);
+    void setTriggerAction(const QString& name, std::function<void()> f);
+
+    void addMenu(const QString& parentMenu, const QString& menuOption);
+    void removeMenu(const QString& menuName);
+    bool menuExists(const QString& menuName) const;
+
+    void addSeparator(const QString& menuName, const QString& separatorName);
+    void removeSeparator(const QString& menuName, const QString& separatorName);
+
+    void addMenuItem(const QString& parentMenu, const QString& menuOption);
+    void addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked = false);
+    void addCheckableMenuItem(const QString& parentMenu, const QString& menuOption, bool checked, std::function<void(bool)> f);
+    void addMenuItem(const QString& parentMenu, const QString& menuOption, std::function<void()> f);
+    void removeMenuItem(const QString& menuitem);
+    bool menuItemExists(const QString& menuName, const QString& menuitem) const;
+    void triggerMenuItem(const QString& menuOption);
+    void enableMenuItem(const QString& menuOption, bool enabled = true);
+    bool isChecked(const QString& menuOption) const;
+    void setChecked(const QString& menuOption, bool isChecked = true);
+    void setCheckable(const QString& menuOption, bool checkable = true);
+    void setExclusiveGroup(const QString& menuOption, const QString & groupName);
+    void setText(const QString& menuOption, const QString& text);
+
+    void setRootMenu(QObject * rootMenu);
+
+private slots:
+    void onTriggeredByName(const QString& name);
+    void onToggledByName(const QString& name);
+
+protected:
+    QHash<QString, std::function<void()>> _triggerActions;
+    QHash<QString, std::function<void(bool)>> _toggleActions;
+    QObject* findMenuObject(const QString& name);
+    const QObject* findMenuObject(const QString& name) const;
+    QObject* _rootMenu{ nullptr };
+    QSignalMapper _triggerMapper;
+    QSignalMapper _toggleMapper;
+};
+
+#endif // hifi_MenuConstants_h
+
+
+
+
diff --git a/libraries/ui/src/MenuConstants.cpp b/libraries/ui/src/MenuConstants.cpp
deleted file mode 100644
index eeaf7b456b..0000000000
--- a/libraries/ui/src/MenuConstants.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "MenuConstants.h"
-#include <QtQml>
-
-QML_DIALOG_DEF(HifiMenu)
-
-static bool init = false;
-
-HifiMenu::HifiMenu(QQuickItem * parent) : QQuickItem(parent) {
-    this->setEnabled(false);
-    qWarning() << "Setting up connection";
-    connect(this, &HifiMenu::enabledChanged, this, [=]() {
-        if (init) {
-            return;
-        }
-        init = true;
-        foreach(QObject * action, findChildren<QObject*>(QRegularExpression(".*HifiAction"))) {
-            connect(action, SIGNAL(triggeredByName(QString)), this, SLOT(onTriggeredByName(QString)));
-            connect(action, SIGNAL(toggledByName(QString)), this, SLOT(onToggledByName(QString)));
-        }
-    });
-}
-
-void HifiMenu::onTriggeredByName(const QString & name) {
-    qDebug() << name << " triggered";
-    if (triggerActions.count(name)) {
-        triggerActions[name]();
-    }
-}
-
-void HifiMenu::onToggledByName(const QString & name) {
-    qDebug() << name << " toggled";
-    if (triggerActions.count(name)) {
-        if (toggleActions.count(name)) {
-            QObject * action = findChild<QObject*>(name + "HifiAction");
-            bool checked = action->property("checked").toBool();
-            toggleActions[name](checked);
-        }
-    }
-}
-
-QHash<QString, std::function<void()>> HifiMenu::triggerActions;
-QHash<QString, std::function<void(bool)>> HifiMenu::toggleActions;
-
-void HifiMenu::setToggleAction(const QString & name, std::function<void(bool)> f) {
-    toggleActions[name] = f;
-}
-
-void HifiMenu::setTriggerAction(const QString & name, std::function<void()> f) {
-    triggerActions[name] = f;
-}
diff --git a/libraries/ui/src/MenuConstants.h b/libraries/ui/src/MenuConstants.h
deleted file mode 100644
index e986410c5b..0000000000
--- a/libraries/ui/src/MenuConstants.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-//  MenuConstants.h
-//
-//  Created by Bradley Austin Davis on 2015/04/21
-//  Copyright 2015 High Fidelity, Inc.
-//
-//  Distributed under the Apache License, Version 2.0.
-//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#pragma once
-#ifndef hifi_MenuContants_h
-#define hifi_MenuConstants_h
-
-#include <QQuickItem>
-#include <QHash>
-#include <QList>
-#include "OffscreenQmlDialog.h"
-
-class HifiMenu : public QQuickItem
-{
-    Q_OBJECT
-    QML_DIALOG_DECL
-
-
-public:
-    HifiMenu(QQuickItem * parent = nullptr);
-    static void setToggleAction(const QString & name, std::function<void(bool)> f);
-    static void setTriggerAction(const QString & name, std::function<void()> f);
-private slots:
-    void onTriggeredByName(const QString & name);
-    void onToggledByName(const QString & name);
-private:
-    static QHash<QString, std::function<void()>> triggerActions;
-    static QHash<QString, std::function<void(bool)>> toggleActions;
-};
-
-#endif // hifi_MenuConstants_h
-
-
-
-
diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp
index d44a5dd282..7b84bb763f 100644
--- a/libraries/ui/src/OffscreenUi.cpp
+++ b/libraries/ui/src/OffscreenUi.cpp
@@ -15,6 +15,10 @@
 #include <QtQml>
 #include "MessageDialog.h"
 
+
+Q_DECLARE_LOGGING_CATEGORY(offscreenFocus)
+Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus")
+
 // Time between receiving a request to render the offscreen UI actually triggering
 // the render.  Could possibly be increased depending on the framerate we expect to
 // achieve.
@@ -93,10 +97,10 @@ void OffscreenUi::create(QOpenGLContext* shareContext) {
 
 #ifdef DEBUG
     connect(_quickWindow, &QQuickWindow::focusObjectChanged, [this]{
-        qDebug() << "New focus item " << _quickWindow->focusObject();
+        qCDebug(offscreenFocus) << "New focus item " << _quickWindow->focusObject();
     });
     connect(_quickWindow, &QQuickWindow::activeFocusItemChanged, [this] {
-        qDebug() << "New active focus item " << _quickWindow->activeFocusItem();
+        qCDebug(offscreenFocus) << "New active focus item " << _quickWindow->activeFocusItem();
     });
 #endif
 
diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h
index 33fb46b28a..b58b4e59cb 100644
--- a/libraries/ui/src/OffscreenUi.h
+++ b/libraries/ui/src/OffscreenUi.h
@@ -43,6 +43,17 @@ public: \
     static void load(std::function<void(QQmlContext*, QQuickItem *)> f = [](QQmlContext*, QQuickItem*) {}); \
 private:
 
+#define HIFI_QML_DECL_LAMBDA \
+protected: \
+    static const QString NAME; \
+    static const QUrl QML; \
+public: \
+    static void registerType(); \
+    static void show(); \
+    static void toggle(); \
+    static void load(); \
+private:
+
 #define HIFI_QML_DEF(x) \
     const QUrl x::QML = QUrl(#x ".qml"); \
     const QString x::NAME = #x; \
@@ -65,6 +76,25 @@ private:
         offscreenUi->load(QML, f); \
     } 
 
+#define HIFI_QML_DEF_LAMBDA(x, f) \
+    const QUrl x::QML = QUrl(#x ".qml"); \
+    const QString x::NAME = #x; \
+    \
+    void x::registerType() { \
+        qmlRegisterType<x>("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \
+    } \
+    void x::show() { \
+        auto offscreenUi = DependencyManager::get<OffscreenUi>(); \
+        offscreenUi->show(QML, NAME, f); \
+    } \
+    void x::toggle() { \
+        auto offscreenUi = DependencyManager::get<OffscreenUi>(); \
+        offscreenUi->toggle(QML, NAME, f); \
+    } \
+    void x::load() { \
+        auto offscreenUi = DependencyManager::get<OffscreenUi>(); \
+        offscreenUi->load(QML, f); \
+    } 
 
 class OffscreenUi : public OffscreenGlCanvas, public Dependency {
     Q_OBJECT
diff --git a/tests/ui/src/main.cpp b/tests/ui/src/main.cpp
index e84e5674c1..4189282de1 100644
--- a/tests/ui/src/main.cpp
+++ b/tests/ui/src/main.cpp
@@ -34,7 +34,7 @@
 #include <QDir>
 
 #include "MessageDialog.h"
-#include "MenuConstants.h"
+#include "HifiMenu.h"
 
 class RateCounter {
     std::vector<float> times;
@@ -181,11 +181,25 @@ public:
         offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir()));
         offscreenUi->load(QUrl("TestRoot.qml"));
         offscreenUi->load(QUrl("RootMenu.qml"));
+        HifiMenu::load();
+        QObject* menuObject = offscreenUi->getRootItem()->findChild<QObject*>("HifiMenu");
+        HifiMenu* menu = offscreenUi->getRootItem()->findChild<HifiMenu*>(); 
+        menu->addMenu("", "File");
+        menu->addMenuItem("File", "Quit", []{
+            QApplication::quit();
+        });
+        menu->addCheckableMenuItem("File", "Toggle", false, [](bool toggled) {
+            qDebug() << "Toggle is " << toggled;
+        });
+        menu->addMenu("", "Edit");
+        menu->addMenuItem("Edit", "Undo");
+        menu->addMenuItem("Edit", "Redo");
+        menu->addMenuItem("Edit", "Copy");
+        menu->addMenuItem("Edit", "Cut");
+        menu->addMenuItem("Edit", "Paste");
+        menu->addMenu("", "Long Menu Name...");
 #endif
         installEventFilter(offscreenUi.data());
-        //HifiMenu::setTriggerAction(MenuOption::Quit, [] {
-        //    QApplication::quit();
-        //});
         offscreenUi->resume();
         _timer.start();
     }
@@ -233,30 +247,16 @@ protected:
         resizeWindow(ev->size());
     }
 
-
-    static QObject * addMenu(QObject * parent, const QString & text) {
-        // FIXME add more checking here to ensure no name conflicts
-        QVariant returnedValue;
-        QMetaObject::invokeMethod(parent, "addMenu",
-            Q_RETURN_ARG(QVariant, returnedValue),
-            Q_ARG(QVariant, text));
-        QObject * result = returnedValue.value<QObject*>();
-        return result;
-    }
-
+  
     void keyPressEvent(QKeyEvent *event) {
         _altPressed = Qt::Key_Alt == event->key();
         switch (event->key()) {
         case Qt::Key_L:
             if (event->modifiers() & Qt::CTRL) {
                 auto offscreenUi = DependencyManager::get<OffscreenUi>();
-                rootMenu = offscreenUi->getRootItem()->findChild<QObject*>("rootMenu");
-                QObject * result = addMenu(rootMenu, "Test 3");
-                result->setParent(rootMenu);
-                qDebug() << "Added " << result;
-                if (menuContext) {
-                    menuContext->setContextProperty("rootMenu", rootMenu);
-                }
+                HifiMenu * menu = offscreenUi->findChild<HifiMenu*>();
+                menu->addMenuItem("", "Test 3");
+                menu->addMenuItem("File", "Test 3");
             }
             break;
         case Qt::Key_K:
@@ -279,12 +279,7 @@ protected:
     QQmlContext* menuContext{ nullptr };
     void keyReleaseEvent(QKeyEvent *event) {
         if (_altPressed && Qt::Key_Alt == event->key()) {
-            HifiMenu::toggle([=](QQmlContext* context, QObject* newItem) {
-                auto offscreenUi = DependencyManager::get<OffscreenUi>();
-                rootMenu = offscreenUi->getRootItem()->findChild<QObject*>("rootMenu");
-                menuContext = context;
-                menuContext->setContextProperty("rootMenu", rootMenu);
-            });
+            HifiMenu::toggle();
         }
     }
 
@@ -327,13 +322,12 @@ void QTestWindow::renderQml() {
 
 const char * LOG_FILTER_RULES = R"V0G0N(
 *.debug=false
-qt.quick.dialogs.registration=true
-qt.quick.mouse.debug = true
+qt.quick.mouse.debug=false
 )V0G0N";
 
 int main(int argc, char** argv) {    
     QGuiApplication app(argc, argv);
-    //QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
+//    QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
     QTestWindow window;
     app.exec();
     return 0;