Files
byre/mac/Sources/Byre/Fonts.swift
T

85 lines
2.9 KiB
Swift
Raw Normal View History

import CoreText
2026-10-20 19:32:27 -07:00
import Foundation
import Synchronization
2026-10-20 19:32:27 -07:00
import SwiftData
import SwiftUI
2026-10-20 19:32:27 -07:00
@MainActor
@Observable
final class FontSize {
static let shared = FontSize()
static let range = 9...20
private(set) var body = PrefsRecord.defaultFontSize
2026-10-21 10:15:26 -07:00
private(set) var code = PrefsRecord.defaultFontSize
2026-10-20 19:32:27 -07:00
private init() {
load()
}
func load() {
2026-10-21 10:15:26 -07:00
let r = record()
body = r?.fontSize ?? PrefsRecord.defaultFontSize
code = r?.codeFontSize ?? PrefsRecord.defaultFontSize
2026-10-20 19:32:27 -07:00
}
2026-10-21 10:15:26 -07:00
func set(body: Int, code: Int) {
2026-10-20 19:32:27 -07:00
if let r = record() {
2026-10-21 10:15:26 -07:00
r.fontSize = body
r.codeFontSize = code
2026-10-20 19:32:27 -07:00
r.saved = Date()
} else {
2026-10-21 10:15:26 -07:00
persistence.insert(PrefsRecord(fontSize: body, codeFontSize: code))
2026-10-20 19:32:27 -07:00
}
saveRecords()
2026-10-21 10:15:26 -07:00
self.body = body
self.code = code
2026-10-20 19:32:27 -07:00
}
private func record() -> PrefsRecord? {
fetchRecords(FetchDescriptor<PrefsRecord>(sortBy: [SortDescriptor(\.saved, order: .reverse)])).first
}
}
enum Fonts {
private static func file(_ family: String, _ subset: String, _ italic: Bool, _ weight: CGFloat) -> CTFontDescriptor {
let url = Bundle.main.resourceURL!.appending(path: "fonts/atkinson-hyperlegible-\(family)-\(subset)-wght-\(italic ? "italic" : "normal").woff2")
2026-10-18 00:31:46 -07:00
let d = (CTFontManagerCreateFontDescriptorsFromURL(url as CFURL) as! [CTFontDescriptor])[0]
return CTFontDescriptorCreateCopyWithVariation(d, 0x7767_6874 as CFNumber, weight)
}
private static func ct(_ size: CGFloat, weight: CGFloat, italic: Bool, mono: Bool) -> CTFont {
let family = mono ? "mono" : "next"
let ext = file(family, "latin-ext", italic, weight)
let d = CTFontDescriptorCreateCopyWithAttributes(file(family, "latin", italic, weight), [kCTFontCascadeListAttribute: [ext]] as CFDictionary)
return CTFontCreateWithFontDescriptor(d, size, nil)
}
private static let fonts = Mutex<[String: CTFont]>([:])
2026-10-16 23:30:57 -07:00
2026-10-21 10:15:26 -07:00
// Call sites give sizes relative to a 13pt body; the user's text or code size shifts them.
2026-10-20 19:32:27 -07:00
@MainActor
private static func cached(_ size: CGFloat, _ weight: CGFloat, _ italic: Bool, _ mono: Bool) -> CTFont {
2026-10-21 10:15:26 -07:00
let size = size + CGFloat((mono ? FontSize.shared.code : FontSize.shared.body) - 13)
let key = "\(size) \(weight) \(italic) \(mono)"
return fonts.withLock { fonts in
if let f = fonts[key] {
return f
}
let f = ct(size, weight: weight, italic: italic, mono: mono)
fonts[key] = f
2026-10-16 23:30:57 -07:00
return f
}
}
2026-10-17 09:15:50 -07:00
2026-10-20 19:32:27 -07:00
@MainActor
static func font(_ size: CGFloat, weight: CGFloat = 400, italic: Bool = false, mono: Bool = false) -> Font {
Font(cached(size, weight, italic, mono))
2026-10-17 09:15:50 -07:00
}
2026-10-20 19:32:27 -07:00
@MainActor
static func ns(_ size: CGFloat, weight: CGFloat = 400, italic: Bool = false, mono: Bool = false) -> NSFont {
cached(size, weight, italic, mono) as NSFont
2026-10-17 09:15:50 -07:00
}
}