Files

183 lines
6.8 KiB
QML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Tiling.
//
// How windows share the space. The window-layout card keeps its handoff row
// because the adjustable parts of window *appearance* -- gaps, corners,
// borders, effects -- live on the Appearance page next to the preview that
// explains them. Splitting them would put two halves of one idea on two pages;
// pointing at the other half keeps one.
import QtQuick
import qs.config
import qs.services
SettingsPage {
id: root
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: "Application window 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."
// These were two read-only rows reporting "Tiling" and "Dynamic", which
// described settings rather than facts -- both are ordinary Hyprland
// options that simply had no controls. TextRow's own documentation says
// a setting the user could reasonably change does not belong in it.
ChoiceRow { setting: "windowLayout" }
ToggleRow { setting: "preserveSplit" }
ChoiceRow { setting: "forceSplit" }
ToggleRow { setting: "windowSnapping" }
ActionRow {
label: "Gaps, corners, and effects"
detail: "Adjusted on the Appearance page, beside a live preview"
action: "Open Appearance"
divider: false
onTriggered: ShellState.openSettingsSection("appearance", "windows")
}
}
// GNOME's Multitasking panel, in Hyprland's terms.
// Only meaningful when the layout above is Master and stack. Hidden
// otherwise, because a card of settings that do nothing under the layout
// you are actually running is worse than not offering the layout at all.
SettingsCard {
visible: DesktopPreferences.get("windowLayout") === "master"
title: "Master and stack"
subtitle: "How the master area behaves. These apply only while the tiling layout above is Master and stack."
SliderRow { setting: "masterFactor" }
ChoiceRow { setting: "masterOrientation" }
ChoiceRow { setting: "masterNewStatus" }
ToggleRow { setting: "masterNewOnTop"; divider: false }
}
SettingsCard {
title: "Window edges"
subtitle: "How the pointer grabs a window's border, and how floating windows behave near each other and the screen edge."
ToggleRow { setting: "resizeOnBorder" }
SliderRow { setting: "borderGrabArea"; zeroLabel: "Border only" }
ToggleRow { setting: "hoverIconOnBorder" }
SliderRow { setting: "snapWindowGap"; zeroLabel: "Touching" }
SliderRow { setting: "snapMonitorGap"; zeroLabel: "Touching" }
ToggleRow { setting: "snapRespectGaps"; divider: false }
}
// Hyprland's own interruptions. Panama turns all four off, which is a
// defensible default and was not previously a decision anyone could
// reverse without editing looks.lua.
SettingsCard {
title: "Hyprland notices"
subtitle: "Panama hides all of these by default. They are the compositor's own, not Panama's."
ToggleRow { setting: "hyprlandLogo" }
ToggleRow { setting: "hyprlandSplash" }
ToggleRow { setting: "hyprlandUpdateNews" }
ToggleRow { setting: "hyprlandDonationNag"; divider: false }
}
}