The chip window was 60 x 44 with the curl tumbling about its centre. The curl reaches 24.2 units from that pivot once the stroke is counted, so a half height of 22 clipped the top and bottom off it on every turn. The box is now 52 x 58 with the pivot at (26, 33), measured off the actual Bezier curve rather than its control points. The shadow sits at 15.1 below the pivot, which is where the curl comes to rest, so the chip lands on its own shadow instead of floating above it. The endless rotation is gone. Each bat now adds one or two whole turns in the direction it was hit and coasts to a stop, so the resting silhouette is always the same one, the one the shadow was placed under. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
128 lines
3.9 KiB
QML
128 lines
3.9 KiB
QML
pragma ComponentBehavior: Bound
|
|
import QtQuick
|
|
import TNCat
|
|
|
|
// One screen-filling, click-through window that holds the cat and the chip.
|
|
// Wayland does not let a client place its own window, so there the cat moves
|
|
// inside this overlay instead of the window moving across the desktop.
|
|
Window {
|
|
id: win
|
|
|
|
required property CatController cat
|
|
required property AppSettings settings
|
|
|
|
signal settingsRequested()
|
|
|
|
// Fullscreen is a visibility, not a visible flag, so the mode switch has to
|
|
// go through visibility or the two fight each other.
|
|
property bool overlayActive: false
|
|
|
|
readonly property int catW: settings.catSize
|
|
readonly property int catH: Math.round(settings.catSize * CatDefs.aspect)
|
|
readonly property real groundY: height - catH - settings.bottomMargin
|
|
|
|
// Only the cat itself should swallow clicks; everything else falls through.
|
|
function refreshInputRegion() {
|
|
Platform.setInputRegion(win, Qt.rect(Math.round(cat.x), Math.round(groundY), catW, catH))
|
|
}
|
|
|
|
visibility: overlayActive ? Window.FullScreen : Window.Hidden
|
|
color: "transparent"
|
|
flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool
|
|
| Qt.NoDropShadowWindowHint | Qt.WindowDoesNotAcceptFocus
|
|
title: qsTr("TNCat")
|
|
|
|
onOverlayActiveChanged: {
|
|
if (!overlayActive)
|
|
return
|
|
cat.stageWidth = width
|
|
cat.catWidth = catW
|
|
refreshInputRegion()
|
|
}
|
|
onWidthChanged: cat.stageWidth = width
|
|
onCatWChanged: cat.catWidth = catW
|
|
|
|
Binding {
|
|
target: win.cat
|
|
property: "catCenter"
|
|
value: Qt.point(win.x + win.cat.x + win.catW / 2, win.y + win.groundY + win.catH / 2)
|
|
}
|
|
|
|
// Coalesce mask updates: one X11 round trip per frame of walking is plenty.
|
|
Timer {
|
|
interval: 33
|
|
running: win.overlayActive
|
|
repeat: true
|
|
onTriggered: win.refreshInputRegion()
|
|
}
|
|
|
|
Chip {
|
|
x: win.cat.chipX - width / 2
|
|
y: win.height - height - win.settings.bottomMargin
|
|
width: Math.round(win.settings.catSize * 0.46)
|
|
height: Math.round(width * CatDefs.chipAspect)
|
|
visible: win.cat.chipVisible
|
|
spin: win.cat.chipSpin
|
|
|
|
Behavior on x {
|
|
NumberAnimation { duration: 320; easing.type: Easing.OutQuad }
|
|
}
|
|
}
|
|
|
|
Cup {
|
|
x: win.cat.cupX - width / 2
|
|
y: win.height - height - win.settings.bottomMargin
|
|
width: Math.round(win.settings.catSize * 0.38)
|
|
height: Math.round(width * 1.18)
|
|
visible: win.cat.cupVisible
|
|
}
|
|
|
|
Item {
|
|
id: catItem
|
|
x: win.cat.x
|
|
y: win.groundY
|
|
width: win.catW
|
|
height: win.catH
|
|
|
|
Cat {
|
|
anchors.fill: parent
|
|
coat: win.settings.coat
|
|
facingRight: win.cat.facingRight
|
|
mood: CatDefs.mood(win.cat.mood)
|
|
lifted: win.cat.dragging
|
|
petted: win.cat.hovered && !win.cat.dragging
|
|
look: win.cat.look
|
|
showCodes: win.settings.showCodes
|
|
|
|
Accessible.role: Accessible.Button
|
|
Accessible.name: qsTr("TNCat")
|
|
}
|
|
|
|
HoverHandler {
|
|
onHoveredChanged: win.cat.hovered = hovered
|
|
}
|
|
|
|
DragHandler {
|
|
target: null
|
|
onActiveChanged: win.cat.dragging = active
|
|
onCentroidChanged: {
|
|
if (active)
|
|
win.cat.x = Math.max(0, Math.min(win.cat.stageWidth - win.catW,
|
|
catItem.x + centroid.position.x - centroid.pressPosition.x))
|
|
}
|
|
}
|
|
|
|
TapHandler {
|
|
acceptedButtons: Qt.LeftButton
|
|
onTapped: win.cat.pet()
|
|
onDoubleTapped: win.settingsRequested()
|
|
onLongPressed: win.settingsRequested()
|
|
}
|
|
|
|
TapHandler {
|
|
acceptedButtons: Qt.RightButton
|
|
onTapped: win.settingsRequested()
|
|
}
|
|
}
|
|
}
|