// Copyright (C) 2026 Danilo M. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. import QtQuick import "../.." import "Fonts.js" as F // The base size, then a row per system and per section entry: what it is, // its size in its own unit and in px, and a switch to give it its own size // instead of following the base (or, inside rofi and hyprlock, its share of // the section's size). Edits are a draft until Save. Column { id: page required property QtObject fonts readonly property var m: page.fonts.draft readonly property real minPx: 8 readonly property real maxPx: 160 spacing: 8 function clamp(px) { return Math.max(page.minPx, Math.min(page.maxPx, px)); } // A step of 1 in the row's own unit, so a pt row moves by whole points. function step(px, unit, d) { return page.clamp(unit === "pt" ? F.toPx(Math.round(F.toPt(px)) + d) : Math.round(px) + d); } component Small: Text { color: Theme.subtext font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } wrapMode: Text.Wrap } component Heading: Text { topPadding: 10 color: Theme.text font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 1; bold: true } } // One column of the stepper: px always first, pt second, so every row // lines up; the unit the system's config is written in is the bright one. component Unit: Text { property bool own: false width: 72 anchors.verticalCenter: parent.verticalCenter horizontalAlignment: Text.AlignRight color: own ? Theme.accent : Theme.subtext font { family: Theme.iconFamily; pixelSize: Theme.fontSize - 3; bold: own } } // − px pt +, the system's own unit highlighted. component Stepper: Row { id: st property real px: 16 property string unit: "px" property bool enabled: true signal changed(real px) spacing: 6 opacity: st.enabled ? 1 : 0.45 Button { text: "−"; enabled: st.enabled; onClicked: st.changed(page.step(st.px, st.unit, -1)) } Unit { text: F.round(st.px) + " px"; own: st.unit === "px" } Unit { text: F.round(F.toPt(st.px)) + " pt"; own: st.unit === "pt" } Button { text: "+"; enabled: st.enabled; onClicked: st.changed(page.step(st.px, st.unit, 1)) } } // A system or a section entry. id is its override key; inherited is the // size it has when it follows. component SizeRow: Item { id: sr required property string key required property string title property string detail: "" property string unit: "px" required property real inherited property string follows: "base" readonly property bool own: page.m.override[sr.key] !== undefined readonly property real px: sr.own ? page.m.override[sr.key] : sr.inherited objectName: "font:" + sr.key width: page.width height: Math.max(48, texts.implicitHeight + 12) Column { id: texts anchors { left: parent.left; leftMargin: 8; right: controls.left; rightMargin: 12; verticalCenter: parent.verticalCenter } Text { width: parent.width text: sr.title color: Theme.text elide: Text.ElideRight font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 2 } } Small { width: parent.width; visible: sr.detail !== ""; text: sr.detail } } Row { id: controls anchors { right: parent.right; rightMargin: 8; verticalCenter: parent.verticalCenter } spacing: 12 Small { anchors.verticalCenter: parent.verticalCenter wrapMode: Text.NoWrap text: sr.own ? "own size" : "follows " + sr.follows } Switch { anchors.verticalCenter: parent.verticalCenter checked: sr.own onToggled: on => page.fonts.setOverride(sr.key, on ? F.round(sr.inherited) : null) } Stepper { anchors.verticalCenter: parent.verticalCenter px: sr.px unit: sr.unit enabled: sr.own onChanged: px => page.fonts.setOverride(sr.key, px) } } } Small { width: parent.width text: "One size for the whole desktop, in pixels. At scale 1 a point is 4/3 of a pixel (96 dpi), so 16 px is 12 pt. " + "A system with its own size keeps it when the base moves." } Item { objectName: "font:base" width: parent.width height: 48 Text { anchors { left: parent.left; leftMargin: 8; verticalCenter: parent.verticalCenter } text: "Base size" color: Theme.text font { family: Theme.fontFamily; pixelSize: Theme.fontSize; bold: true } } Stepper { anchors { right: parent.right; rightMargin: 8; verticalCenter: parent.verticalCenter } px: page.m.base onChanged: px => page.fonts.setBase(px) } } Heading { text: "Systems" } Repeater { model: F.SYSTEMS.filter(s => s.id !== "groupbar") SizeRow { required property var modelData key: modelData.id title: modelData.label detail: modelData.where + ". Seen " + modelData.when + "." unit: modelData.unit inherited: page.m.base } } Heading { text: "Hyprland groupbar" } SizeRow { key: "groupbar" title: "Group tab titles" detail: "group:groupbar:font_size, a keystone.lua line. Seen at once. Its text_offset is tuned for 14 px." inherited: page.m.base } // rofi and hyprlock: the section's size, which is its body text, then // each entry at its designed ratio to the body. Repeater { model: F.SECTIONS Column { id: sec required property var modelData readonly property var entries: sec.modelData.id === "rofi" ? page.fonts.rofiEntries : page.fonts.hyprlockEntries readonly property real body: sec.entries.length ? Math.min.apply(null, sec.entries.map(e => e.pt)) : 0 width: page.width spacing: 8 Heading { text: sec.modelData.label } Small { x: 8 width: parent.width - 16 visible: sec.entries.length === 0 text: "No sizes found to scale: " + (sec.modelData.id === "rofi" ? "no var(kf-..., \"...\") in ~/.config/rofi/udt." : "no $kf_... = size in ~/.config/hypr/hyprlock.conf.") } SizeRow { visible: sec.entries.length > 0 key: sec.modelData.id title: sec.modelData.label + " body text" detail: "Designed at " + sec.body + " pt; everything below keeps its ratio to it. Seen " + sec.modelData.when + "." unit: "pt" inherited: page.m.base } Repeater { model: sec.entries SizeRow { required property var modelData key: sec.modelData.id + ":" + modelData.name title: modelData.name.replace(/^kf[-_]/, "") detail: (modelData.family ? modelData.family + ", " : "") + "designed " + modelData.pt + " pt" unit: "pt" follows: sec.modelData.label inherited: F.entryPx(page.m, sec.modelData.id, sec.entries, { name: "", pt: modelData.pt }) } } } } }