Skip to content

Instantly share code, notes, and snippets.

View krzyzanowskim's full-sized avatar

Marcin Krzyzanowski krzyzanowskim

View GitHub Profile
@krzyzanowskim
krzyzanowskim / TextKit2.swift
Last active April 7, 2024 13:10
Minimal setup of TextKit2 components to produce PDF document
import Cocoa
let loremIpsum = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque erat risus, laoreet et eros id, lobortis elementum sem. Nullam nec magna massa. Donec gravida felis at odio tincidunt pretium et in orci. Curabitur suscipit porta purus non faucibus. Cras dapibus felis eu enim rutrum, vel aliquet lacus volutpat. Quisque fermentum vulputate dictum. Morbi mattis orci quis dui posuere, id vulputate turpis tempus. Sed vulputate augue at ullamcorper feugiat. Phasellus nec lacus eget sapien congue lacinia vel et nulla. Phasellus sollicitudin gravida dapibus. Donec molestie ullamcorper lacus eu rutrum. Praesent lacinia dignissim dui eu ultricies. Integer in lacus lobortis, porttitor sem eu, tincidunt dolor. Cras dignissim nisl in maximus ullamcorper.
Proin nec vulputate magna. In interdum leo sit amet arcu consequat facilisis. Fusce ut malesuada ante, nec malesuada nisl. Mauris porta velit quis tortor mollis, in suscipit augue efficitur. Praesent eleifend mollis neque, non sempe
@krzyzanowskim
krzyzanowskim / PastelColor.swift
Last active February 10, 2024 10:27
Random pastel colors
struct ContentView: View {
@State var color: Color = .Pastel.random()
var body: some View {
Rectangle()
.foregroundColor(color)
.onTapGesture {
color = .Pastel.random()
}
}
extension StringProtocol {
subscript(_ offset: Int) -> String.Element {
if offset >= 0 {
self[index(startIndex, offsetBy: offset)]
} else {
self[index(endIndex, offsetBy: offset)]
}
}
@krzyzanowskim
krzyzanowskim / StringGetSizeThatFits.swift
Last active November 12, 2023 14:51
Calculate frame of String, that fits given width
// Excerpt from https://github.com/krzyzanowskim/CoreTextWorkshop
// Licence BSD-2 clause
// Marcin Krzyzanowski marcin@krzyzanowskim.com
func getSizeThatFits(_ attributedString: NSAttributedString, maxWidth: CGFloat) -> CGSize {
let framesetter = CTFramesetterCreateWithAttributedString(attributedString)
let rectPath = CGRect(origin: .zero, size: CGSize(width: maxWidth, height: 50000))
let ctFrame = CTFramesetterCreateFrame(framesetter, CFRange(), CGPath(rect: rectPath, transform: nil), nil)
@krzyzanowskim
krzyzanowskim / LineBreakPropose.swift
Last active October 28, 2023 22:45
"given this many pixels and a string with these attributes, tell me the optimal places to do a line break" https://iosdevelopers.slack.com/archives/C1GPPBMHC/p1697470218613869?thread_ts=1697467894.270959&cid=C1GPPBMHC
import Cocoa
/// "given this many pixels and a string with these attributes, tell me the optimal places to do a line break"
class LineBreakPropose: NSObject, NSTextLayoutManagerDelegate {
var lineBreaks: [NSTextLocation] = []
init(_ attributedString: NSAttributedString, in size: CGSize, by lineBreakMode: NSLineBreakMode = .byWordWrapping) {
super.init()
@krzyzanowskim
krzyzanowskim / FB13290979.md
Last active October 21, 2023 16:57
NSTextContainer.lineFragmentPadding does not affect end of the fragment usageBoundsForTextContainer rectangle

I noticed that NSTextContainer.lineFragmentPadding value does not affect the NSTextLayoutManager.usageBoundsForTextContainer rectangle on both sizes.

Documentation of lineFragmentPadding says: "The padding appears at the beginning and end of the line fragment rectangles.", however the value of the usageBoundsForTextContainer does not resize appropriately.

Let's see how a different value of lineFragmentPadding affect the text container rectangle:

for lineFragmentPadding = 5 usageBoundsForTextContainer = (x: 5.0, y: 0.0, width: 66.73828125, height: 14.0)

for lineFragmentPadding = 0

@krzyzanowskim
krzyzanowskim / FB13291926.md
Created October 20, 2023 21:00
FB13291926: NSTextLayoutManager.usageBoundsForTextContainer observer is never trigerred

I noticed that NSTextLayoutManager.usageBoundsForTextContainer is no longer KVO observable, despite being documented as KVO-compliant.. I believe it worked around macOS 13.

var usageBoundsForTextContainerObserver: NSKeyValueObservation?

usageBoundsForTextContainerObserver = textLayoutManager.observe(\.usageBoundsForTextContainer, options: [.new]) { textLayoutManager, change in
    print("never called")
}
// Documentation says:
//
// > Executes the specified block for each range of a particular attribute in the attributed string.
//
// documentation is not correct (or implementation, hard to tell). The block is executed at least once, not matter if particular attribute is or is not present in the attributed string.
import Foundation
import AppKit
/// Attributed string without any attribute, in particular no font attribute set
@krzyzanowskim
krzyzanowskim / reversible-formatstyle.swift
Last active July 21, 2023 14:21
ReversibleFormatStyle - like FormatStyle but reversible, more like Formatter
import Foundation
// like FormatStyle but reversible, more like Formatter
protocol ReversibleFormatStyle<FormatOutput>: FormatStyle {
func format(_ value: FormatOutput) -> FormatInput
}
// Implementation
struct ReversibleNumFormatStyle: ReversibleFormatStyle {
//
// MultilineLabel.swift
//
// Created by Marcin Krzyzanowski on 19/09/2019.
//
import UIKit
public class MultilineLabel: UILabel {
override public init(frame: CGRect) {