overhauled navigation, it doesn't suck now

This commit is contained in:
2026-08-09 23:47:10 -05:00
parent f70e9b0b08
commit 75f0cbded6
3 changed files with 199 additions and 40 deletions
+1
View File
@@ -19,6 +19,7 @@ qt_add_qml_module(nomad-shell
VERSION 1.0 VERSION 1.0
QML_FILES QML_FILES
qml/Main.qml qml/Main.qml
qml/NavigationManager.qml
) )
target_link_libraries(nomad-shell target_link_libraries(nomad-shell
+59 -40
View File
@@ -59,50 +59,27 @@ QtObject {
property int focusRegion: bottomWindow.mainMenuNavRegions.GamesList property int focusRegion: bottomWindow.mainMenuNavRegions.GamesList
property int dockMenuIndex: 0 property int dockMenuIndex: 0
NavigationManager {
id: navigationManager
rootItem: bottomRoot
}
Connections { Connections {
target: inputManager target: inputManager
function onActionPressed(action) { function onActionPressed(action) {
if (action === InputManager.Up) { switch (action) {
if (bottomWindow.focusRegion < bottomWindow.mainMenuNavRegions.Count - 1) { case InputManager.Up:
bottomWindow.focusRegion += 1 case InputManager.Down:
} case InputManager.Left:
} case InputManager.Right:
if (action === InputManager.Down) { navigationManager.move(action)
if (bottomWindow.focusRegion > 0) { break
bottomWindow.focusRegion -= 1
}
}
if (action === InputManager.Left || action === InputManager.Right) {
switch (bottomWindow.focusRegion) {
case bottomWindow.mainMenuNavRegions.GamesList:
if (action === InputManager.Left) {
if (gamesList.currentIndex > 0) {
gamesList.currentIndex -= 1
}
} else {
if (gamesList.currentIndex < gamesList.count - 1) {
gamesList.currentIndex += 1
}
}
break
case bottomWindow.mainMenuNavRegions.DockMenu:
if (action === InputManager.Left) {
if (bottomWindow.dockMenuIndex > 0) {
bottomWindow.dockMenuIndex -= 1
}
} else {
if (bottomWindow.dockMenuIndex < dockRepeater.count - 1) {
bottomWindow.dockMenuIndex += 1
}
}
break
}
} }
} }
} }
Rectangle { Rectangle {
id: bottomRoot id: bottomRoot
anchors.fill: parent anchors.fill: parent
@@ -135,17 +112,36 @@ QtObject {
model: 20 model: 20
Component.onCompleted: {
if (currentItem) {
navigationManager.focusItem(currentItem)
}
}
delegate: Rectangle { delegate: Rectangle {
id: gameTile
width: 110 width: 110
height: 110 height: 110
color: bottomWindow.focusRegion === bottomWindow.mainMenuNavRegions.GamesList && index === gamesList.currentIndex ? "blue" : "white" color: navigationManager.currentItem === gameTile ? "blue" : "white"
function navFocus() {
gamesList.currentIndex = index
}
Component.onCompleted: {
navigationManager.registerItem(gameTile)
}
Component.onDestruction: {
navigationManager.unregisterItem(gameTile)
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
bottomWindow.focusRegion = bottomWindow.mainMenuNavRegions.GamesList navigationManager.focusItem(gameTile)
gamesList.currentIndex = index
} }
} }
} }
@@ -165,9 +161,32 @@ QtObject {
model: 5 model: 5
Rectangle { Rectangle {
id: dockButton
width: 60 width: 60
height: 60 height: 60
color: bottomWindow.focusRegion === bottomWindow.mainMenuNavRegions.DockMenu && index === bottomWindow.dockMenuIndex ? "blue" : "white"
color: navigationManager.currentItem === dockButton ? "blue" : "white"
function navFocus() {
bottomWindow.dockMenuIndex = index
}
Component.onCompleted: {
navigationManager.registerItem(dockButton)
}
Component.onDestruction: {
navigationManager.unregisterItem(dockButton)
}
MouseArea {
anchors.fill: parent
onClicked: {
navigationManager.focusItem(dockButton)
}
}
} }
} }
} }
+139
View File
@@ -0,0 +1,139 @@
import QtQuick
import NomadInput 1.0
QtObject {
id: manager
property Item rootItem: null
property list<QtObject> items
property var currentItem: null
function focusItem(item) {
if (!item) {
return
}
currentItem = item
if (typeof item.navFocus === "function") {
item.navFocus()
}
}
function registerItem(item) {
if (!item) {
return
}
for (let i = 0; i < items.length; i++) {
if (items[i] === item) {
return
}
}
items.push(item)
}
function unregisterItem(item) {
if (!item) {
return
}
for (let i = 0; i < items.length; i++) {
if (items[i] === item) {
items.splice(i, 1)
if (currentItem === item) {
currentItem = null
}
return;
}
}
}
function move(action) {
if (!currentItem || !rootItem) {
return
}
let dx = 0
let dy = 0
switch(action) {
case InputManager.Left:
dx = -1
break
case InputManager.Right:
dx = 1
break
case InputManager.Up:
dy = -1
break
case InputManager.Down:
dy = 1
break
default:
return
}
let currentCenter = currentItem.mapToItem(rootItem, currentItem.width / 2, currentItem.height / 2)
let bestItem = null
let bestScore = Infinity
for (let i = 0; i < items.length; i++) {
let candidate = items[i]
if (!candidate) {
continue
}
if (candidate === currentItem) {
continue
}
if (!candidate.visible || !candidate.enabled) {
continue
}
let candidateCenter = candidate.mapToItem(rootItem, candidate.width / 2, candidate.height / 2)
let differenceX = candidateCenter.x - currentCenter.x
let differenceY = candidateCenter.y - currentCenter.y
let forwardDistance
let sidewaysDistance
if (dx !== 0) {
forwardDistance = differenceX * dx
sidewaysDistance = Math.abs(differenceY)
} else {
forwardDistance = differenceY * dy
sidewaysDistance = Math.abs(differenceX)
}
if (forwardDistance <= 0) {
continue
}
let score = forwardDistance + sidewaysDistance * 2
if (score < bestScore) {
bestScore = score
bestItem = candidate
}
console.log("candidate:", candidate, "center:", candidateCenter.x, candidateCenter.y, "difference:", differenceX, differenceY)
}
if (bestItem) {
focusItem(bestItem)
}
console.log("MOVE", inputManager.actionName(action), "current:", currentItem, "center:", currentCenter.x, currentCenter.y)
}
}