Add Qt Bigscreen (QML/CMake), remove Tauri
Add a native Qt "Bigscreen" shell: CMakeLists, C++ entry (main.cpp, InputRouter), QML module (Theme, ShellWindow, views and components) and a Bigscreen/.gitignore; update top-level .gitignore and README with Qt build/run instructions. Remove the legacy Tauri/web prototype files (package.json, package-lock.json, src-tauri and many web assets) as part of the migration to the Qt/CMake-based shell.
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
import QtQuick
|
||||
|
||||
ShellWindow {
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Nebula.Bigscreen
|
||||
|
||||
ApplicationWindow {
|
||||
id: window
|
||||
|
||||
width: 1280
|
||||
height: 720
|
||||
visible: true
|
||||
title: "Nebula Bigscreen"
|
||||
color: Theme.backgroundDeep
|
||||
|
||||
property string currentView: "home"
|
||||
property bool powerOverlayVisible: false
|
||||
property string signedInUser: "Player"
|
||||
|
||||
NebulaBackground {
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
TopBar {
|
||||
id: topBar
|
||||
width: parent.width
|
||||
userName: window.signedInUser
|
||||
accentFocus: contentLoader.item && contentLoader.item.accentFocus !== undefined
|
||||
? contentLoader.item.accentFocus()
|
||||
: 0
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: contentLoader
|
||||
width: parent.width
|
||||
height: parent.height - topBar.height
|
||||
sourceComponent: viewComponentFor(window.currentView)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: contentLoader.item
|
||||
ignoreUnknownSignals: true
|
||||
function onNavigate(route) {
|
||||
window.onChildNavigate(route)
|
||||
}
|
||||
function onGoBack() {
|
||||
window.onChildGoBack()
|
||||
}
|
||||
}
|
||||
|
||||
PowerOverlay {
|
||||
id: powerOverlay
|
||||
visible: window.powerOverlayVisible
|
||||
z: 10
|
||||
|
||||
onDismissed: window.powerOverlayVisible = false
|
||||
onActionChosen: function(actionId) {
|
||||
console.log("Power action:", actionId)
|
||||
window.powerOverlayVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: InputRouter
|
||||
function onActionTriggered(action) {
|
||||
if (window.powerOverlayVisible) {
|
||||
window.handlePowerInput(action)
|
||||
return
|
||||
}
|
||||
if (action === InputRouter.Menu) {
|
||||
window.powerOverlayVisible = true
|
||||
return
|
||||
}
|
||||
if (contentLoader.item && contentLoader.item.handleInput) {
|
||||
contentLoader.item.handleInput(action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: homeComponent
|
||||
HomeView {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: libraryComponent
|
||||
LibraryView {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: settingsComponent
|
||||
SettingsView {}
|
||||
}
|
||||
|
||||
function viewComponentFor(viewId) {
|
||||
switch (viewId) {
|
||||
case "library":
|
||||
return libraryComponent
|
||||
case "settings":
|
||||
return settingsComponent
|
||||
default:
|
||||
return homeComponent
|
||||
}
|
||||
}
|
||||
|
||||
function onChildNavigate(route) {
|
||||
if (route === "power") {
|
||||
window.powerOverlayVisible = true
|
||||
return
|
||||
}
|
||||
window.currentView = route
|
||||
}
|
||||
|
||||
function onChildGoBack() {
|
||||
window.currentView = "home"
|
||||
}
|
||||
|
||||
function handlePowerInput(action) {
|
||||
switch (action) {
|
||||
case InputRouter.Up:
|
||||
powerOverlay.moveFocus(-1)
|
||||
break
|
||||
case InputRouter.Down:
|
||||
powerOverlay.moveFocus(1)
|
||||
break
|
||||
case InputRouter.Accept:
|
||||
powerOverlay.activateFocused()
|
||||
break
|
||||
case InputRouter.Back:
|
||||
window.powerOverlayVisible = false
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
pragma Singleton
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
readonly property color backgroundDeep: "#050A17"
|
||||
readonly property color backgroundMid: "#111321"
|
||||
readonly property color backgroundPanel: "#181A2E"
|
||||
|
||||
readonly property color accentCyan: "#4FD8FF"
|
||||
readonly property color accentPurple: "#6F5CFF"
|
||||
readonly property color accentLine: "#30325A"
|
||||
|
||||
readonly property color textPrimary: "#F2F7FF"
|
||||
readonly property color textMuted: "#A8BDD8"
|
||||
|
||||
readonly property int tileWidth: 280
|
||||
readonly property int tileHeight: 160
|
||||
readonly property int tileGap: 20
|
||||
readonly property int topBarHeight: 72
|
||||
readonly property int focusScaleDuration: 180
|
||||
|
||||
readonly property real tileFocusScale: 1.06
|
||||
readonly property real tilePressScale: 0.96
|
||||
|
||||
readonly property font brandFont: Qt.font({
|
||||
family: "Segoe UI",
|
||||
pixelSize: 28,
|
||||
weight: Font.DemiBold
|
||||
})
|
||||
readonly property font titleFont: Qt.font({
|
||||
family: "Segoe UI",
|
||||
pixelSize: 22,
|
||||
weight: Font.DemiBold
|
||||
})
|
||||
readonly property font bodyFont: Qt.font({
|
||||
family: "Segoe UI",
|
||||
pixelSize: 16,
|
||||
weight: Font.Normal
|
||||
})
|
||||
readonly property font metaFont: Qt.font({
|
||||
family: "Segoe UI",
|
||||
pixelSize: 13,
|
||||
weight: Font.Normal
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import QtQuick
|
||||
import Nebula.Bigscreen
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string label: ""
|
||||
property string meta: ""
|
||||
property string iconText: ""
|
||||
property bool focused: false
|
||||
property bool pressed: false
|
||||
|
||||
signal activated()
|
||||
|
||||
implicitWidth: Theme.tileWidth
|
||||
implicitHeight: Theme.tileHeight
|
||||
|
||||
scale: pressed ? Theme.tilePressScale : (focused ? Theme.tileFocusScale : 1.0)
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation { duration: Theme.focusScaleDuration; easing.type: Easing.OutCubic }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: card
|
||||
anchors.fill: parent
|
||||
radius: 14
|
||||
color: Theme.backgroundPanel
|
||||
border.width: focused ? 2 : 1
|
||||
border.color: focused ? Theme.accentCyan : Theme.accentLine
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
visible: focused
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: "#224FD8FF" }
|
||||
GradientStop { position: 1.0; color: "transparent" }
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
spacing: 10
|
||||
|
||||
Text {
|
||||
text: root.iconText
|
||||
font.pixelSize: 36
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.label
|
||||
font: Theme.titleFont
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
Text {
|
||||
text: root.meta
|
||||
font: Theme.metaFont
|
||||
color: Theme.textMuted
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 12
|
||||
height: 3
|
||||
radius: 2
|
||||
color: Theme.accentCyan
|
||||
opacity: focused ? 1.0 : 0.0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: Theme.focusScaleDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: root.activated()
|
||||
onPressed: root.pressed = true
|
||||
onReleased: root.pressed = false
|
||||
onCanceled: root.pressed = false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: "#050A17" }
|
||||
GradientStop { position: 0.55; color: "#0E1630" }
|
||||
GradientStop { position: 1.0; color: "#1A1342" }
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: 48
|
||||
Rectangle {
|
||||
width: (index % 5) + 1
|
||||
height: width
|
||||
radius: width / 2
|
||||
color: index % 3 === 0 ? "#88FFFFFF" : "#44B8D4FF"
|
||||
x: (index * 137) % root.width
|
||||
y: (index * 89) % root.height
|
||||
opacity: 0.35 + (index % 7) * 0.05
|
||||
|
||||
SequentialAnimation on opacity {
|
||||
loops: Animation.Infinite
|
||||
running: true
|
||||
NumberAnimation {
|
||||
from: 0.2
|
||||
to: 0.7
|
||||
duration: 2000 + (index % 5) * 400
|
||||
}
|
||||
NumberAnimation {
|
||||
from: 0.7
|
||||
to: 0.2
|
||||
duration: 2000 + (index % 5) * 400
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
opacity: 0.35
|
||||
gradient: Gradient {
|
||||
orientation: Gradient.Vertical
|
||||
GradientStop { position: 0.0; color: "transparent" }
|
||||
GradientStop { position: 1.0; color: "#CC000000" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Nebula.Bigscreen
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property int focusIndex: 0
|
||||
readonly property var actions: [
|
||||
{ label: "Sleep", meta: "Suspend system" },
|
||||
{ label: "Restart", meta: "Reboot NebulaOS" },
|
||||
{ label: "Shut down", meta: "Power off" },
|
||||
{ label: "Log out", meta: "Return to login" },
|
||||
{ label: "Desktop Mode", meta: "Switch session" },
|
||||
{ label: "Close", meta: "Back to Home" }
|
||||
]
|
||||
|
||||
signal dismissed()
|
||||
signal actionChosen(string actionId)
|
||||
|
||||
anchors.fill: parent
|
||||
color: "#CC050A17"
|
||||
|
||||
Keys.onPressed: function(event) { event.accepted = true }
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
width: Math.min(parent.width - 80, 520)
|
||||
spacing: 12
|
||||
|
||||
Text {
|
||||
text: "Power"
|
||||
font: Theme.brandFont
|
||||
color: Theme.textPrimary
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: root.actions
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 56
|
||||
radius: 10
|
||||
color: index === root.focusIndex ? "#22304A66" : Theme.backgroundPanel
|
||||
border.color: index === root.focusIndex ? Theme.accentCyan : Theme.accentLine
|
||||
border.width: index === root.focusIndex ? 2 : 1
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
|
||||
Text {
|
||||
text: modelData.label
|
||||
font: Theme.titleFont
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
Text {
|
||||
text: modelData.meta
|
||||
font: Theme.metaFont
|
||||
color: Theme.textMuted
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
root.focusIndex = index
|
||||
root.activateFocused()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function moveFocus(delta) {
|
||||
focusIndex = Math.max(0, Math.min(actions.length - 1, focusIndex + delta))
|
||||
}
|
||||
|
||||
function activateFocused() {
|
||||
const labels = ["sleep", "restart", "shutdown", "logout", "desktop", "close"]
|
||||
const id = labels[focusIndex]
|
||||
if (id === "close") {
|
||||
dismissed()
|
||||
} else {
|
||||
actionChosen(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import QtQuick
|
||||
import Nebula.Bigscreen
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var tiles: []
|
||||
property int focusIndex: 0
|
||||
property real accentFocus: 0
|
||||
|
||||
signal tileActivated(int index)
|
||||
|
||||
implicitHeight: Theme.tileHeight + 24
|
||||
|
||||
onFocusIndexChanged: root.accentFocus = focusIndex / Math.max(1, tiles.length - 1)
|
||||
|
||||
Row {
|
||||
id: rail
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 40
|
||||
spacing: Theme.tileGap
|
||||
|
||||
Repeater {
|
||||
model: root.tiles
|
||||
|
||||
AppTile {
|
||||
label: modelData.label
|
||||
meta: modelData.meta
|
||||
iconText: modelData.icon
|
||||
focused: index === root.focusIndex
|
||||
|
||||
onActivated: root.tileActivated(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function moveFocus(delta) {
|
||||
if (tiles.length === 0) {
|
||||
return
|
||||
}
|
||||
const next = Math.max(0, Math.min(tiles.length - 1, focusIndex + delta))
|
||||
focusIndex = next
|
||||
}
|
||||
|
||||
function activateFocused() {
|
||||
if (tiles.length === 0) {
|
||||
return
|
||||
}
|
||||
tileActivated(focusIndex)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Nebula.Bigscreen
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string userName: "Player"
|
||||
property real accentFocus: 0
|
||||
|
||||
implicitHeight: Theme.topBarHeight
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 40
|
||||
anchors.rightMargin: 40
|
||||
spacing: 16
|
||||
|
||||
Text {
|
||||
text: "Nebula OS"
|
||||
font: Theme.brandFont
|
||||
color: Theme.textPrimary
|
||||
style: Text.Outline
|
||||
styleColor: Theme.accentCyan
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Item { Layout.fillWidth: true }
|
||||
|
||||
RowLayout {
|
||||
spacing: 14
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
Rectangle {
|
||||
width: 36
|
||||
height: 36
|
||||
radius: 18
|
||||
color: Theme.backgroundPanel
|
||||
border.color: Theme.accentCyan
|
||||
border.width: 2
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: root.userName.length > 0 ? root.userName.charAt(0).toUpperCase() : "?"
|
||||
font: Theme.titleFont
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: clockLabel
|
||||
font: Theme.bodyFont
|
||||
color: Theme.textMuted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 40 + root.accentFocus * 320
|
||||
width: 120
|
||||
height: 2
|
||||
radius: 1
|
||||
color: Theme.accentCyan
|
||||
opacity: 0.85
|
||||
|
||||
Behavior on anchors.leftMargin {
|
||||
NumberAnimation { duration: Theme.focusScaleDuration; easing.type: Easing.OutCubic }
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 1000
|
||||
running: true
|
||||
repeat: true
|
||||
triggeredOnStart: true
|
||||
onTriggered: clockLabel.text = Qt.formatTime(new Date(), "hh:mm AP")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Nebula.Bigscreen
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property var homeTiles: [
|
||||
{ label: "Library", meta: "Games and apps", icon: "📚", route: "library" },
|
||||
{ label: "Settings", meta: "System controls", icon: "⚙", route: "settings" },
|
||||
{ label: "Power", meta: "Sleep and sessions", icon: "⏻", route: "power" }
|
||||
]
|
||||
|
||||
signal navigate(string route)
|
||||
|
||||
spacing: 28
|
||||
|
||||
Text {
|
||||
text: "Home"
|
||||
font: Theme.brandFont
|
||||
color: Theme.textPrimary
|
||||
Layout.leftMargin: 40
|
||||
}
|
||||
|
||||
TileRail {
|
||||
id: rail
|
||||
Layout.fillWidth: true
|
||||
tiles: root.homeTiles
|
||||
|
||||
onTileActivated: function(index) {
|
||||
const route = root.homeTiles[index].route
|
||||
if (route === "power") {
|
||||
root.navigate("power")
|
||||
} else {
|
||||
root.navigate(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleInput(action) {
|
||||
switch (action) {
|
||||
case InputRouter.Left:
|
||||
rail.moveFocus(-1)
|
||||
break
|
||||
case InputRouter.Right:
|
||||
rail.moveFocus(1)
|
||||
break
|
||||
case InputRouter.Accept:
|
||||
rail.activateFocused()
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
function accentFocus() {
|
||||
return rail.accentFocus
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Nebula.Bigscreen
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
signal goBack()
|
||||
|
||||
readonly property var entries: [
|
||||
{ title: "Nebula Demo", meta: "Local • Ready", icon: "🎮" },
|
||||
{ title: "Retro Runner", meta: "Wine • Installed", icon: "👾" },
|
||||
{ title: "Media Hub", meta: "App • Installed", icon: "🎬" }
|
||||
]
|
||||
|
||||
property int focusIndex: 0
|
||||
|
||||
spacing: 20
|
||||
|
||||
Text {
|
||||
text: "Library"
|
||||
font: Theme.brandFont
|
||||
color: Theme.textPrimary
|
||||
Layout.leftMargin: 40
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Mock entries for v0 — scanners and launchers come later."
|
||||
font: Theme.metaFont
|
||||
color: Theme.textMuted
|
||||
Layout.leftMargin: 40
|
||||
Layout.bottomMargin: 8
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: list
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: 40
|
||||
Layout.rightMargin: 40
|
||||
clip: true
|
||||
spacing: 12
|
||||
model: root.entries
|
||||
|
||||
delegate: Rectangle {
|
||||
width: list.width
|
||||
height: 72
|
||||
radius: 12
|
||||
color: index === root.focusIndex ? "#22304A66" : Theme.backgroundPanel
|
||||
border.color: index === root.focusIndex ? Theme.accentCyan : Theme.accentLine
|
||||
border.width: index === root.focusIndex ? 2 : 1
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 16
|
||||
|
||||
Text {
|
||||
text: modelData.icon
|
||||
font.pixelSize: 28
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
Text {
|
||||
text: modelData.title
|
||||
font: Theme.titleFont
|
||||
color: Theme.textPrimary
|
||||
}
|
||||
Text {
|
||||
text: modelData.meta
|
||||
font: Theme.metaFont
|
||||
color: Theme.textMuted
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleInput(action) {
|
||||
switch (action) {
|
||||
case InputRouter.Up:
|
||||
focusIndex = Math.max(0, focusIndex - 1)
|
||||
list.currentIndex = focusIndex
|
||||
break
|
||||
case InputRouter.Down:
|
||||
focusIndex = Math.min(entries.length - 1, focusIndex + 1)
|
||||
list.currentIndex = focusIndex
|
||||
break
|
||||
case InputRouter.Back:
|
||||
root.goBack()
|
||||
break
|
||||
case InputRouter.Accept:
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
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
|
||||
|
||||
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: 3
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleInput(action) {
|
||||
switch (action) {
|
||||
case InputRouter.Left:
|
||||
categoryIndex = Math.max(0, categoryIndex - 1)
|
||||
break
|
||||
case InputRouter.Right:
|
||||
categoryIndex = Math.min(categories.length - 1, categoryIndex + 1)
|
||||
break
|
||||
case InputRouter.Up:
|
||||
itemIndex = Math.max(0, itemIndex - 1)
|
||||
break
|
||||
case InputRouter.Down:
|
||||
itemIndex = Math.min(2, itemIndex + 1)
|
||||
break
|
||||
case InputRouter.Back:
|
||||
root.goBack()
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user