diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 63ea386452..9ca230b577 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -4,9 +4,10 @@ import QtGraphicalEffects 1.0 Item { id: tablet objectName: "tablet" - property double micLevel: 0.8 - + property int rowIndex: 0 + property int columnIndex: 0 + property int count: (flowMain.children.length - 1) width: parent.width height: parent.height @@ -42,7 +43,6 @@ Item { // pass a reference to the tabletRoot object to the button. button.tabletRoot = parent.parent; - return button; } @@ -212,5 +212,67 @@ Item { } } ] + + function setCurrentItemState(state) { + var index = rowIndex + columnIndex; + + if (index >= 0 && index <= count ) { + flowMain.children[index].state = state; + } + } + function nextItem() { + setCurrentItemState("base state"); + var nextColumnIndex = (columnIndex + 3 + 1) % 3; + var nextIndex = rowIndex + nextColumnIndex; + if(nextIndex <= count) { + columnIndex = nextColumnIndex; + }; + setCurrentItemState("hover state"); + } + + function previousItem() { + setCurrentItemState("base state"); + var prevIndex = (columnIndex + 3 - 1) % 3; + if((rowIndex + prevIndex) <= count){ + columnIndex = prevIndex; + } + setCurrentItemState("hover state"); + } + + function upItem() { + setCurrentItemState("base state"); + rowIndex = rowIndex - 3; + if (rowIndex < 0 ) { + rowIndex = (count - (count % 3)); + var index = rowIndex + columnIndex; + if(index > count) { + rowIndex = rowIndex - 3; + } + } + setCurrentItemState("hover state"); + } + + function downItem() { + setCurrentItemState("base state"); + rowIndex = rowIndex + 3; + var index = rowIndex + columnIndex; + if (index > count ) { + rowIndex = 0; + } + setCurrentItemState("hover state"); + } + + function selectItem() { + flowMain.children[rowIndex + columnIndex].clicked(); + if (tabletRoot) { + tabletRoot.playButtonClickSound(); + } + } + + Keys.onRightPressed: nextItem(); + Keys.onLeftPressed: previousItem(); + Keys.onDownPressed: downItem(); + Keys.onUpPressed: upItem(); + Keys.onReturnPressed: selectItem(); } diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml index f9c668a81f..6c2685f155 100644 --- a/interface/resources/qml/hifi/tablet/TabletButton.qml +++ b/interface/resources/qml/hifi/tablet/TabletButton.qml @@ -109,6 +109,7 @@ Item { MouseArea { anchors.fill: parent hoverEnabled: true + enabled: true onClicked: { console.log("Tablet Button Clicked!"); if (tabletButton.inDebugMode) { diff --git a/interface/resources/qml/hifi/tablet/TabletMenu.qml b/interface/resources/qml/hifi/tablet/TabletMenu.qml index 39f48f0334..a80ca12d5f 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenu.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenu.qml @@ -5,7 +5,7 @@ import QtQml 2.2 import "." import "../../styles-uit" -Item { +FocusScope { id: tabletMenu objectName: "tabletMenu" @@ -87,6 +87,10 @@ Item { } } + function pop() { + menuPopperUpper.closeLastMenu(); + } + function setRootMenu(menu) { tabletMenu.rootMenu = menu buildMenu() diff --git a/interface/resources/qml/hifi/tablet/TabletMenuView.qml b/interface/resources/qml/hifi/tablet/TabletMenuView.qml index b02c5b67ec..6411c1af02 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuView.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuView.qml @@ -13,12 +13,12 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import "../../styles-uit" - +import "." FocusScope { id: root implicitHeight: background.height implicitWidth: background.width - + objectName: "root" property alias currentItem: listView.currentItem property alias model: listView.model property bool isSubMenu: false @@ -45,6 +45,7 @@ FocusScope { height: 720 contentWidth: 480 contentHeight: 720 + objectName: "menuList" topMargin: hifi.dimensions.menuPadding.y bottomMargin: hifi.dimensions.menuPadding.y @@ -107,17 +108,21 @@ FocusScope { } 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(); + Keys.onLeftPressed: previousPage(); } + + function previousItem() { listView.currentIndex = (listView.currentIndex + listView.count - 1) % listView.count; } + function nextItem() { listView.currentIndex = (listView.currentIndex + listView.count + 1) % listView.count; } + function selectCurrentItem() { if (listView.currentIndex != -1) root.selected(currentItem.source); } + function previousPage() { root.parent.pop(); } + + } diff --git a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml index 57d4c5837f..3f8a3d8245 100644 --- a/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml +++ b/interface/resources/qml/hifi/tablet/TabletMouseHandler.qml @@ -58,7 +58,6 @@ Item { 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}) @@ -81,6 +80,7 @@ Item { if (menuStack.length) { topMenu = menuStack[menuStack.length - 1]; topMenu.focus = true; + topMenu.forceActiveFocus(); // show current menu level on nav bar if (topMenu.objectName === "") { breadcrumbText.text = "Menu"; @@ -90,8 +90,7 @@ Item { } else { breadcrumbText.text = "Menu"; topMenu = null; - //offscreenFlags.navigationFocused = false; - menuRoot.enabled = false; + offscreenFlags.navigationFocused = false; } } @@ -99,7 +98,8 @@ Item { menuStack.push(newMenu); topMenu = newMenu; topMenu.focus = true; - //offscreenFlags.navigationFocused = true; + topMenu.forceActiveFocus(); + offscreenFlags.navigationFocused = true; } function clearMenus() { @@ -159,16 +159,20 @@ Item { function popup(parent, items) { d.clearMenus(); - menuRoot.enabled = true; d.buildMenu(items, point); } function closeLastMenu() { - if (d.menuStack.length) { + if (d.menuStack.length > 1) { d.popMenu(); return true; } return false; } + function previousItem() { d.topMenu.previousItem(); } + function nextItem() { d.topMenu.nextItem(); } + function selectCurrentItem() { d.topMenu.selectCurrentItem(); } + function previousPage() { d.topMenu.previousPage(); } + } diff --git a/interface/resources/qml/hifi/tablet/TabletRoot.qml b/interface/resources/qml/hifi/tablet/TabletRoot.qml index 541119d4f0..ec803fd919 100644 --- a/interface/resources/qml/hifi/tablet/TabletRoot.qml +++ b/interface/resources/qml/hifi/tablet/TabletRoot.qml @@ -6,6 +6,8 @@ Item { objectName: "tabletRoot" property var eventBridge; + signal showDesktop(); + function loadSource(url) { loader.source = url; } @@ -33,7 +35,6 @@ Item { height: parent.height onLoaded: { - // propogate eventBridge to WebEngineView if (loader.item.hasOwnProperty("eventBridge")) { loader.item.eventBridge = eventBridge; @@ -44,8 +45,12 @@ Item { } }); } + loader.item.forceActiveFocus(); + offscreenFlags.navigationFocused = true; } } + + Component.onDestruction: { offscreenFlags.navigationFocused = false; } width: 480 height: 720 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 45cea3f6c5..5e278fee86 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -977,6 +977,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) { using namespace controller; auto offscreenUi = DependencyManager::get(); + auto tabletScriptingInterface = DependencyManager::get(); if (offscreenUi->navigationFocused()) { auto actionEnum = static_cast(action); int key = Qt::Key_unknown; @@ -1021,25 +1022,28 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo break; } - if (navAxis) { + auto window = tabletScriptingInterface->getTabletWindow(); + if (navAxis && window) { if (lastKey != Qt::Key_unknown) { QKeyEvent event(QEvent::KeyRelease, lastKey, Qt::NoModifier); - sendEvent(offscreenUi->getWindow(), &event); + sendEvent(window, &event); lastKey = Qt::Key_unknown; } if (key != Qt::Key_unknown) { QKeyEvent event(QEvent::KeyPress, key, Qt::NoModifier); - sendEvent(offscreenUi->getWindow(), &event); + sendEvent(window, &event); + tabletScriptingInterface->processEvent(&event); lastKey = key; } - } else if (key != Qt::Key_unknown) { + } else if (key != Qt::Key_unknown && window) { if (state) { QKeyEvent event(QEvent::KeyPress, key, Qt::NoModifier); - sendEvent(offscreenUi->getWindow(), &event); + sendEvent(window, &event); + tabletScriptingInterface->processEvent(&event); } else { QKeyEvent event(QEvent::KeyRelease, key, Qt::NoModifier); - sendEvent(offscreenUi->getWindow(), &event); + sendEvent(window, &event); } return; } diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 652d1c6d6d..f052081cc6 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -151,6 +151,8 @@ void Web3DOverlay::loadSourceURL() { if (_webSurface->getRootItem() && _webSurface->getRootItem()->objectName() == "tabletRoot") { auto tabletScriptingInterface = DependencyManager::get(); + auto flags = tabletScriptingInterface->getFlags(); + _webSurface->getRootContext()->setContextProperty("offscreenFlags", flags); tabletScriptingInterface->setQmlTabletRoot("com.highfidelity.interface.tablet.system", _webSurface->getRootItem(), _webSurface.data()); } } diff --git a/libraries/script-engine/src/TabletScriptingInterface.cpp b/libraries/script-engine/src/TabletScriptingInterface.cpp index 822aa25306..4c4eb19f45 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.cpp +++ b/libraries/script-engine/src/TabletScriptingInterface.cpp @@ -47,6 +47,89 @@ void TabletScriptingInterface::setQmlTabletRoot(QString tabletId, QQuickItem* qm } } +QQuickWindow* TabletScriptingInterface::getTabletWindow() { + TabletProxy* tablet = qobject_cast(getTablet("com.highfidelity.interface.tablet.system")); + QObject* qmlSurface = tablet->getTabletSurface(); + OffscreenQmlSurface* surface = dynamic_cast(qmlSurface); + + if (!surface) { + return nullptr; + } + QQuickWindow* window = surface->getWindow(); + return window; +} + +void TabletScriptingInterface::processMenuEvents(QObject* object, const QKeyEvent* event) { + switch (event->key()) { + case Qt::Key_Down: + QMetaObject::invokeMethod(object, "nextItem"); + break; + + case Qt::Key_Up: + QMetaObject::invokeMethod(object, "previousItem"); + break; + + case Qt::Key_Left: + QMetaObject::invokeMethod(object, "previousPage"); + break; + + case Qt::Key_Right: + QMetaObject::invokeMethod(object, "selectCurrentItem"); + break; + + case Qt::Key_Return: + QMetaObject::invokeMethod(object, "selectCurrentItem"); + break; + defualt: + break; + } +} + +void TabletScriptingInterface::processTabletEvents(QObject* object, const QKeyEvent* event) { + switch (event->key()) { + case Qt::Key_Down: + QMetaObject::invokeMethod(object, "downItem"); + break; + + case Qt::Key_Up: + QMetaObject::invokeMethod(object, "upItem"); + break; + + case Qt::Key_Left: + QMetaObject::invokeMethod(object, "previousItem"); + break; + + case Qt::Key_Right: + QMetaObject::invokeMethod(object, "nextItem"); + break; + + case Qt::Key_Return: + QMetaObject::invokeMethod(object, "selectItem"); + break; + defualt: + break; + } +} + + +void TabletScriptingInterface::processEvent(const QKeyEvent* event) { + TabletProxy* tablet = qobject_cast(getTablet("com.highfidelity.interface.tablet.system")); + QObject* qmlTablet = tablet->getQmlTablet(); + QObject* qmlMenu = tablet->getQmlMenu(); + + if (qmlTablet) { + processTabletEvents(qmlTablet, event); + } else if (qmlMenu) { + processMenuEvents(qmlMenu, event); + } +} + +QObject* TabletScriptingInterface::getFlags() +{ + auto offscreenUi = DependencyManager::get(); + return offscreenUi->getFlags(); +} + // // TabletProxy // @@ -200,6 +283,10 @@ void TabletProxy::addButtonsToHomeScreen() { QObject::disconnect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen())); } +QObject* TabletProxy::getTabletSurface() { + return _qmlOffscreenSurface; +} + void TabletProxy::addButtonsToMenuScreen() { if (!_qmlTabletRoot) { return; @@ -212,7 +299,6 @@ void TabletProxy::addButtonsToMenuScreen() { QQuickItem* VrMenu = loader->findChild("tabletMenu"); if (!VrMenu) { - qDebug() << "----------> could not find vr menu"; return; } @@ -246,6 +332,28 @@ QQuickItem* TabletProxy::getQmlTablet() const { return tablet; } +QQuickItem* TabletProxy::getQmlMenu() const { + if (!_qmlTabletRoot) { + return nullptr; + } + + auto loader = _qmlTabletRoot->findChild("loader"); + if (!loader) { + return nullptr; + } + + QQuickItem* VrMenu = loader->findChild("tabletMenu"); + if (!VrMenu) { + return nullptr; + } + + QQuickItem* menuList = VrMenu->findChild("tabletMenuHandlerItem"); + if (!menuList) { + return nullptr; + } + return menuList; +} + // // TabletButtonProxy // diff --git a/libraries/script-engine/src/TabletScriptingInterface.h b/libraries/script-engine/src/TabletScriptingInterface.h index a7894c0afd..4b8c792af3 100644 --- a/libraries/script-engine/src/TabletScriptingInterface.h +++ b/libraries/script-engine/src/TabletScriptingInterface.h @@ -47,6 +47,16 @@ public: void setQmlTabletRoot(QString tabletId, QQuickItem* qmlTabletRoot, QObject* qmlOffscreenSurface); + void processEvent(const QKeyEvent* event); + + QQuickWindow* getTabletWindow(); + + QObject* getFlags(); + +private: + void processMenuEvents(QObject* object, const QKeyEvent* event); + void processTabletEvents(QObject* object, const QKeyEvent* event); + protected: std::mutex _mutex; std::map> _tabletProxies; @@ -112,6 +122,13 @@ public: */ Q_INVOKABLE void emitScriptEvent(QVariant msg); + + QObject* getTabletSurface(); + + QQuickItem* getQmlTablet() const; + + QQuickItem* getQmlMenu() const; + signals: /**jsdoc * Signaled when this tablet receives an event from the html/js embedded in the tablet @@ -126,7 +143,6 @@ private slots: void addButtonsToMenuScreen(); protected: void removeButtonsFromHomeScreen(); - QQuickItem* getQmlTablet() const; QString _name; std::mutex _mutex;