61c448eb00
Integrate SDL3 controller support and wire it into the InputRouter.
- Add ControllerInputService (src/ControllerInputService.{h,cpp}) to discover, poll and translate SDL3 gamepad events into InputRouter actions, with axis repeat handling and debouncing.
- Update CMakeLists to find or fetch SDL3, add the new source files to the target, link the SDL3 target, and copy runtime DLLs on Windows.
- Add triggerAction(Action) to InputRouter and use it from existing keyboard handling to centralize action dispatch.
- Instantiate ControllerInputService in main so controllers feed the InputRouter.
- Update QML views (ShellWindow, HomeView, LibraryView, SettingsView) to use numeric action IDs and add small UI/status text and navigation tweaks for controller-driven flows.
These changes enable gamepad/controller input for Bigscreen via SDL3 and adapt UI code to handle the mapped actions.
134 lines
3.6 KiB
QML
134 lines
3.6 KiB
QML
import QtQuick
|
|
import QtQuick.Layouts
|
|
import Nebula.Bigscreen
|
|
|
|
ColumnLayout {
|
|
id: root
|
|
|
|
signal goBack()
|
|
|
|
readonly property var categories: [
|
|
"Network",
|
|
"Audio",
|
|
"Display",
|
|
"Controller",
|
|
"System"
|
|
]
|
|
|
|
property int categoryIndex: 0
|
|
property int itemIndex: 0
|
|
readonly property int settingCount: 3
|
|
property string statusText: "Choose a setting with Accept. Detailed controls come later."
|
|
|
|
spacing: 20
|
|
|
|
Text {
|
|
text: "Settings"
|
|
font: Theme.brandFont
|
|
color: Theme.textPrimary
|
|
Layout.leftMargin: 40
|
|
}
|
|
|
|
Row {
|
|
Layout.leftMargin: 40
|
|
spacing: 16
|
|
|
|
Repeater {
|
|
model: root.categories
|
|
|
|
Rectangle {
|
|
height: 40
|
|
width: categoryLabel.implicitWidth + 24
|
|
radius: 8
|
|
color: index === root.categoryIndex ? "#22304A66" : "transparent"
|
|
border.color: index === root.categoryIndex ? Theme.accentCyan : "transparent"
|
|
border.width: index === root.categoryIndex ? 2 : 0
|
|
|
|
Text {
|
|
id: categoryLabel
|
|
anchors.centerIn: parent
|
|
text: modelData
|
|
font: Theme.bodyFont
|
|
color: index === root.categoryIndex ? Theme.accentCyan : Theme.textMuted
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
Layout.margins: 40
|
|
radius: 16
|
|
color: Theme.backgroundPanel
|
|
border.color: Theme.accentLine
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
anchors.margins: 24
|
|
spacing: 12
|
|
|
|
Text {
|
|
text: root.categories[root.categoryIndex]
|
|
font: Theme.titleFont
|
|
color: Theme.textPrimary
|
|
}
|
|
|
|
Repeater {
|
|
model: root.settingCount
|
|
|
|
Rectangle {
|
|
Layout.fillWidth: true
|
|
height: 52
|
|
radius: 10
|
|
color: index === root.itemIndex ? "#22304A66" : Theme.backgroundMid
|
|
border.color: index === root.itemIndex ? Theme.accentCyan : Theme.accentLine
|
|
border.width: index === root.itemIndex ? 2 : 1
|
|
|
|
Text {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 16
|
|
text: "Placeholder setting " + (index + 1)
|
|
font: Theme.bodyFont
|
|
color: Theme.textPrimary
|
|
}
|
|
}
|
|
}
|
|
|
|
Text {
|
|
text: root.statusText
|
|
font: Theme.metaFont
|
|
color: Theme.textMuted
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleInput(action) {
|
|
switch (action) {
|
|
case 3:
|
|
categoryIndex = Math.max(0, categoryIndex - 1)
|
|
itemIndex = 0
|
|
break
|
|
case 4:
|
|
categoryIndex = Math.min(categories.length - 1, categoryIndex + 1)
|
|
itemIndex = 0
|
|
break
|
|
case 1:
|
|
itemIndex = Math.max(0, itemIndex - 1)
|
|
break
|
|
case 2:
|
|
itemIndex = Math.min(settingCount - 1, itemIndex + 1)
|
|
break
|
|
case 6:
|
|
root.goBack()
|
|
break
|
|
case 5:
|
|
statusText = categories[categoryIndex] + " setting " + (itemIndex + 1) + " selected."
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|