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

+38 -12
View File
@@ -7,10 +7,9 @@
#include <QPointF>
class AppSettings;
class QWindow;
// Drives the cat: wanders along the bottom of the screen, occasionally dashes,
// sits, grooms, stretches or naps, and reacts to petting and dragging.
// Drives the cat: wanders along its ground line, sits, grooms, stretches and
// naps, chases the odd metal chip, and reacts to petting and dragging.
class CatController : public QObject
{
Q_OBJECT
@@ -18,8 +17,9 @@ class CatController : public QObject
QML_UNCREATABLE("Provided by C++")
Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged)
Q_PROPERTY(qreal screenWidth READ screenWidth WRITE setScreenWidth NOTIFY screenWidthChanged)
Q_PROPERTY(qreal stageWidth READ stageWidth WRITE setStageWidth NOTIFY stageWidthChanged)
Q_PROPERTY(qreal catWidth READ catWidth WRITE setCatWidth NOTIFY catWidthChanged)
Q_PROPERTY(QPointF catCenter READ catCenter WRITE setCatCenter NOTIFY catCenterChanged)
Q_PROPERTY(bool facingRight READ facingRight NOTIFY facingRightChanged)
Q_PROPERTY(Mood mood READ mood NOTIFY moodChanged)
Q_PROPERTY(bool paused READ paused WRITE setPaused NOTIFY pausedChanged)
@@ -27,23 +27,29 @@ class CatController : public QObject
Q_PROPERTY(bool hovered READ hovered WRITE setHovered NOTIFY hoveredChanged)
Q_PROPERTY(QPointF look READ look NOTIFY lookChanged)
Q_PROPERTY(bool chipVisible READ chipVisible NOTIFY chipVisibleChanged)
Q_PROPERTY(qreal chipX READ chipX NOTIFY chipXChanged)
Q_PROPERTY(int chipKick READ chipKick NOTIFY chipKickChanged)
public:
enum class Mood { Walking, Running, Sitting, Grooming, Stretching, Sleeping, Loving, Alert };
enum class Mood { Walking, Running, Sitting, Grooming, Stretching, Sleeping, Loving, Alert, Chasing, Batting };
Q_ENUM(Mood)
explicit CatController(AppSettings *settings, QObject *parent = nullptr);
void setWindow(QWindow *window);
qreal x() const { return m_x; }
void setX(qreal x);
qreal screenWidth() const { return m_screenWidth; }
void setScreenWidth(qreal width);
qreal stageWidth() const { return m_stageWidth; }
void setStageWidth(qreal width);
qreal catWidth() const { return m_catWidth; }
void setCatWidth(qreal width);
// Where the cat's face is on the desktop, so the eyes can find the cursor.
QPointF catCenter() const { return m_catCenter; }
void setCatCenter(const QPointF &center);
bool facingRight() const { return m_facingRight; }
Mood mood() const { return m_mood; }
@@ -58,39 +64,54 @@ public:
QPointF look() const { return m_look; }
bool chipVisible() const { return m_chipVisible; }
qreal chipX() const { return m_chipX; }
int chipKick() const { return m_chipKick; }
Q_INVOKABLE void pet();
Q_INVOKABLE void doTrick(Mood mood);
Q_INVOKABLE void tossChip();
signals:
void xChanged();
void screenWidthChanged();
void stageWidthChanged();
void catWidthChanged();
void catCenterChanged();
void facingRightChanged();
void moodChanged();
void pausedChanged();
void draggingChanged();
void hoveredChanged();
void lookChanged();
void chipVisibleChanged();
void chipXChanged();
void chipKickChanged();
private:
void tick();
void trackCursor();
void setMood(Mood mood);
void setFacingRight(bool right);
void setChipX(qreal x);
void pickNextMood();
void holdMood(Mood mood, int ms);
void batChip();
void endChase();
void scheduleChip();
qreal catNose() const;
AppSettings *m_settings;
QWindow *m_window = nullptr;
QTimer m_tickTimer;
QTimer m_moodTimer;
QTimer m_cursorTimer;
QTimer m_chipTimer;
QElapsedTimer m_clock;
qint64 m_lastTickMs = 0;
qreal m_x = 120;
qreal m_screenWidth = 1440;
qreal m_stageWidth = 1440;
qreal m_catWidth = 120;
QPointF m_catCenter;
bool m_facingRight = true;
Mood m_mood = Mood::Walking;
bool m_paused = false;
@@ -98,4 +119,9 @@ private:
bool m_hovered = false;
bool m_frozen = false;
QPointF m_look;
bool m_chipVisible = false;
qreal m_chipX = 0;
int m_chipKick = 0;
int m_batsLeft = 0;
};