Rename to TNCat, add chip chase, G-codes and a Wayland layout

The project is now TNCat, after HEIDENHAIN's TNC controls. Binary, QML module
URI, settings path, bundle id and .desktop entry follow; the environment
switches are TNCAT_*.

Entertainment: a curled steel chip skitters in every minute or two, the cat
runs it down and bats it away a few times before sitting back looking pleased.
Mood changes flash the matching machine code above its head, G00 for a sprint,
G01 for a stroll, M08 while it washes, G28 for a stretch, M30 for a nap.

Window handling was split into two layouts. X11 and macOS keep one small window
per object, positioned by the app. Wayland gets a screen-filling overlay whose
input region is masked down to the cat, since a Wayland client cannot place its
own window. Overlay mode is automatic there and available elsewhere via
TNCAT_OVERLAY=1.

Also adds a ground-line setting so the cat can walk above a softkey row.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
JulianandClaude Opus 5 committed 2026-09-10 22:53:40 +02:00
1 parent acef398f49
commit 0f1df75a1d
19 files changed
+817 -185

No files matched your search

+69 -6
View File
@@ -13,6 +13,16 @@ Item {
property bool lifted: false
property bool petted: false
property point look: Qt.point(0, 0)
property bool showCodes: true
// The cat announces what it is doing in the machine's own language.
readonly property string moodCode: mood === "running" || mood === "chasing" ? "G00"
: mood === "walking" ? "G01"
: mood === "sitting" ? "M00"
: mood === "grooming" ? "M08"
: mood === "stretching" ? "G28"
: mood === "sleeping" ? "M30"
: ""
readonly property bool dark: coat.hslLightness < 0.45
readonly property color coatShade: Qt.darker(coat, 1.12)
@@ -23,7 +33,7 @@ Item {
readonly property color blush: "#f77d95"
readonly property bool walking: mood === "walking"
readonly property bool running: mood === "running"
readonly property bool running: mood === "running" || mood === "chasing"
readonly property bool moving: (walking || running) && !lifted
readonly property bool sleeping: mood === "sleeping"
readonly property bool happy: mood === "loving" || mood === "grooming" || mood === "stretching" || petted
@@ -299,8 +309,8 @@ Item {
id: eyeBall
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width: eye.width * (cat.mood === "alert" ? 1.15 : 1)
height: eye.height * eye.open * (cat.mood === "alert" ? 1.15 : 1)
width: eye.width * (cat.mood === "alert" || cat.mood === "batting" ? 1.15 : 1)
height: eye.height * eye.open * (cat.mood === "alert" || cat.mood === "batting" ? 1.15 : 1)
radius: width / 2
color: cat.eyeColor
visible: eye.open > 0.08
@@ -449,14 +459,17 @@ Item {
// speech bubble: "!" / "z" / "♥"
Text {
id: bubble
readonly property string glyph: cat.mood === "alert" ? "!" : cat.sleeping ? "z" : (cat.mood === "loving" || cat.petted) ? "♥" : ""
readonly property string glyph: cat.mood === "alert" || cat.mood === "batting" ? "!"
: cat.sleeping ? "z"
: (cat.mood === "loving" || cat.petted) ? "♥" : ""
x: 82; y: 4
text: glyph
visible: glyph.length > 0
font.pixelSize: cat.mood === "alert" ? 22 : 16
font.pixelSize: cat.mood === "alert" || cat.mood === "batting" ? 22 : 16
font.bold: true
font.family: "Helvetica Neue"
color: cat.mood === "alert" ? "#f2a33c" : (glyph === "♥" ? "#f25f7a" : cat.ink)
color: cat.mood === "alert" || cat.mood === "batting" ? "#f2a33c"
: (glyph === "♥" ? "#ff5b7f" : cat.ink)
transform: Scale { xScale: cat.facingRight ? 1 : -1; origin.x: bubble.width / 2 }
Accessible.ignored: true
@@ -474,6 +487,50 @@ Item {
}
}
// Machine code tag above the head, flashed whenever the mood changes
Item {
id: codeTag
x: 30; y: 2
width: codeBg.width
height: codeBg.height
opacity: 0
visible: cat.showCodes && opacity > 0.01
transformOrigin: Item.Center
transform: Scale { xScale: cat.facingRight ? 1 : -1; origin.x: codeTag.width / 2 }
z: 10
scale: cat.unit
Accessible.ignored: true
Rectangle {
id: codeBg
width: codeText.implicitWidth + 10
height: codeText.implicitHeight + 6
radius: 4
color: "#242833"
opacity: 0.92
antialiasing: true
Text {
id: codeText
anchors.centerIn: parent
text: cat.moodCode
color: "#8fd6ff"
font.pixelSize: 11
font.bold: true
font.family: "Menlo"
}
}
SequentialAnimation {
id: codeFlash
NumberAnimation { target: codeTag; property: "opacity"; to: 1; duration: 160 }
PauseAnimation { duration: 1500 }
NumberAnimation { target: codeTag; property: "opacity"; to: 0; duration: 500 }
}
}
onMoodCodeChanged: if (showCodes && moodCode.length > 0) codeFlash.restart()
states: [
State {
name: "running"
@@ -509,6 +566,12 @@ Item {
PropertyChanges { head.y: 24; head.x: 44; head.rotation: 4 }
PropertyChanges { cat.tailC1X: 24; cat.tailC1Y: 86; cat.tailC2X: 60; cat.tailC2Y: 90; cat.tailX: 76; cat.tailY: 78 }
},
State {
name: "batting"
when: cat.mood === "batting" && !cat.lifted
PropertyChanges { body.rotation: -10; body.x: 26 }
PropertyChanges { head.y: 10; head.x: 50 }
},
State {
name: "lifted"
when: cat.lifted