Allow keyboard navigation of 'vr menu'

This commit is contained in:
Brad Davis 2016-01-03 20:22:39 -08:00
parent ec8a2ae093
commit bfa9213a10
3 changed files with 167 additions and 138 deletions

View file

@ -1,7 +1,9 @@
import Hifi 1.0 as Hifi import Hifi 1.0 as Hifi
import QtQuick 2.4 import QtQuick 2.4
import QtQuick.Controls 1.3 import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3 import QtQuick.Controls.Styles 1.3
import "controls" import "controls"
import "styles" import "styles"
@ -21,15 +23,18 @@ Hifi.VrMenu {
property var models: [] property var models: []
property var columns: [] property var columns: []
onEnabledChanged: { onEnabledChanged: {
console.log("Activating menu " + enabled);
if (enabled && columns.length == 0) { if (enabled && columns.length == 0) {
console.log(rootMenu)
console.log(rootMenu.items)
pushColumn(rootMenu.items); pushColumn(rootMenu.items);
} }
opacity = enabled ? 1.0 : 0.0 opacity = enabled ? 1.0 : 0.0
if (enabled) { offscreenFlags.navigationFocused = enabled;
forceActiveFocus() // if (enabled) {
} //forceActiveFocus()
// }
} }
// The actual animator // The actual animator
@ -49,13 +54,12 @@ Hifi.VrMenu {
} }
property var menuBuilder: Component { property var menuBuilder: Component {
Border { VrMenuView {
HifiConstants { id: hifi } property int menuDepth: root.models.length - 1
property int menuDepth model: root.models[menuDepth]
Component.onCompleted: { Component.onCompleted: {
menuDepth = root.models.length - 1 if (menuDepth === 0) {
if (menuDepth == 0) {
x = lastMousePosition.x - 20 x = lastMousePosition.x - 20
y = lastMousePosition.y - 20 y = lastMousePosition.y - 20
} else { } else {
@ -63,50 +67,11 @@ Hifi.VrMenu {
x = lastColumn.x + 64; x = lastColumn.x + 64;
y = lastMousePosition.y - height / 2; y = lastMousePosition.y - height / 2;
} }
//recalcSize();
} }
border.color: hifi.colors.hifiBlue onSelected: {
color: hifi.colors.window root.selectItem(menuDepth, item)
implicitHeight: listView.implicitHeight + 16
implicitWidth: listView.implicitWidth + 16
Column {
id: listView
property real minWidth: 0
anchors {
top: parent.top
topMargin: 8
left: parent.left
leftMargin: 8
right: parent.right
rightMargin: 8
}
Repeater {
model: root.models[menuDepth]
delegate: Loader {
id: loader
source: "VrMenuItem.qml"
Binding {
target: loader.item
property: "menuContainer"
value: root
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "source"
value: modelData
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "listView"
value: listView
when: loader.status == Loader.Ready
}
}
}
} }
} }
} }
@ -116,14 +81,14 @@ Hifi.VrMenu {
} }
function pushColumn(items) { function pushColumn(items) {
models.push(items) models.push(itemsToModel(items))
if (columns.length) { if (columns.length) {
var oldColumn = lastColumn(); var oldColumn = lastColumn();
//oldColumn.enabled = false //oldColumn.enabled = false
} }
var newColumn = menuBuilder.createObject(root); var newColumn = menuBuilder.createObject(root);
columns.push(newColumn); columns.push(newColumn);
newColumn.forceActiveFocus(); forceActiveFocus();
} }
function popColumn() { function popColumn() {
@ -145,13 +110,41 @@ Hifi.VrMenu {
curColumn.forceActiveFocus(); curColumn.forceActiveFocus();
} }
function selectItem(source) { function itemsToModel(items) {
var newListModel = Qt.createQmlObject('import QtQuick 2.2; ListModel {}', root);
console.log(items)
console.log(items.length)
for (var i = 0; i < items.length; ++i) {
var item = items[i];
switch (item.type) {
case 2:
newListModel.append({"type":item.type, "name": item.title, "item": item})
break;
case 1:
newListModel.append({"type":item.type, "name": item.text, "item": item})
break;
case 0:
newListModel.append({"type":item.type, "name": "-----", "item": item})
break;
}
}
return newListModel;
}
function selectItem(depth, source) {
var popped = false;
while (depth + 1 < columns.length) {
popColumn()
popped = true
}
switch (source.type) { switch (source.type) {
case 2: case 2:
lastColumn().enabled = false
pushColumn(source.items) pushColumn(source.items)
break; break;
case 1: case 1:
source.trigger() if (!popped) source.trigger()
enabled = false enabled = false
break; break;
case 0: case 0:
@ -165,14 +158,6 @@ Hifi.VrMenu {
} }
} }
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Escape:
root.popColumn()
event.accepted = true;
}
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
id: mouseArea id: mouseArea
@ -206,4 +191,36 @@ Hifi.VrMenu {
function removeItem(menu, menuItem) { function removeItem(menu, menuItem) {
menu.removeItem(menuItem); menu.removeItem(menuItem);
} }
function previousItem() {
if (columns.length) {
lastColumn().incrementCurrentIndex()
}
}
function nextItem() {
if (columns.length) {
lastColumn().decrementCurrentIndex()
}
}
function selectCurrentItem() {
if (columns.length) {
var depth = columns.length - 1;
var index = lastColumn().currentIndex;
if (index >= 0) {
var model = models[depth];
var item = model.get(index).item;
selectItem(depth, item);
}
}
}
Keys.onDownPressed: previousItem();
Keys.onUpPressed: nextItem();
Keys.onSpacePressed: selectCurrentItem();
Keys.onReturnPressed: selectCurrentItem();
Keys.onRightPressed: selectCurrentItem();
Keys.onLeftPressed: popColumn();
Keys.onEscapePressed: popColumn();
} }

View file

@ -1,62 +1,23 @@
import QtQuick 2.4 import QtQuick 2.4
import QtQuick.Controls 1.3 import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3 import QtQuick.Controls.Styles 1.3
import "controls"
import "styles" import "styles"
import "controls"
Item { Item {
id: root id: root
HifiConstants { HifiConstants { id: hifi }
id: hifi
}
// The model object
property alias text: label.text
property var source property var source
property var menuContainer
property var listView
MouseArea {
anchors.left: parent.left
anchors.right: tag.right
anchors.rightMargin: -4
anchors.top: parent.top
anchors.bottom: parent.bottom
acceptedButtons: Qt.LeftButton
hoverEnabled: true
Rectangle {
id: highlight
visible: false
anchors.fill: parent
color: "#7f0e7077"
}
onEntered: {
//if (source.type == 2 && enabled) {
// timer.start()
//}
highlight.visible = source.enabled
}
onExited: {
timer.stop()
highlight.visible = false
}
onClicked: {
select()
}
}
implicitHeight: source.visible ? label.implicitHeight * 1.5 : 0 implicitHeight: source.visible ? label.implicitHeight * 1.5 : 0
implicitWidth: label.implicitWidth + label.height * 2.5 implicitWidth: label.width + label.height * 2.5
visible: source.visible visible: source.visible
width: parent.width
Timer {
id: timer
interval: 1000
onTriggered: parent.select()
}
FontAwesome { FontAwesome {
clip: true clip: true
@ -84,32 +45,18 @@ Item {
Text { Text {
id: label id: label
text: typedText()
anchors.left: check.right anchors.left: check.right
anchors.leftMargin: 4 anchors.leftMargin: 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
color: source.enabled ? hifi.colors.text : hifi.colors.disabledText color: source.enabled ? hifi.colors.text : hifi.colors.disabledText
enabled: source.enabled && source.visible enabled: source.visible && (source.type !== 0 ? source.enabled : false)
visible: source.visible visible: source.visible
function typedText() {
if (source) {
switch (source.type) {
case 2:
return source.title
case 1:
return source.text
case 0:
return "-----"
}
}
return ""
}
} }
FontAwesome { FontAwesome {
id: tag id: tag
x: listView.width - width - 4 x: root.parent.width - width
size: label.height size: label.height
width: implicitWidth width: implicitWidth
visible: source.visible && (source.type == 2) visible: source.visible && (source.type == 2)
@ -117,17 +64,4 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: label.color color: label.color
} }
function select() {
//timer.stop();
var popped = false
while (columns.length - 1 > listView.parent.menuDepth) {
popColumn()
popped = true
}
if (!popped || source.type != 1) {
root.menuContainer.selectItem(source)
}
}
} }

View file

@ -0,0 +1,78 @@
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
import "styles"
ListView {
id: root
HifiConstants { id: hifi }
width: 128
height: count * 32
onEnabledChanged: root.recalcSize();
onVisibleChanged: root.recalcSize();
signal selected(var item)
highlight: Rectangle {
width: root.currentItem ? root.currentItem.width : 0
height: root.currentItem ? root.currentItem.height : 0
color: "lightsteelblue"; radius: 3
// y: root.currentItem ? root.currentItem.y : 0
}
delegate: VrMenuItem {
text: name
source: item
onImplicitHeightChanged: root.recalcSize()
onImplicitWidthChanged: root.recalcSize()
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: root.currentIndex = index
onClicked: root.selected(item)
}
}
onCountChanged: recalcSize();
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
}
}
if (maxWidth > width) {
width = maxWidth;
}
if (newHeight > height) {
height = newHeight
}
currentIndex = originalIndex;
}
Border {
id: border
anchors.fill: parent
anchors.margins: -8
z: parent.z - 1
border.color: hifi.colors.hifiBlue
color: hifi.colors.window
}
}