From c99f897db1eb1ecd098ee03e95369b2417f88206 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 4 Jan 2017 23:47:18 +0000 Subject: [PATCH 1/5] first commit --- .../src/TabletScriptingInterface.cpp | 17 +++++++++++++++++ .../src/TabletScriptingInterface.h | 3 +++ scripts/system/libraries/WebTablet.js | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index 056d946482..3b5c292f26 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -14,6 +14,8 @@ #include #include #include "ScriptEngineLogging.h" +#include "DependencyManager.h" +#include "OffscreenUi.h" TabletScriptingInterface::TabletScriptingInterface() { qmlRegisterType("Hifi", 1, 0, "SoundEffect"); @@ -56,6 +58,7 @@ void TabletScriptingInterface::setQmlTabletRoot(QString tabletId, QQuickItem* qm static const char* TABLET_SOURCE_URL = "Tablet.qml"; static const char* WEB_VIEW_SOURCE_URL = "TabletWebView.qml"; static const char* LOADER_SOURCE_PROPERTY_NAME = "LoaderSource"; +static const char* VRMENU_SOURCE_URL = "VrMenuView.qml"; TabletProxy::TabletProxy(QString name) : _name(name) { ; @@ -95,6 +98,16 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr } } +void TabletProxy::gotoMenuScreen() { + if (_qmlTabletRoot) { + _qmlTabletRoot->setProperty(LOADER_SOURCE_PROPERTY_NAME, TABLET_SOURCE_URL); + auto loader = _qmlTabletRoot->findChild("loader"); + auto offscreenUi = DependencyManager::get(); + auto rootMenu = offscreenUi->getRootMenu(); + QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL))); + } +} + void TabletProxy::gotoHomeScreen() { if (_qmlTabletRoot) { QString tabletSource = _qmlTabletRoot->property(LOADER_SOURCE_PROPERTY_NAME).toString(); @@ -186,6 +199,10 @@ void TabletProxy::addButtonsToHomeScreen() { QObject::disconnect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen())); } +void TabletProxy::addButtonsToMenuScreen() { + +} + void TabletProxy::removeButtonsFromHomeScreen() { auto tabletScriptingInterface = DependencyManager::get(); for (auto& buttonProxy : _tabletButtonProxies) { diff --git a/libraries/script-engine/src/TabletScriptingInterface.h b/libraries/script-engine/src/TabletScriptingInterface.h index 43750e2519..f49c9ea498 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.h +++ b/libraries/script-engine/src/TabletScriptingInterface.h @@ -65,6 +65,8 @@ public: void setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface); + Q_INVOKABLE void gotoMenuScreen(); + /**jsdoc * transition to the home screen * @function TabletProxy#gotoHomeScreen @@ -120,6 +122,7 @@ signals: private slots: void addButtonsToHomeScreen(); + void addButtonsToMenuScreen(); protected: void removeButtonsFromHomeScreen(); QQuickItem* getQmlTablet() const; diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index beb54ae3fa..12f655554e 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -118,7 +118,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { _this.clicked = true; } var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - tablet.gotoHomeScreen(); + tablet.gotoMenuScreen(); } }; From 3fab901b495f30644cfd951e7e8f8bc9a7bf5af8 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 5 Jan 2017 17:58:42 +0000 Subject: [PATCH 2/5] commit chabges --- .../resources/qml/hifi/tablet/TabletMenu.qml | 12 +++++++++ .../src/TabletScriptingInterface.cpp | 25 +++++++++++++++---- 2 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 interface/resources/qml/hifi/tablet/TabletMenu.qml diff --git a/interface/resources/qml/hifi/tablet/TabletMenu.qml b/interface/resources/qml/hifi/tablet/TabletMenu.qml new file mode 100644 index 0000000000..00227a6312 --- /dev/null +++ b/interface/resources/qml/hifi/tablet/TabletMenu.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 +import QtGraphicalEffects 1.0 +"../../menus" +Item { + id: tabletMenu + objectName: "menu" + property var rootMenu: Menu { objectName: "rootMenu" } + + Rectangle { + color: "#2b2b2b" + } +} diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index 3b5c292f26..f740a508a9 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -58,7 +58,7 @@ void TabletScriptingInterface::setQmlTabletRoot(QString tabletId, QQuickItem* qm static const char* TABLET_SOURCE_URL = "Tablet.qml"; static const char* WEB_VIEW_SOURCE_URL = "TabletWebView.qml"; static const char* LOADER_SOURCE_PROPERTY_NAME = "LoaderSource"; -static const char* VRMENU_SOURCE_URL = "VrMenuView.qml"; +static const char* VRMENU_SOURCE_URL = "TabletMenu.qml"; TabletProxy::TabletProxy(QString name) : _name(name) { ; @@ -101,9 +101,8 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr void TabletProxy::gotoMenuScreen() { if (_qmlTabletRoot) { _qmlTabletRoot->setProperty(LOADER_SOURCE_PROPERTY_NAME, TABLET_SOURCE_URL); - auto loader = _qmlTabletRoot->findChild("loader"); - auto offscreenUi = DependencyManager::get(); - auto rootMenu = offscreenUi->getRootMenu(); + //auto loader = _qmlTabletRoot->findChild("loader"); + //QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen())); QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL))); } } @@ -200,7 +199,23 @@ void TabletProxy::addButtonsToHomeScreen() { } void TabletProxy::addButtonsToMenuScreen() { - + if (!_qmlTabletRoot) { + return; + } + + auto loader = _qmlTabletRoot->findChild("loader"); + if (!loader) { + return; + } + + QQuickItem* VrMenu = loader->findChild("VrMenu"); + if (!VrMenu) { + qDebug() << "----------> could not find vr menu"; + return; + } + + QString name = "Menu"; + QVariant returnedValue; } void TabletProxy::removeButtonsFromHomeScreen() { From 6c51edec7764381a1017194c97aed57814416057 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 6 Jan 2017 22:29:07 +0000 Subject: [PATCH 3/5] added context menu to tablet --- .../resources/qml/hifi/tablet/TabletMenu.qml | 27 ++- .../qml/hifi/tablet/TabletMenuItem.qml | 113 ++++++++++++ .../qml/hifi/tablet/TabletMenuView.qml | 117 +++++++++++++ .../qml/hifi/tablet/TabletMouseHandler.qml | 163 ++++++++++++++++++ .../src/TabletScriptingInterface.cpp | 15 +- libraries/ui/src/OffscreenUi.cpp | 4 + libraries/ui/src/OffscreenUi.h | 4 +- scripts/defaultScripts.js | 3 +- scripts/system/menu.js | 30 ++++ 9 files changed, 460 insertions(+), 16 deletions(-) create mode 100644 interface/resources/qml/hifi/tablet/TabletMenuItem.qml create mode 100644 interface/resources/qml/hifi/tablet/TabletMenuView.qml create mode 100644 interface/resources/qml/hifi/tablet/TabletMouseHandler.qml create mode 100644 scripts/system/menu.js diff --git a/interface/resources/qml/hifi/tablet/TabletMenu.qml b/interface/resources/qml/hifi/tablet/TabletMenu.qml index 00227a6312..36de421a78 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenu.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenu.qml @@ -1,12 +1,27 @@ -import QtQuick 2.0 +import QtQuick 2.5 import QtGraphicalEffects 1.0 -"../../menus" +import QtQuick.Controls 1.4 +import QtQml 2.2 +import "." + + Item { id: tabletMenu - objectName: "menu" - property var rootMenu: Menu { objectName: "rootMenu" } + objectName: "tabletMenu" - Rectangle { - color: "#2b2b2b" + width: parent.width + height: parent.height + + property var rootMenu: Menu { objectName:"rootMenu" } + property var point: Qt.point(50, 50) + + TabletMouseHandler { id: menuPopperUpper } + + function setRootMenu(menu) { + tabletMenu.rootMenu = menu + buildMenu() + } + function buildMenu() { + menuPopperUpper.popup(tabletMenu, rootMenu.items) } } diff --git a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml new file mode 100644 index 0000000000..ce45ca7065 --- /dev/null +++ b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml @@ -0,0 +1,113 @@ +// +// VrMenuItem.qml +// +// Created by Bradley Austin Davis on 29 Apr 2015 +// 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 +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import "../../controls-uit" +import "../../styles-uit" + +Item { + id: root + HifiConstants { id: hifi } + property alias text: label.text + property var source + + implicitHeight: source.visible ? 2 * label.implicitHeight : 0 + implicitWidth: 2 * hifi.dimensions.menuPadding.x + check.width + label.width + tail.width + visible: source.visible + width: parent.width + + CheckBox { + id: check + // FIXME: Should use radio buttons if source.exclusiveGroup. + anchors { + left: parent.left + leftMargin: hifi.dimensions.menuPadding.x + top: label.top + topMargin: 0 + } + width: 20 + visible: source.visible && source.type === 1 && source.checkable + checked: setChecked() + function setChecked() { + if (!source || source.type !== 1 || !source.checkable) { + return false; + } + // FIXME this works for native QML menus but I don't think it will + // for proxied QML menus + return source.checked; + } + } + + RalewaySemiBold { + id: label + size: hifi.fontSizes.rootMenu + font.capitalization: isSubMenu ? Font.MixedCase : Font.AllUppercase + anchors.left: check.right + anchors.verticalCenter: parent.verticalCenter + verticalAlignment: Text.AlignVCenter + color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow50 + enabled: source.visible && (source.type !== 0 ? source.enabled : false) + visible: source.visible + } + + Item { + id: separator + anchors { + fill: parent + leftMargin: hifi.dimensions.menuPadding.x + check.width + rightMargin: hifi.dimensions.menuPadding.x + tail.width + } + visible: source.type === MenuItemType.Separator + + Rectangle { + anchors { + left: parent.left + right: parent.right + verticalCenter: parent.verticalCenter + } + height: 1 + color: hifi.colors.lightGray50 + } + } + + Item { + id: tail + width: 48 + (shortcut.visible ? shortcut.width : 0) + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: hifi.dimensions.menuPadding.x + } + + RalewayLight { + id: shortcut + text: source.shortcut ? source.shortcut : "" + size: hifi.fontSizes.shortcutText + color: hifi.colors.baseGrayShadow + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 15 + visible: source.visible && text != "" + } + + HiFiGlyphs { + text: hifi.glyphs.disclosureExpand + color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow25 + size: 2 * hifi.fontSizes.rootMenuDisclosure + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + horizontalAlignment: Text.AlignRight + visible: source.visible && (source.type === 2) + } + } +} diff --git a/interface/resources/qml/hifi/tablet/TabletMenuView.qml b/interface/resources/qml/hifi/tablet/TabletMenuView.qml new file mode 100644 index 0000000000..b3a6bcf811 --- /dev/null +++ b/interface/resources/qml/hifi/tablet/TabletMenuView.qml @@ -0,0 +1,117 @@ +// +// VrMenuView.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 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 +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 + +import "../../styles-uit" + +FocusScope { + id: root + implicitHeight: background.height + implicitWidth: background.width + + property alias currentItem: listView.currentItem + property alias model: listView.model + property bool isSubMenu: false + signal selected(var item) + + HifiConstants { id: hifi } + + Rectangle { + id: background + anchors.fill: listView + radius: hifi.dimensions.borderRadius + border.width: hifi.dimensions.borderWidth + border.color: hifi.colors.lightGrayText80 + color: isSubMenu ? hifi.colors.faintGray : hifi.colors.faintGray80 + } + + ListView { + id: listView + x: 8; y: 8 + width: parent.width + height: parent.height + topMargin: hifi.dimensions.menuPadding.y + onEnabledChanged: recalcSize(); + onVisibleChanged: recalcSize(); + onCountChanged: recalcSize(); + focus: true + highlightMoveDuration: 0 + + highlight: Rectangle { + anchors { + left: parent ? parent.left : undefined + right: parent ? parent.right : undefined + leftMargin: hifi.dimensions.borderWidth + rightMargin: hifi.dimensions.borderWidth + } + color: hifi.colors.white + } + + delegate: TabletMenuItem { + text: name + source: item + onImplicitHeightChanged: listView.recalcSize() + onImplicitWidthChanged: listView.recalcSize() + + MouseArea { + anchors.fill: parent + hoverEnabled: true + onEntered: listView.currentIndex = index + onClicked: root.selected(item) + } + } + + function recalcSize() { + if (model.count !== count || !visible) { + return; + } + + var originalIndex = currentIndex; + var maxWidth = width; + var newHeight = 0; + for (var i = 0; i < count; ++i) { + currentIndex = i; + if (!currentItem) { + continue; + } + if (currentItem && currentItem.implicitWidth > maxWidth) { + maxWidth = currentItem.implicitWidth + } + if (currentItem.visible) { + newHeight += currentItem.implicitHeight + } + } + newHeight += 2 * hifi.dimensions.menuPadding.y; // White space at top and bottom. + if (maxWidth > width) { + width = maxWidth; + } + if (newHeight > height) { + height = newHeight + } + currentIndex = originalIndex; + } + + function previousItem() { currentIndex = (currentIndex + count - 1) % count; } + function nextItem() { currentIndex = (currentIndex + count + 1) % count; } + function selectCurrentItem() { if (currentIndex != -1) root.selected(currentItem.source); } + + Keys.onUpPressed: previousItem(); + Keys.onDownPressed: nextItem(); + Keys.onSpacePressed: selectCurrentItem(); + Keys.onRightPressed: selectCurrentItem(); + Keys.onReturnPressed: selectCurrentItem(); + } +} + + + diff --git a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml new file mode 100644 index 0000000000..db74de82fb --- /dev/null +++ b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml @@ -0,0 +1,163 @@ +// +// MessageDialog.qml +// +// Created by Bradley Austin Davis on 18 Jan 2016 +// Copyright 2016 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 +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +import "." + +Item { + id: root + anchors.fill: parent + objectName: "tabletMenuHandlerItem" + + MouseArea { + id: menuRoot; + objectName: "tabletMenuHandlerMouseArea" + anchors.fill: parent + enabled: d.topMenu !== null + onClicked: { + d.clearMenus(); + } + } + + QtObject { + id: d + property var menuStack: [] + property var topMenu: null; + property var modelMaker: Component { ListModel { } } + property var menuViewMaker: Component { + TabletMenuView { + id: subMenu + onSelected: d.handleSelection(subMenu, currentItem, item) + } + } + property var delay: Timer { // No setTimeout in QML. + property var menuItem: null; + interval: 0 + repeat: false + running: false + function trigger(item) { // Capture item and schedule asynchronous Timer. + menuItem = item; + start(); + } + onTriggered: { + menuItem.trigger(); // Now trigger the item. + } + } + + function toModel(items) { + var result = modelMaker.createObject(tabletMenu); + for (var i = 0; i < items.length; ++i) { + var item = items[i]; + if (!item.visible) continue; + console.log(item.title) + switch (item.type) { + case MenuItemType.Menu: + result.append({"name": item.title, "item": item}) + break; + case MenuItemType.Item: + result.append({"name": item.text, "item": item}) + break; + case MenuItemType.Separator: + result.append({"name": "", "item": item}) + break; + } + } + return result; + } + + function popMenu() { + if (menuStack.length) { + menuStack.pop().destroy(); + } + if (menuStack.length) { + topMenu = menuStack[menuStack.length - 1]; + topMenu.focus = true; + } else { + topMenu = null; + //offscreenFlags.navigationFocused = false; + menuRoot.enabled = false; + } + } + + function pushMenu(newMenu) { + menuStack.push(newMenu); + topMenu = newMenu; + topMenu.focus = true; + //offscreenFlags.navigationFocused = true; + } + + function clearMenus() { + while (menuStack.length) { + popMenu() + } + } + + function clampMenuPosition(menu) { + var margins = 0; + if (menu.x < margins) { + menu.x = margins + } else if ((menu.x + menu.width + margins) > root.width) { + menu.x = root.width - (menu.width + margins); + } + + if (menu.y < 0) { + menu.y = margins + } else if ((menu.y + menu.height + margins) > root.height) { + menu.y = root.height - (menu.height + margins); + } + } + + function buildMenu(items, targetPosition) { + var model = toModel(items); + // Menus must be childed to desktop for Z-ordering + var newMenu = menuViewMaker.createObject(tabletMenu, { model: model, isSubMenu: topMenu !== null }); + pushMenu(newMenu); + return newMenu; + } + + function handleSelection(parentMenu, selectedItem, item) { + while (topMenu && topMenu !== parentMenu) { + popMenu(); + } + + switch (item.type) { + case MenuItemType.Menu: + var target = Qt.vector2d(topMenu.x, topMenu.y).plus(Qt.vector2d(selectedItem.x + 96, selectedItem.y)); + buildMenu(item.items, target).objectName = item.title; + break; + + case MenuItemType.Item: + console.log("Triggering " + item.text) + // Don't block waiting for modal dialogs and such that the menu might open. + delay.trigger(item); + clearMenus(); + break; + } + } + + } + + function popup(parent, items) { + d.clearMenus(); + menuRoot.enabled = true; + d.buildMenu(items, point); + } + + function closeLastMenu() { + if (d.menuStack.length) { + d.popMenu(); + return true; + } + return false; + } + +} diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index f740a508a9..45635d0cbb 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -100,9 +100,9 @@ void TabletProxy::setQmlTabletRoot(QQuickItem* qmlTabletRoot, QObject* qmlOffscr void TabletProxy::gotoMenuScreen() { if (_qmlTabletRoot) { - _qmlTabletRoot->setProperty(LOADER_SOURCE_PROPERTY_NAME, TABLET_SOURCE_URL); - //auto loader = _qmlTabletRoot->findChild("loader"); - //QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen())); + _qmlTabletRoot->setProperty(LOADER_SOURCE_PROPERTY_NAME, VRMENU_SOURCE_URL); + auto loader = _qmlTabletRoot->findChild("loader"); + QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen())); QMetaObject::invokeMethod(_qmlTabletRoot, "loadSource", Q_ARG(const QVariant&, QVariant(VRMENU_SOURCE_URL))); } } @@ -172,7 +172,7 @@ void TabletProxy::removeButton(QObject* tabletButtonProxy) { void TabletProxy::updateAudioBar(const double micLevel) { auto tablet = getQmlTablet(); if (!tablet) { - qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml"; + //qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml"; } else { QMetaObject::invokeMethod(tablet, "setMicLevel", Qt::AutoConnection, Q_ARG(QVariant, QVariant(micLevel))); } @@ -208,14 +208,15 @@ void TabletProxy::addButtonsToMenuScreen() { return; } - QQuickItem* VrMenu = loader->findChild("VrMenu"); + QQuickItem* VrMenu = loader->findChild("tabletMenu"); if (!VrMenu) { qDebug() << "----------> could not find vr menu"; return; } - QString name = "Menu"; - QVariant returnedValue; + auto offscreenUi = DependencyManager::get(); + QObject* menu = offscreenUi->getRootMenu(); + QMetaObject::invokeMethod(VrMenu, "setRootMenu", Qt::AutoConnection, Q_ARG(QVariant, QVariant::fromValue(menu))); } void TabletProxy::removeButtonsFromHomeScreen() { diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 60d80c6b35..3e14d97d40 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -524,6 +524,10 @@ QQuickItem* OffscreenUi::getDesktop() { return _desktop; } +QObject* OffscreenUi::getRootMenu() { + return getRootItem()->findChild("rootMenu"); +} + QQuickItem* OffscreenUi::getToolWindow() { return _toolWindow; } diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index 3ab4fa0758..409b70ea3a 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -50,7 +50,7 @@ public: // Setting pinned to true will hide all overlay elements on the desktop that don't have a pinned flag void setPinned(bool pinned = true); - + void togglePinned(); void setConstrainToolbarToCenterX(bool constrained); @@ -59,7 +59,7 @@ public: QObject* getFlags(); QQuickItem* getDesktop(); QQuickItem* getToolWindow(); - + QObject* getRootMenu(); enum Icon { ICON_NONE = 0, ICON_QUESTION, diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 61461c7f06..bd3131f4ff 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -35,7 +35,8 @@ var DEFAULT_SCRIPTS = [ "system/snapshot.js", "system/help.js", "system/bubble.js", - "system/tablet-ui/tabletUI.js" + "system/tablet-ui/tabletUI.js", + "system/menu.js" ]; // add a menu item for debugging diff --git a/scripts/system/menu.js b/scripts/system/menu.js new file mode 100644 index 0000000000..94097271bf --- /dev/null +++ b/scripts/system/menu.js @@ -0,0 +1,30 @@ +// +// menu.js +// scripts/system/ +// +// Created by Dante Ruiz on 5 Jun 2017 +// Copyright 2016 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 +// + +(function() { + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var button = tablet.addButton({ + icon: "icons/tablet-icons/menu-i.svg", + text: "Menu" + }); + + + function onClicked() { + tablet.gotoMenuScreen(); + } + + button.clicked.connect(onClicked); + + Script.scriptEnding.connect(function () { + button.clicked.disconnect(onClicked); + tablet.removeButton(button); + }) +}()); \ No newline at end of file From 670584651852a68e93e03d151684795937229c7f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 6 Jan 2017 23:25:25 +0000 Subject: [PATCH 4/5] clean up round 1 --- interface/resources/qml/desktop/Desktop.qml | 27 +-------------------- libraries/ui/src/OffscreenUi.cpp | 2 -- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index 66b59f0aea..c536020122 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -465,32 +465,7 @@ FocusScope { Component { id: fileDialogBuilder; FileDialog { } } function fileDialog(properties) { return fileDialogBuilder.createObject(desktop, properties); - } - - MenuMouseHandler { id: menuPopperUpper } - function popupMenu(point) { - menuPopperUpper.popup(desktop, rootMenu.items, point); - } - - function toggleMenu(point) { - menuPopperUpper.toggle(desktop, rootMenu.items, point); - } - - Keys.onEscapePressed: { - if (menuPopperUpper.closeLastMenu()) { - event.accepted = true; - return; - } - event.accepted = false; - } - - Keys.onLeftPressed: { - if (menuPopperUpper.closeLastMenu()) { - event.accepted = true; - return; - } - event.accepted = false; - } + } function unfocusWindows() { // First find the active focus item, and unfocus it, all the way diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 3e14d97d40..1814d30c0a 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -538,8 +538,6 @@ void OffscreenUi::unfocusWindows() { } void OffscreenUi::toggleMenu(const QPoint& screenPosition) { // caller should already have mapped using getReticlePosition - emit showDesktop(); // we really only want to do this if you're showing the menu, but for now this works - QMetaObject::invokeMethod(_desktop, "toggleMenu", Q_ARG(QVariant, screenPosition)); } From 2fc76d64fd6becb75bcecb1bf35f8ae71c770524 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 10 Jan 2017 16:31:55 +0000 Subject: [PATCH 5/5] clean up unused code and files --- interface/resources/qml/desktop/Desktop.qml | 1 - .../resources/qml/menus/MenuMouseHandler.qml | 175 ------------------ interface/resources/qml/menus/VrMenuItem.qml | 113 ----------- interface/resources/qml/menus/VrMenuView.qml | 117 ------------ interface/src/Application.cpp | 19 -- interface/src/Application.h | 1 - libraries/ui/src/OffscreenUi.cpp | 3 - libraries/ui/src/OffscreenUi.h | 1 - scripts/system/libraries/WebTablet.js | 2 +- 9 files changed, 1 insertion(+), 431 deletions(-) delete mode 100644 interface/resources/qml/menus/MenuMouseHandler.qml delete mode 100644 interface/resources/qml/menus/VrMenuItem.qml delete mode 100644 interface/resources/qml/menus/VrMenuView.qml diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index c536020122..cc64d0f2b4 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -12,7 +12,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import "../dialogs" -import "../menus" import "../js/Utils.js" as Utils // This is our primary 'desktop' object to which all VR dialogs and windows are childed. diff --git a/interface/resources/qml/menus/MenuMouseHandler.qml b/interface/resources/qml/menus/MenuMouseHandler.qml deleted file mode 100644 index 48574d41e5..0000000000 --- a/interface/resources/qml/menus/MenuMouseHandler.qml +++ /dev/null @@ -1,175 +0,0 @@ -// -// MessageDialog.qml -// -// Created by Bradley Austin Davis on 18 Jan 2016 -// Copyright 2016 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 -// - -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -import "." - -Item { - id: root - anchors.fill: parent - objectName: "MouseMenuHandlerItem" - - MouseArea { - id: menuRoot; - objectName: "MouseMenuHandlerMouseArea" - anchors.fill: parent - enabled: d.topMenu !== null - onClicked: { - d.clearMenus(); - } - } - - QtObject { - id: d - property var menuStack: [] - property var topMenu: null; - property var modelMaker: Component { ListModel { } } - property var menuViewMaker: Component { - VrMenuView { - id: subMenu - onSelected: d.handleSelection(subMenu, currentItem, item) - } - } - property var delay: Timer { // No setTimeout in QML. - property var menuItem: null; - interval: 0 - repeat: false - running: false - function trigger(item) { // Capture item and schedule asynchronous Timer. - menuItem = item; - start(); - } - onTriggered: { - menuItem.trigger(); // Now trigger the item. - } - } - - function toModel(items) { - var result = modelMaker.createObject(desktop); - for (var i = 0; i < items.length; ++i) { - var item = items[i]; - if (!item.visible) continue; - switch (item.type) { - case MenuItemType.Menu: - result.append({"name": item.title, "item": item}) - break; - case MenuItemType.Item: - result.append({"name": item.text, "item": item}) - break; - case MenuItemType.Separator: - result.append({"name": "", "item": item}) - break; - } - } - return result; - } - - function popMenu() { - if (menuStack.length) { - menuStack.pop().destroy(); - } - if (menuStack.length) { - topMenu = menuStack[menuStack.length - 1]; - topMenu.focus = true; - } else { - topMenu = null; - offscreenFlags.navigationFocused = false; - menuRoot.enabled = false; - } - } - - function pushMenu(newMenu) { - menuStack.push(newMenu); - topMenu = newMenu; - topMenu.focus = true; - offscreenFlags.navigationFocused = true; - } - - function clearMenus() { - while (menuStack.length) { - popMenu() - } - } - - function clampMenuPosition(menu) { - var margins = 0; - if (menu.x < margins) { - menu.x = margins - } else if ((menu.x + menu.width + margins) > root.width) { - menu.x = root.width - (menu.width + margins); - } - - if (menu.y < 0) { - menu.y = margins - } else if ((menu.y + menu.height + margins) > root.height) { - menu.y = root.height - (menu.height + margins); - } - } - - function buildMenu(items, targetPosition) { - var model = toModel(items); - // Menus must be childed to desktop for Z-ordering - var newMenu = menuViewMaker.createObject(desktop, { model: model, z: topMenu ? topMenu.z + 1 : desktop.zLevels.menu, isSubMenu: topMenu !== null }); - if (targetPosition) { - newMenu.x = targetPosition.x - newMenu.y = targetPosition.y - newMenu.height / 3 * 1 - } - clampMenuPosition(newMenu); - pushMenu(newMenu); - return newMenu; - } - - function handleSelection(parentMenu, selectedItem, item) { - while (topMenu && topMenu !== parentMenu) { - popMenu(); - } - - switch (item.type) { - case MenuItemType.Menu: - var target = Qt.vector2d(topMenu.x, topMenu.y).plus(Qt.vector2d(selectedItem.x + 96, selectedItem.y)); - buildMenu(item.items, target).objectName = item.title; - break; - - case MenuItemType.Item: - console.log("Triggering " + item.text) - // Don't block waiting for modal dialogs and such that the menu might open. - delay.trigger(item); - clearMenus(); - break; - } - } - - } - - function popup(parent, items, point) { - d.clearMenus(); - menuRoot.enabled = true; - d.buildMenu(items, point); - } - - function toggle(parent, items, point) { - if (d.topMenu) { - d.clearMenus(); - return; - } - popup(parent, items, point); - } - - function closeLastMenu() { - if (d.menuStack.length) { - d.popMenu(); - return true; - } - return false; - } - -} diff --git a/interface/resources/qml/menus/VrMenuItem.qml b/interface/resources/qml/menus/VrMenuItem.qml deleted file mode 100644 index 38d2b57c03..0000000000 --- a/interface/resources/qml/menus/VrMenuItem.qml +++ /dev/null @@ -1,113 +0,0 @@ -// -// VrMenuItem.qml -// -// Created by Bradley Austin Davis on 29 Apr 2015 -// 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 -// - -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -import "../controls-uit" -import "../styles-uit" - -Item { - id: root - HifiConstants { id: hifi } - property alias text: label.text - property var source - - implicitHeight: source.visible ? 2 * label.implicitHeight : 0 - implicitWidth: 2 * hifi.dimensions.menuPadding.x + check.width + label.width + tail.width - visible: source.visible - width: parent.width - - CheckBox { - id: check - // FIXME: Should use radio buttons if source.exclusiveGroup. - anchors { - left: parent.left - leftMargin: hifi.dimensions.menuPadding.x - top: label.top - topMargin: 0 - } - width: 20 - visible: source.visible && source.type === 1 && source.checkable - checked: setChecked() - function setChecked() { - if (!source || source.type !== 1 || !source.checkable) { - return false; - } - // FIXME this works for native QML menus but I don't think it will - // for proxied QML menus - return source.checked; - } - } - - RalewaySemiBold { - id: label - size: hifi.fontSizes.rootMenu - font.capitalization: isSubMenu ? Font.MixedCase : Font.AllUppercase - anchors.left: check.right - anchors.verticalCenter: parent.verticalCenter - verticalAlignment: Text.AlignVCenter - color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow50 - enabled: source.visible && (source.type !== 0 ? source.enabled : false) - visible: source.visible - } - - Item { - id: separator - anchors { - fill: parent - leftMargin: hifi.dimensions.menuPadding.x + check.width - rightMargin: hifi.dimensions.menuPadding.x + tail.width - } - visible: source.type === MenuItemType.Separator - - Rectangle { - anchors { - left: parent.left - right: parent.right - verticalCenter: parent.verticalCenter - } - height: 1 - color: hifi.colors.lightGray50 - } - } - - Item { - id: tail - width: 48 + (shortcut.visible ? shortcut.width : 0) - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - rightMargin: hifi.dimensions.menuPadding.x - } - - RalewayLight { - id: shortcut - text: source.shortcut ? source.shortcut : "" - size: hifi.fontSizes.shortcutText - color: hifi.colors.baseGrayShadow - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - anchors.rightMargin: 15 - visible: source.visible && text != "" - } - - HiFiGlyphs { - text: hifi.glyphs.disclosureExpand - color: source.enabled ? hifi.colors.baseGrayShadow : hifi.colors.baseGrayShadow25 - size: 2 * hifi.fontSizes.rootMenuDisclosure - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - horizontalAlignment: Text.AlignRight - visible: source.visible && (source.type === 2) - } - } -} diff --git a/interface/resources/qml/menus/VrMenuView.qml b/interface/resources/qml/menus/VrMenuView.qml deleted file mode 100644 index 5db13fc160..0000000000 --- a/interface/resources/qml/menus/VrMenuView.qml +++ /dev/null @@ -1,117 +0,0 @@ -// -// VrMenuView.qml -// -// Created by Bradley Austin Davis on 18 Jan 2016 -// Copyright 2016 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 -// - -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -import "../styles-uit" - -FocusScope { - id: root - implicitHeight: background.height - implicitWidth: background.width - - property alias currentItem: listView.currentItem - property alias model: listView.model - property bool isSubMenu: false - signal selected(var item) - - HifiConstants { id: hifi } - - Rectangle { - id: background - anchors.fill: listView - radius: hifi.dimensions.borderRadius - border.width: hifi.dimensions.borderWidth - border.color: hifi.colors.lightGrayText80 - color: isSubMenu ? hifi.colors.faintGray : hifi.colors.faintGray80 - } - - ListView { - id: listView - x: 8; y: 8 - width: 128 - height: count * 32 - topMargin: hifi.dimensions.menuPadding.y - onEnabledChanged: recalcSize(); - onVisibleChanged: recalcSize(); - onCountChanged: recalcSize(); - focus: true - highlightMoveDuration: 0 - - highlight: Rectangle { - anchors { - left: parent ? parent.left : undefined - right: parent ? parent.right : undefined - leftMargin: hifi.dimensions.borderWidth - rightMargin: hifi.dimensions.borderWidth - } - color: hifi.colors.white - } - - delegate: VrMenuItem { - text: name - source: item - onImplicitHeightChanged: listView.recalcSize() - onImplicitWidthChanged: listView.recalcSize() - - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: listView.currentIndex = index - onClicked: root.selected(item) - } - } - - function recalcSize() { - if (model.count !== count || !visible) { - return; - } - - var originalIndex = currentIndex; - var maxWidth = width; - var newHeight = 0; - for (var i = 0; i < count; ++i) { - currentIndex = i; - if (!currentItem) { - continue; - } - if (currentItem && currentItem.implicitWidth > maxWidth) { - maxWidth = currentItem.implicitWidth - } - if (currentItem.visible) { - newHeight += currentItem.implicitHeight - } - } - newHeight += 2 * hifi.dimensions.menuPadding.y; // White space at top and bottom. - if (maxWidth > width) { - width = maxWidth; - } - if (newHeight > height) { - height = newHeight - } - currentIndex = originalIndex; - } - - function previousItem() { currentIndex = (currentIndex + count - 1) % count; } - function nextItem() { currentIndex = (currentIndex + count + 1) % count; } - function selectCurrentItem() { if (currentIndex != -1) root.selected(currentItem.source); } - - Keys.onUpPressed: previousItem(); - Keys.onDownPressed: nextItem(); - Keys.onSpacePressed: selectCurrentItem(); - Keys.onRightPressed: selectCurrentItem(); - Keys.onReturnPressed: selectCurrentItem(); - } -} - - - diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1458ec0018..f28ed10bdc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1059,10 +1059,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get()->toggleMute(); } else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) { cycleCamera(); - } else if (action == controller::toInt(controller::Action::UI_NAV_SELECT)) { - if (!offscreenUi->navigationFocused()) { - toggleMenuUnderReticle(); - } } else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) { toggleTabletUI(); } else if (action == controller::toInt(controller::Action::RETICLE_X)) { @@ -1580,17 +1576,6 @@ QString Application::getUserAgent() { return userAgent; } -void Application::toggleMenuUnderReticle() const { - // In HMD, if the menu is near the mouse but not under it, the reticle can be at a significantly - // different depth. When you focus on the menu, the cursor can appear to your crossed eyes as both - // on the menu and off. - // Even in 2D, it is arguable whether the user would want the menu to be to the side. - const float X_LEFT_SHIFT = 50.0; - auto offscreenUi = DependencyManager::get(); - auto reticlePosition = getApplicationCompositor().getReticlePosition(); - offscreenUi->toggleMenu(QPoint(reticlePosition.x - X_LEFT_SHIFT, reticlePosition.y)); -} - uint64_t lastTabletUIToggle { 0 }; const uint64_t toggleTabletUILockout { 500000 }; void Application::toggleTabletUI() const { @@ -2931,10 +2916,6 @@ void Application::keyPressEvent(QKeyEvent* event) { void Application::keyReleaseEvent(QKeyEvent* event) { - if (event->key() == Qt::Key_Alt && _altPressed && hasFocus()) { - toggleMenuUnderReticle(); - } - _keysPressed.remove(event->key()); _controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts diff --git a/interface/src/Application.h b/interface/src/Application.h index c789c705a3..3b89aa52f3 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -484,7 +484,6 @@ private: static void dragEnterEvent(QDragEnterEvent* event); void maybeToggleMenuVisible(QMouseEvent* event) const; - void toggleMenuUnderReticle() const; void toggleTabletUI() const; MainWindow* _window; diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 1814d30c0a..918fb7b54a 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -537,9 +537,6 @@ void OffscreenUi::unfocusWindows() { Q_ASSERT(invokeResult); } -void OffscreenUi::toggleMenu(const QPoint& screenPosition) { // caller should already have mapped using getReticlePosition -} - class FileDialogListener : public ModalDialogListener { Q_OBJECT diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index 409b70ea3a..c648e2ec86 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -45,7 +45,6 @@ public: bool navigationFocused(); void setNavigationFocused(bool focused); void unfocusWindows(); - void toggleMenu(const QPoint& screenCoordinates); // Setting pinned to true will hide all overlay elements on the desktop that don't have a pinned flag diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 12f655554e..beb54ae3fa 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -118,7 +118,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { _this.clicked = true; } var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - tablet.gotoMenuScreen(); + tablet.gotoHomeScreen(); } };