// 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." WallpaperControls { id: wallpaperControls width: parent.width } WallpaperPicker { id: wallpapers width: parent.width mode: wallpaperControls.mode selectedOutput: wallpaperControls.selectedOutput } 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) } } }