345 lines
13 KiB
QML
345 lines
13 KiB
QML
// Appearance — the page the rest of the settings vocabulary was built for.
|
|
//
|
|
// Before Stage 3 this page adjusted a clock format and three vitals toggles,
|
|
// and its "Theme" card was two rows of text pretending to be controls. It now
|
|
// drives the compositor directly: every row here is applied through
|
|
// `hyprctl eval` and confirmed by reading the value back before it is stored.
|
|
//
|
|
// The preview is pinned above the controls rather than sitting inline, because
|
|
// the numbers are meaningless on their own -- "outer gaps 24" only means
|
|
// something once you have watched the windows move apart by that much, at the
|
|
// scale of the display you actually use.
|
|
|
|
import QtQuick
|
|
import qs.config
|
|
import qs.services
|
|
|
|
SettingsPage {
|
|
id: root
|
|
|
|
property string expandedPicker: ""
|
|
|
|
title: "Appearance"
|
|
lede: "Tune the Prism shell and the applications that live inside it. The preview above is your real geometry, to scale."
|
|
|
|
header: Component {
|
|
Column {
|
|
spacing: 9
|
|
|
|
DesktopPreview {
|
|
width: parent.width
|
|
}
|
|
|
|
Text {
|
|
width: parent.width
|
|
horizontalAlignment: Text.AlignHCenter
|
|
text: SystemSettings.lastError !== ""
|
|
? SystemSettings.lastError
|
|
: "Live preview — the focused window wears the prism border"
|
|
color: SystemSettings.lastError !== "" ? Theme.warn : Theme.fgMuted
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
elide: Text.ElideRight
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Background"
|
|
subtitle: Wallpaper.lastError !== ""
|
|
? Wallpaper.lastError
|
|
: "Applied to every display. Looked for in ~/Pictures/Wallpapers, ~/Pictures/Backgrounds, ~/.local/share/backgrounds, and /usr/share/backgrounds."
|
|
|
|
WallpaperPicker {
|
|
id: wallpapers
|
|
width: parent.width
|
|
}
|
|
|
|
ActionRow {
|
|
visible: wallpapers.hidden > 0 || wallpapers.expanded
|
|
label: wallpapers.expanded ? "Showing every image" : wallpapers.hidden + " more available"
|
|
detail: "The grid is kept short so the rest of this page stays reachable"
|
|
action: wallpapers.expanded ? "Show fewer" : "Show all"
|
|
onTriggered: wallpapers.expanded = !wallpapers.expanded
|
|
}
|
|
|
|
ActionRow {
|
|
label: "Look for new images"
|
|
detail: Wallpaper.scanning
|
|
? "Scanning…"
|
|
: Wallpaper.available.length + " image" + (Wallpaper.available.length === 1 ? "" : "s") + " found"
|
|
action: "Rescan"
|
|
divider: false
|
|
enabled: !Wallpaper.scanning
|
|
onTriggered: Wallpaper.rescan()
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Lock screen"
|
|
subtitle: LockScreen.lastError !== ""
|
|
? LockScreen.lastError
|
|
: "A representative preview of the screen shown before authentication."
|
|
|
|
LockScreenPreview {
|
|
width: parent.width
|
|
}
|
|
|
|
ChoiceRow { setting: "lockBackgroundMode" }
|
|
SliderRow { setting: "lockBlurLevel"; zeroLabel: "Off" }
|
|
ToggleRow { setting: "lockShowClock" }
|
|
ToggleRow { setting: "lockShowDate" }
|
|
ToggleRow { setting: "lockShowUser" }
|
|
ToggleRow { setting: "lockFadeOnEmpty"; divider: false }
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Colour scheme"
|
|
subtitle: ColorScheme.lastError !== ""
|
|
? ColorScheme.lastError
|
|
: "Light is Tokyo Night Day, the official light variant — the same hues at a different lightness, so the blue-into-orchid signature survives the switch. Applications and window borders follow."
|
|
|
|
ChoiceRow { setting: "colorScheme"; divider: false }
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Shell typography"
|
|
subtitle: Fonts.lastError !== ""
|
|
? Fonts.lastError
|
|
: "Every piece of text in the shell. Samples are drawn in the font they name."
|
|
|
|
SliderRow { setting: "interfaceFontSize" }
|
|
|
|
TextRow {
|
|
label: "Interface font"
|
|
detail: Fonts.interfaceMissing
|
|
? "Not installed on this machine — fontconfig is substituting something else"
|
|
: "Used for all shell text"
|
|
value: Fonts.interfaceFont
|
|
}
|
|
|
|
FontPicker {
|
|
width: parent.width
|
|
families: Fonts.interfaceFonts
|
|
current: Fonts.interfaceFont
|
|
emptyText: Fonts.scanning ? "Reading installed fonts…" : "No interface fonts found"
|
|
onPicked: family => Fonts.setInterface(family)
|
|
}
|
|
|
|
TextRow {
|
|
label: "Icon font"
|
|
detail: Fonts.iconMissing
|
|
? "Not installed — the shell's glyphs will not draw correctly"
|
|
: "Draws the shell's glyphs, so only Nerd Fonts are offered"
|
|
value: Fonts.iconFont
|
|
}
|
|
|
|
FontPicker {
|
|
width: parent.width
|
|
families: Fonts.iconFonts
|
|
current: Fonts.iconFont
|
|
emptyText: "No Nerd Fonts installed"
|
|
onPicked: family => Fonts.setIcon(family)
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Application typography"
|
|
subtitle: DesktopStyle.lastError !== ""
|
|
? DesktopStyle.lastError
|
|
: "Fonts used by applications that follow the desktop defaults. Open one family at a time to keep the page calm."
|
|
|
|
ActionRow {
|
|
label: "Application font"
|
|
detail: DesktopStyle.applicationFont
|
|
action: root.expandedPicker === "application-font" ? "Close" : "Choose"
|
|
onTriggered: root.expandedPicker = root.expandedPicker === "application-font" ? "" : "application-font"
|
|
}
|
|
|
|
FontPicker {
|
|
visible: root.expandedPicker === "application-font"
|
|
width: parent.width
|
|
families: Fonts.interfaceFonts
|
|
current: DesktopStyle.applicationFont
|
|
emptyText: Fonts.scanning ? "Reading installed fonts…" : "No application fonts found"
|
|
onPicked: family => {
|
|
if (DesktopStyle.setApplicationFont(family))
|
|
root.expandedPicker = "";
|
|
}
|
|
}
|
|
|
|
SliderRow { setting: "applicationFontSize" }
|
|
|
|
ActionRow {
|
|
label: "Document font"
|
|
detail: DesktopStyle.documentFont
|
|
action: root.expandedPicker === "document-font" ? "Close" : "Choose"
|
|
onTriggered: root.expandedPicker = root.expandedPicker === "document-font" ? "" : "document-font"
|
|
}
|
|
|
|
FontPicker {
|
|
visible: root.expandedPicker === "document-font"
|
|
width: parent.width
|
|
families: Fonts.interfaceFonts
|
|
current: DesktopStyle.documentFont
|
|
emptyText: Fonts.scanning ? "Reading installed fonts…" : "No document fonts found"
|
|
onPicked: family => {
|
|
if (DesktopStyle.setDocumentFont(family))
|
|
root.expandedPicker = "";
|
|
}
|
|
}
|
|
|
|
SliderRow { setting: "documentFontSize" }
|
|
|
|
ActionRow {
|
|
label: "Monospace font"
|
|
detail: DesktopStyle.monospaceFont
|
|
action: root.expandedPicker === "monospace-font" ? "Close" : "Choose"
|
|
onTriggered: root.expandedPicker = root.expandedPicker === "monospace-font" ? "" : "monospace-font"
|
|
}
|
|
|
|
FontPicker {
|
|
visible: root.expandedPicker === "monospace-font"
|
|
width: parent.width
|
|
families: Fonts.monospaceFonts
|
|
current: DesktopStyle.monospaceFont
|
|
emptyText: Fonts.scanning ? "Reading installed fonts…" : "No monospace fonts found"
|
|
onPicked: family => {
|
|
if (DesktopStyle.setMonospaceFont(family))
|
|
root.expandedPicker = "";
|
|
}
|
|
}
|
|
|
|
SliderRow { setting: "monospaceFontSize" }
|
|
ChoiceRow { setting: "fontHinting" }
|
|
ChoiceRow { setting: "fontAntialiasing"; divider: false }
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Icons & pointer"
|
|
subtitle: DesktopStyle.lastError !== ""
|
|
? DesktopStyle.lastError
|
|
: "Installed themes only. The pointer updates in applications and Hyprland together."
|
|
|
|
ActionRow {
|
|
label: "Application icons"
|
|
detail: DesktopStyle.iconTheme
|
|
action: root.expandedPicker === "icon-theme" ? "Close" : "Choose"
|
|
enabled: DesktopStyle.catalogLoaded
|
|
onTriggered: root.expandedPicker = root.expandedPicker === "icon-theme" ? "" : "icon-theme"
|
|
}
|
|
|
|
SearchPicker {
|
|
visible: root.expandedPicker === "icon-theme"
|
|
width: parent.width
|
|
items: DesktopStyle.iconThemes
|
|
current: DesktopStyle.iconTheme
|
|
placeholder: "Search icon themes"
|
|
emptyText: DesktopStyle.scanning ? "Reading installed icon themes…" : "No icon themes found"
|
|
onPicked: value => {
|
|
if (DesktopStyle.setIconTheme(value))
|
|
root.expandedPicker = "";
|
|
}
|
|
}
|
|
|
|
ActionRow {
|
|
label: "Pointer theme"
|
|
detail: DesktopStyle.cursorTheme
|
|
action: root.expandedPicker === "cursor-theme" ? "Close" : "Choose"
|
|
enabled: DesktopStyle.catalogLoaded
|
|
divider: false
|
|
onTriggered: root.expandedPicker = root.expandedPicker === "cursor-theme" ? "" : "cursor-theme"
|
|
}
|
|
|
|
SearchPicker {
|
|
visible: root.expandedPicker === "cursor-theme"
|
|
width: parent.width
|
|
items: DesktopStyle.cursorThemes
|
|
current: DesktopStyle.cursorTheme
|
|
placeholder: "Search pointer themes"
|
|
emptyText: DesktopStyle.scanning ? "Reading installed pointer themes…" : "No pointer themes found"
|
|
onPicked: value => {
|
|
if (DesktopStyle.setCursorTheme(value))
|
|
root.expandedPicker = "";
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Titlebars"
|
|
subtitle: "For applications that draw GNOME-compatible titlebars. Hyprland itself does not add titlebar buttons to tiled windows."
|
|
|
|
ChoiceRow { setting: "titlebarButtonSide" }
|
|
ToggleRow { setting: "titlebarMaximizeButton" }
|
|
ChoiceRow { setting: "titlebarDoubleClick"; divider: false }
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Windows"
|
|
subtitle: "Spacing and shape of tiled windows. Each change is applied to the compositor and confirmed before it is saved."
|
|
|
|
SliderRow { setting: "windowRounding" }
|
|
SliderRow { setting: "gapsIn" }
|
|
SliderRow { setting: "gapsOut" }
|
|
SliderRow { setting: "borderSize"; zeroLabel: "None" }
|
|
SliderRow { setting: "roundingPower" }
|
|
SliderRow { setting: "inactiveOpacity" }
|
|
SliderRow { setting: "activeOpacity" }
|
|
SliderRow { setting: "fullscreenOpacity"; divider: false }
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Effects"
|
|
subtitle: "Each of these costs frame time. Turning one off is a legitimate way to buy it back while gaming."
|
|
|
|
ToggleRow { setting: "blurEnabled" }
|
|
SliderRow { setting: "blurSize" }
|
|
SliderRow { setting: "blurPasses" }
|
|
ToggleRow { setting: "shadowEnabled" }
|
|
SliderRow { setting: "shadowRange"; zeroLabel: "None" }
|
|
SliderRow { setting: "shadowRenderPower" }
|
|
ToggleRow { setting: "shadowSharp" }
|
|
ToggleRow { setting: "glowEnabled" }
|
|
SliderRow { setting: "glowRange"; zeroLabel: "None" }
|
|
ToggleRow { setting: "animationsEnabled"; divider: false }
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Clock"
|
|
|
|
ToggleRow { setting: "use24Hour" }
|
|
ToggleRow { setting: "showSeconds" }
|
|
ToggleRow { setting: "showWeekday"; divider: false }
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "System vitals"
|
|
subtitle: "Choose what appears beside the workspace indicator."
|
|
|
|
ToggleRow { setting: "showCpu" }
|
|
ToggleRow { setting: "showMemory" }
|
|
ToggleRow { setting: "showGpu"; divider: true }
|
|
// Refresh interval was on the Home page, which split one concept across
|
|
// two pages -- what the vitals show here, how often they update there.
|
|
SliderRow { setting: "vitalsIntervalMs"; divider: GraphicsDevices.devices.length > 1 || GraphicsDevices.selectionMissing }
|
|
|
|
// Only worth asking when there is a choice to make.
|
|
ChoiceGrid {
|
|
visible: GraphicsDevices.devices.length > 1 || GraphicsDevices.selectionMissing
|
|
width: parent.width
|
|
label: "Graphics device"
|
|
detail: GraphicsDevices.selectionMissing
|
|
? "The stored device is not present on this machine, so the graphics readout is hidden. Choose one below."
|
|
: "Which GPU the graphics readout measures."
|
|
options: GraphicsDevices.devices.map(device => ({
|
|
value: device.path,
|
|
label: GraphicsDevices.shortName(device.name)
|
|
}))
|
|
current: GraphicsDevices.selectedPath
|
|
divider: false
|
|
onPicked: value => GraphicsDevices.select(value)
|
|
}
|
|
}
|
|
|
|
}
|