Shortcuts you invent, rules you write, gestures you own - all still just data

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-25 01:51:59 -04:00
parent f9e5d3f470
commit 06c53d6c21
48 changed files with 4749 additions and 140 deletions
@@ -16,6 +16,109 @@ SettingsPage {
title: "Tiling"
lede: "How windows share the space, and where their edges are."
// The rule being edited, or null while the editor is closed. Held here
// rather than in the editor so that opening one row's Edit closes another's.
property var editingRule: null
property bool addingRule: false
readonly property bool ruleEditorOpen: root.addingRule || root.editingRule !== null
function closeRuleEditor(): void {
root.addingRule = false;
root.editingRule = null;
}
// Per-application behavior, above the general tiling settings: a rule for
// one application is what somebody came here to write, and the gaps and
// borders below are set once and left alone.
SettingsCard {
title: "App rules"
subtitle: "How specific applications behave when they open. Behaviors, not regexes: pick an application, tick what it should do. Panama's own surfaces cannot be matched."
Repeater {
id: ruleRows
model: WindowRules.rules
WindowRuleRow {
id: ruleRow
required property var modelData
required property int index
rule: ruleRow.modelData
divider: ruleRow.index < ruleRows.count - 1
onEditRequested: {
root.addingRule = false;
root.editingRule = ruleRow.modelData;
ruleEditor.load(ruleRow.modelData);
}
onRemoveRequested: {
if (root.editingRule === ruleRow.modelData)
root.closeRuleEditor();
WindowRules.removeRule(String(ruleRow.modelData.class ?? ""));
}
}
}
Text {
width: parent.width
visible: WindowRules.rules.length === 0 && !root.ruleEditorOpen
text: "No rules yet. Every application opens the way the compositor decides."
color: Theme.fgMuted
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
topPadding: 10
bottomPadding: 10
}
WindowRuleEditor {
id: ruleEditor
width: parent.width
visible: root.ruleEditorOpen
onCommitted: rule => {
const saved = root.editingRule === null
? WindowRules.addRule(rule)
: WindowRules.updateRule(String(root.editingRule.class ?? ""), rule);
if (saved)
root.closeRuleEditor();
}
onCanceled: root.closeRuleEditor()
}
SettingRow {
visible: !root.ruleEditorOpen
label: "Add a rule"
detail: WindowRules.rules.length === 0
? "Applies on save, with a compositor reload"
: (WindowRules.applied
? "Applied on the last reload — Hyprland publishes no rule listing, so this is the reload's word, not a read-back of the rules themselves"
: "Saved, waiting on the reload that puts it in effect")
controlWidth: 130
divider: false
SettingsButton {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
tone: "accent"
text: " Add a rule"
enabled: !WindowRules.reloading
onClicked: {
root.editingRule = null;
ruleEditor.reset();
root.addingRule = true;
}
}
}
ErrorRow { message: WindowRules.lastError }
}
SettingsCard {
title: "Window layout"
subtitle: "Follows the Forge mental model, with native Hyprland tiling."