diff options
Diffstat (limited to 'desktop/modules/fonts/FontsPage.qml')
| -rw-r--r-- | desktop/modules/fonts/FontsPage.qml | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/desktop/modules/fonts/FontsPage.qml b/desktop/modules/fonts/FontsPage.qml new file mode 100644 index 0000000..fd2e672 --- /dev/null +++ b/desktop/modules/fonts/FontsPage.qml @@ -0,0 +1,212 @@ +// Copyright (C) 2026 Danilo M. <danix@danix.xyz> +// +// 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 }) + } + } + } + } +} |
