Files
TNCcat/qml/SettingsWindow.qml
JulianandClaude Opus 5 0aceb3665d Fix the collapsed cat window on Linux, warn about the compositor
The CatDefs singleton did not resolve on the reporter's Linux build, which
showed up as "property mood of object CatDefs is not a function". The same
lookup failure made CatDefs.aspect undefined, so the cat window's height became
NaN and the cat rendered as a moving line. The mug survived because its height
used a literal ratio.

The singleton is gone rather than repaired, since nothing in it had to be
shared. The mood name now comes from C++, derived from the enum key, so there
is one source of truth instead of a list in QML that had to match. Window sizes
now follow the implicit size of the drawing they contain, so the proportions
live in the one file that defines them.

Also for X11: TNCat now warns, naming Xfce's compositor setting, when its
window comes up without an alpha channel, which is what a missing compositor
looks like and why the mug had a black background. Opaque mode no longer hides
the chip and the mug. TNCAT_DEBUG=1 logs window geometry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 09:33:44 +02:00

293 lines
11 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import TNCat
// Plain Qt Quick: no Controls, no Widgets, no Layouts.
Window {
id: win
required property CatController cat
required property AppSettings settings
readonly property var coats: [
{ name: qsTr("Apricot"), color: "#f4b183" },
{ name: qsTr("Ivory"), color: "#f3ede2" },
{ name: qsTr("Grey"), color: "#a4a6b3" },
{ name: qsTr("Charcoal"), color: "#3c3b46" },
{ name: qsTr("Sage"), color: "#a9bfa0" },
{ name: qsTr("Plum"), color: "#9a7bb0" }
]
readonly property real margin: 22
readonly property real labelWidth: 96
width: 440
// Tall enough for the whole panel, but never taller than the screen; the
// Flickable takes over when it has to be shorter.
height: Math.min(830, Screen.desktopAvailableHeight - 60)
minimumWidth: 380
minimumHeight: 420
title: qsTr("TNCat")
color: "#faf7f2"
flags: Qt.Dialog
Flickable {
id: flick
anchors.fill: parent
contentWidth: width
contentHeight: content.implicitHeight + win.margin * 2
boundsBehavior: Flickable.StopAtBounds
Column {
id: content
x: win.margin
y: win.margin
width: flick.width - win.margin * 2
spacing: 16
// header
Item {
width: parent.width
height: Math.max(96, headerText.implicitHeight)
Loader {
id: preview
width: 106
height: Math.round(width * 106 / 120)
anchors.verticalCenter: parent.verticalCenter
active: win.visible
sourceComponent: Cat {
coat: win.settings.coat
mood: "sitting"
showCodes: false
petted: previewHover.hovered
HoverHandler { id: previewHover }
}
}
Column {
id: headerText
anchors.left: preview.right
anchors.leftMargin: 14
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: 4
Text {
text: qsTr("TNCat")
font.pixelSize: 26
font.bold: true
color: "#2f2a36"
}
Text {
width: headerText.width
wrapMode: Text.WordWrap
text: qsTr("A little cat that wanders along the bottom of your screen. Click to pet it, drag it somewhere else.")
color: "#7a7484"
font.pixelSize: 12
}
}
}
SettingsGroup {
width: parent.width
title: qsTr("COAT")
Flow {
width: parent.width
spacing: 12
Repeater {
model: win.coats
Column {
id: swatch
required property var modelData
readonly property bool selected: Qt.colorEqual(win.settings.coat, modelData.color)
spacing: 4
Rectangle {
width: 40
height: 40
radius: 20
color: swatch.modelData.color
border.width: swatch.selected ? 3 : 1
border.color: swatch.selected ? "#f25f7a" : "#d8d2ca"
antialiasing: true
activeFocusOnTab: true
Accessible.role: Accessible.RadioButton
Accessible.name: swatch.modelData.name
Accessible.checked: swatch.selected
Accessible.onPressAction: win.settings.coat = swatch.modelData.color
TapHandler { onTapped: win.settings.coat = swatch.modelData.color }
Keys.onSpacePressed: win.settings.coat = swatch.modelData.color
}
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: swatch.modelData.name
font.pixelSize: 11
color: "#7a7484"
}
}
}
}
}
SettingsGroup {
width: parent.width
title: qsTr("THE CAT")
spacing: 12
Item {
width: parent.width
height: 26
Text {
id: sizeLabel
anchors.verticalCenter: parent.verticalCenter
width: win.labelWidth
text: qsTr("Size")
color: "#2f2a36"
font.pixelSize: 13
}
AppSlider {
anchors.left: sizeLabel.right
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
from: 72; to: 260; stepSize: 4
value: win.settings.catSize
suffix: qsTr("px")
onMoved: function(v) { win.settings.catSize = v }
}
}
Item {
width: parent.width
height: 26
Text {
id: paceLabel
anchors.verticalCenter: parent.verticalCenter
width: win.labelWidth
text: qsTr("Pace")
color: "#2f2a36"
font.pixelSize: 13
}
AppSlider {
anchors.left: paceLabel.right
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
from: 10; to: 200; stepSize: 5
value: win.settings.walkSpeed
onMoved: function(v) { win.settings.walkSpeed = v }
}
}
Item {
width: parent.width
height: 26
Text {
id: groundLabel
anchors.verticalCenter: parent.verticalCenter
width: win.labelWidth
text: qsTr("Ground line")
color: "#2f2a36"
font.pixelSize: 13
}
AppSlider {
anchors.left: groundLabel.right
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
from: 0; to: 600; stepSize: 10
value: win.settings.bottomMargin
suffix: qsTr("px")
onMoved: function(v) { win.settings.bottomMargin = v }
}
}
Text {
width: parent.width
wrapMode: Text.WordWrap
text: qsTr("The ground line lifts the cat off the bottom edge, so it can walk above a taskbar or a row of softkeys.")
color: "#9b95a3"
font.pixelSize: 11
}
}
SettingsGroup {
width: parent.width
title: qsTr("HABITS")
spacing: 12
AppToggle {
width: parent.width
checked: win.settings.followCursor
text: qsTr("Follow the mouse with its eyes")
onToggled: function(v) { win.settings.followCursor = v }
}
AppToggle {
width: parent.width
checked: win.settings.showCodes
text: qsTr("Announce what it does in G-code")
onToggled: function(v) { win.settings.showCodes = v }
}
AppToggle {
width: parent.width
checked: win.settings.chipsEnabled
text: qsTr("Chase a chip now and then")
onToggled: function(v) { win.settings.chipsEnabled = v }
}
AppToggle {
width: parent.width
checked: win.settings.coffeeEnabled
text: qsTr("Stop for coffee now and then")
onToggled: function(v) { win.settings.coffeeEnabled = v }
}
AppToggle {
width: parent.width
checked: win.cat.paused
text: win.cat.paused ? qsTr("Napping, nothing will wake it") : qsTr("Awake and on the move")
onToggled: function(v) { win.cat.paused = v }
}
}
SettingsGroup {
width: parent.width
title: qsTr("TRICKS")
Flow {
width: parent.width
spacing: 8
AppButton { text: qsTr("Sit"); onClicked: win.cat.doTrick(CatController.Sitting) }
AppButton { text: qsTr("Groom"); onClicked: win.cat.doTrick(CatController.Grooming) }
AppButton { text: qsTr("Stretch"); onClicked: win.cat.doTrick(CatController.Stretching) }
AppButton { text: qsTr("Dash"); onClicked: win.cat.doTrick(CatController.Running) }
AppButton { text: qsTr("Nap"); onClicked: win.cat.doTrick(CatController.Sleeping) }
AppButton { text: qsTr("Chip"); onClicked: win.cat.tossChip() }
AppButton { text: qsTr("Coffee"); onClicked: win.cat.coffeeBreak() }
}
}
Item {
width: parent.width
height: 34
Text {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
text: qsTr("%n pet(s) so far.", "", win.settings.petCount)
color: "#7a7484"
font.pixelSize: 12
}
AppButton {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Quit")
onClicked: Qt.quit()
}
}
}
}
}