Replace NTextInput with NComboBox for font settings
FontService: use Qt.fontFamilies to grab available fonts and split Mono fonts NComboBox: allow height changes GeneralTab: replace NTextInput with NComboBox
This commit is contained in:
parent
8d05cb9f3b
commit
520da3e915
4 changed files with 191 additions and 19 deletions
|
|
@ -107,6 +107,9 @@ Singleton {
|
||||||
// Kickoff Matugen service
|
// Kickoff Matugen service
|
||||||
MatugenService.init()
|
MatugenService.init()
|
||||||
|
|
||||||
|
// Kickoff Font service
|
||||||
|
FontService.init()
|
||||||
|
|
||||||
Qt.callLater(function () {
|
Qt.callLater(function () {
|
||||||
validateMonitorConfigurations()
|
validateMonitorConfigurations()
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -158,36 +158,39 @@ ColumnLayout {
|
||||||
spacing: Style.marginL * scaling
|
spacing: Style.marginL * scaling
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|
||||||
NTextInput {
|
NComboBox {
|
||||||
label: "Default Font"
|
label: "Default Font"
|
||||||
description: "Main font used throughout the interface."
|
description: "Main font used throughout the interface."
|
||||||
text: Settings.data.ui.fontDefault
|
model: FontService.availableFonts
|
||||||
placeholderText: "Roboto"
|
currentKey: Settings.data.ui.fontDefault
|
||||||
Layout.fillWidth: true
|
placeholder: "Select default font..."
|
||||||
onEditingFinished: {
|
popupHeight: 420 * scaling
|
||||||
Settings.data.ui.fontDefault = text
|
onSelected: function (key) {
|
||||||
|
Settings.data.ui.fontDefault = key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NTextInput {
|
NComboBox {
|
||||||
label: "Fixed Width Font"
|
label: "Fixed Width Font"
|
||||||
description: "Monospace font used for terminal and code display."
|
description: "Monospace font used for terminal and code display."
|
||||||
text: Settings.data.ui.fontFixed
|
model: FontService.monospaceFonts
|
||||||
placeholderText: "DejaVu Sans Mono"
|
currentKey: Settings.data.ui.fontFixed
|
||||||
Layout.fillWidth: true
|
placeholder: "Select monospace font..."
|
||||||
onEditingFinished: {
|
popupHeight: 320 * scaling
|
||||||
Settings.data.ui.fontFixed = text
|
onSelected: function (key) {
|
||||||
|
Settings.data.ui.fontFixed = key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NTextInput {
|
NComboBox {
|
||||||
label: "Billboard Font"
|
label: "Billboard Font"
|
||||||
description: "Large font used for clocks and prominent displays."
|
description: "Large font used for clocks and prominent displays."
|
||||||
text: Settings.data.ui.fontBillboard
|
model: FontService.displayFonts
|
||||||
placeholderText: "Inter"
|
currentKey: Settings.data.ui.fontBillboard
|
||||||
Layout.fillWidth: true
|
placeholder: "Select display font..."
|
||||||
onEditingFinished: {
|
popupHeight: 320 * scaling
|
||||||
Settings.data.ui.fontBillboard = text
|
onSelected: function (key) {
|
||||||
|
Settings.data.ui.fontBillboard = key
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
165
Services/FontService.qml
Normal file
165
Services/FontService.qml
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import qs.Commons
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property ListModel availableFonts: ListModel {}
|
||||||
|
property ListModel monospaceFonts: ListModel {}
|
||||||
|
property ListModel displayFonts: ListModel {}
|
||||||
|
property bool fontsLoaded: false
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
|
||||||
|
// Fonts will be loaded when init() is called
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
Logger.log("FontService", "Service started")
|
||||||
|
loadSystemFonts()
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSystemFonts() {
|
||||||
|
Logger.log("FontService", "Loading system fonts...")
|
||||||
|
|
||||||
|
var fontFamilies = Qt.fontFamilies()
|
||||||
|
|
||||||
|
availableFonts.clear()
|
||||||
|
monospaceFonts.clear()
|
||||||
|
displayFonts.clear()
|
||||||
|
|
||||||
|
for (var i = 0; i < fontFamilies.length; i++) {
|
||||||
|
var fontName = fontFamilies[i]
|
||||||
|
if (fontName && fontName.trim() !== "") {
|
||||||
|
availableFonts.append({
|
||||||
|
"key": fontName,
|
||||||
|
"name": fontName
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isMonospaceFont(fontName)) {
|
||||||
|
monospaceFonts.append({
|
||||||
|
"key": fontName,
|
||||||
|
"name": fontName
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDisplayFont(fontName)) {
|
||||||
|
displayFonts.append({
|
||||||
|
"key": fontName,
|
||||||
|
"name": fontName
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortModel(availableFonts)
|
||||||
|
sortModel(monospaceFonts)
|
||||||
|
sortModel(displayFonts)
|
||||||
|
|
||||||
|
if (monospaceFonts.count === 0) {
|
||||||
|
Logger.log("FontService", "No monospace fonts detected, adding fallbacks")
|
||||||
|
addFallbackFonts(
|
||||||
|
monospaceFonts,
|
||||||
|
["DejaVu Sans Mono", "Liberation Mono", "Courier New", "Courier", "Monaco", "Consolas", "Lucida Console", "Monaco", "Andale Mono"])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayFonts.count === 0) {
|
||||||
|
Logger.log("FontService", "No display fonts detected, adding fallbacks")
|
||||||
|
addFallbackFonts(
|
||||||
|
displayFonts,
|
||||||
|
["Inter", "Roboto", "Open Sans", "Arial", "Helvetica", "Verdana", "Segoe UI", "SF Pro Display", "Ubuntu", "Noto Sans"])
|
||||||
|
}
|
||||||
|
|
||||||
|
fontsLoaded = true
|
||||||
|
Logger.log("FontService", "Loaded", availableFonts.count, "fonts (", monospaceFonts.count, "monospace,",
|
||||||
|
displayFonts.count, "display)")
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMonospaceFont(fontName) {
|
||||||
|
var patterns = ["mono", "monospace", "fixed", "console", "terminal", "typewriter", "courier", "dejavu", "liberation", "source code", "fira code", "jetbrains", "cascadia", "hack", "inconsolata", "roboto mono", "ubuntu mono", "menlo", "consolas", "monaco", "andale mono"]
|
||||||
|
var lowerFontName = fontName.toLowerCase()
|
||||||
|
|
||||||
|
for (var i = 0; i < patterns.length; i++) {
|
||||||
|
if (lowerFontName.includes(patterns[i]))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var commonFonts = ["DejaVu Sans Mono", "Liberation Mono", "Source Code Pro", "Fira Code", "JetBrains Mono", "Cascadia Code", "Hack", "Inconsolata", "Roboto Mono", "Ubuntu Mono", "Menlo", "Consolas", "Monaco", "Andale Mono", "Courier New", "Courier", "Lucida Console", "Monaco", "MS Gothic", "MS Mincho"]
|
||||||
|
return commonFonts.includes(fontName)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDisplayFont(fontName) {
|
||||||
|
var patterns = ["display", "headline", "title", "hero", "showcase", "brand", "inter", "roboto", "open sans", "lato", "montserrat", "poppins", "raleway", "nunito", "source sans", "ubuntu", "noto sans", "work sans", "dm sans", "manrope", "plus jakarta", "figtree"]
|
||||||
|
var lowerFontName = fontName.toLowerCase()
|
||||||
|
|
||||||
|
for (var i = 0; i < patterns.length; i++) {
|
||||||
|
if (lowerFontName.includes(patterns[i]))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var commonFonts = ["Inter", "Roboto", "Open Sans", "Lato", "Montserrat", "Poppins", "Raleway", "Nunito", "Source Sans Pro", "Ubuntu", "Noto Sans", "Work Sans", "DM Sans", "Manrope", "Plus Jakarta Sans", "Figtree", "SF Pro Display", "Segoe UI", "Arial", "Helvetica", "Verdana"]
|
||||||
|
return commonFonts.includes(fontName)
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortModel(model) {
|
||||||
|
var fontsArray = []
|
||||||
|
for (var i = 0; i < model.count; i++) {
|
||||||
|
fontsArray.push({
|
||||||
|
"key": model.get(i).key,
|
||||||
|
"name": model.get(i).name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fontsArray.sort(function (a, b) {
|
||||||
|
return a.name.localeCompare(b.name)
|
||||||
|
})
|
||||||
|
|
||||||
|
model.clear()
|
||||||
|
for (var j = 0; j < fontsArray.length; j++) {
|
||||||
|
model.append(fontsArray[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFallbackFonts(model, fallbackFonts) {
|
||||||
|
for (var i = 0; i < fallbackFonts.length; i++) {
|
||||||
|
var fontName = fallbackFonts[i]
|
||||||
|
var exists = false
|
||||||
|
for (var j = 0; j < model.count; j++) {
|
||||||
|
if (model.get(j).name === fontName) {
|
||||||
|
exists = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exists) {
|
||||||
|
model.append({
|
||||||
|
"key": fontName,
|
||||||
|
"name": fontName
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortModel(model)
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchFonts(query) {
|
||||||
|
if (!query || query.trim() === "")
|
||||||
|
return availableFonts
|
||||||
|
|
||||||
|
var results = []
|
||||||
|
var lowerQuery = query.toLowerCase()
|
||||||
|
|
||||||
|
for (var i = 0; i < availableFonts.count; i++) {
|
||||||
|
var font = availableFonts.get(i)
|
||||||
|
if (font.name.toLowerCase().includes(lowerQuery)) {
|
||||||
|
results.push(font)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ RowLayout {
|
||||||
|
|
||||||
readonly property real preferredHeight: Style.baseWidgetSize * 1.1 * scaling
|
readonly property real preferredHeight: Style.baseWidgetSize * 1.1 * scaling
|
||||||
property real preferredWidth: 320 * scaling
|
property real preferredWidth: 320 * scaling
|
||||||
|
property real popupHeight: 160 * scaling
|
||||||
|
|
||||||
property string label: ""
|
property string label: ""
|
||||||
property string description: ""
|
property string description: ""
|
||||||
|
|
@ -86,7 +87,7 @@ RowLayout {
|
||||||
popup: Popup {
|
popup: Popup {
|
||||||
y: combo.height
|
y: combo.height
|
||||||
width: combo.width
|
width: combo.width
|
||||||
implicitHeight: Math.min(160 * scaling, contentItem.implicitHeight + Style.marginM * scaling * 2)
|
implicitHeight: Math.min(root.popupHeight, contentItem.implicitHeight + Style.marginM * scaling * 2)
|
||||||
padding: Style.marginM * scaling
|
padding: Style.marginM * scaling
|
||||||
|
|
||||||
contentItem: ListView {
|
contentItem: ListView {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue