mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 16:55:07 +02:00
added context menu to tablet
This commit is contained in:
parent
3fab901b49
commit
6c51edec77
9 changed files with 460 additions and 16 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
113
interface/resources/qml/hifi/tablet/TabletMenuItem.qml
Normal file
113
interface/resources/qml/hifi/tablet/TabletMenuItem.qml
Normal file
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
117
interface/resources/qml/hifi/tablet/TabletMenuView.qml
Normal file
117
interface/resources/qml/hifi/tablet/TabletMenuView.qml
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
163
interface/resources/qml/hifi/tablet/TabletMouseHandler.qml
Normal file
163
interface/resources/qml/hifi/tablet/TabletMouseHandler.qml
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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<QQuickItem*>("loader");
|
||||
//QObject::connect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToMenuScreen()));
|
||||
_qmlTabletRoot->setProperty(LOADER_SOURCE_PROPERTY_NAME, VRMENU_SOURCE_URL);
|
||||
auto loader = _qmlTabletRoot->findChild<QQuickItem*>("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<QQuickItem*>("VrMenu");
|
||||
QQuickItem* VrMenu = loader->findChild<QQuickItem*>("tabletMenu");
|
||||
if (!VrMenu) {
|
||||
qDebug() << "----------> could not find vr menu";
|
||||
return;
|
||||
}
|
||||
|
||||
QString name = "Menu";
|
||||
QVariant returnedValue;
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QObject* menu = offscreenUi->getRootMenu();
|
||||
QMetaObject::invokeMethod(VrMenu, "setRootMenu", Qt::AutoConnection, Q_ARG(QVariant, QVariant::fromValue(menu)));
|
||||
}
|
||||
|
||||
void TabletProxy::removeButtonsFromHomeScreen() {
|
||||
|
|
|
@ -524,6 +524,10 @@ QQuickItem* OffscreenUi::getDesktop() {
|
|||
return _desktop;
|
||||
}
|
||||
|
||||
QObject* OffscreenUi::getRootMenu() {
|
||||
return getRootItem()->findChild<QObject*>("rootMenu");
|
||||
}
|
||||
|
||||
QQuickItem* OffscreenUi::getToolWindow() {
|
||||
return _toolWindow;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
30
scripts/system/menu.js
Normal file
30
scripts/system/menu.js
Normal file
|
@ -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);
|
||||
})
|
||||
}());
|
Loading…
Reference in a new issue