Skip to content

Commit 5598a15

Browse files
authored
Update TextLayoutProperties (#658)
1 parent 4b4c099 commit 5598a15

File tree

5 files changed

+251
-23
lines changed

5 files changed

+251
-23
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//
2+
// Text+Justification.swift
3+
// OpenSwiftUICore
4+
//
5+
// Audited for 6.5.4
6+
// Status: Complete
7+
// ID: F89CCC57FFF9CABCAC4F565338DE677C (SwiftUICore)
8+
9+
@_spi(Private)
10+
@available(OpenSwiftUI_v5_0, *)
11+
public struct TextJustification: Sendable, Equatable {
12+
struct Full: Equatable {
13+
var allLines: Bool
14+
var flexible: Bool
15+
}
16+
17+
enum Storage: Equatable {
18+
case full(Full)
19+
case none
20+
}
21+
22+
var storage: Storage
23+
24+
public static let none: TextJustification = .init(storage: .none)
25+
26+
public static let full: TextJustification = .full()
27+
28+
public static let stretched: TextJustification = .stretched(true)
29+
30+
public static func stretched(_ flexible: Bool = true) -> TextJustification {
31+
.full(allLines: true, flexible: flexible)
32+
}
33+
34+
public static func full(
35+
allLines: Bool = false,
36+
flexible: Bool = false
37+
) -> TextJustification {
38+
.init(storage: .full(.init(allLines: allLines, flexible: flexible)))
39+
}
40+
}
41+
42+
private struct TextJustificationKey: EnvironmentKey {
43+
static let defaultValue: TextJustification = .none
44+
}
45+
46+
extension EnvironmentValues {
47+
var textJustification: TextJustification {
48+
get { self[TextJustificationKey.self] }
49+
set { self[TextJustificationKey.self] = newValue }
50+
}
51+
}
52+
53+
@_spi(Private)
54+
@available(OpenSwiftUI_v5_0, *)
55+
extension View {
56+
57+
@available(OpenSwiftUI_v5_0, *)
58+
nonisolated public func justification(_ justfication: TextJustification) -> some View {
59+
environment(\.textJustification, justfication)
60+
}
61+
}

Sources/OpenSwiftUICore/View/Text/Text/Text+LayoutShape.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,7 @@ package struct TextShape: Equatable {
104104
)
105105
}
106106
}
107+
108+
extension EnvironmentValues {
109+
@Entry var textShape: TextShape = .bounds
110+
}

Sources/OpenSwiftUICore/View/Text/Text/Text+Sizing.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,46 @@
66
// Status: Complete
77
// ID: 22747AAF70EE5063D02F299CE90A18BE (SwiftUICore)
88

9+
// MARK: TextSizingModifier
10+
11+
protocol TextSizingModifier: Equatable {
12+
func updateLayoutMargins(_ margins: inout EdgeInsets)
13+
}
14+
15+
class AnyTextSizingModifier: Equatable, TextSizingModifier, @unchecked Sendable {
16+
static func == (lhs: AnyTextSizingModifier, rhs: AnyTextSizingModifier) -> Bool {
17+
lhs.isEqual(to: rhs)
18+
}
19+
20+
func updateLayoutMargins(_ margins: inout EdgeInsets) {
21+
_openSwiftUIBaseClassAbstractMethod()
22+
}
23+
24+
func isEqual(to other: AnyTextSizingModifier) -> Bool {
25+
_openSwiftUIBaseClassAbstractMethod()
26+
}
27+
}
28+
29+
private class ConcreteTextSizingModifier<M>: AnyTextSizingModifier, @unchecked Sendable where M: TextSizingModifier {
30+
let modifier: M
31+
32+
init(modifier: M) {
33+
self.modifier = modifier
34+
}
35+
36+
override func updateLayoutMargins(_ margins: inout EdgeInsets) {
37+
modifier.updateLayoutMargins(&margins)
38+
}
39+
40+
override func isEqual(to other: AnyTextSizingModifier) -> Bool {
41+
guard let other = other as? ConcreteTextSizingModifier else {
42+
return false
43+
}
44+
return modifier == other.modifier
45+
}
46+
}
47+
48+
949
// MARK: - Text + Sizing
1050

1151
@_spi(Private)
@@ -22,6 +62,8 @@ extension Text {
2262

2363
package var storage: Text.Sizing.Storage
2464

65+
private var modifiers: [AnyTextSizingModifier] = []
66+
2567
package init(_ storage: Text.Sizing.Storage) {
2668
self.storage = storage
2769
}
@@ -34,6 +76,16 @@ extension Text {
3476
}
3577
}
3678

79+
//extension Text.Sizing {
80+
// func layoutMargins(
81+
// for: NSAttributedString,
82+
// metrics: inout NSAttributedString.EncodedFontMetrics?
83+
// layoutProperties: LayoutProperties
84+
// ) {
85+
// _openSwiftUIUnimplementedFailure()
86+
// }
87+
//}
88+
3789
private struct TextSizingKey: EnvironmentKey {
3890
static let defaultValue: Text.Sizing = .standard
3991
}

Sources/OpenSwiftUICore/View/Text/Text/Text+View.swift

Lines changed: 125 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,23 @@ public struct TextLayoutProperties: Equatable {
4545

4646
package var lowerLineLimit: Int?
4747

48-
// public var truncationMode: Text.TruncationMode =
48+
public var truncationMode: Text.TruncationMode = .tail
4949

50-
public var multilineTextAlignment: TextAlignment
50+
public var multilineTextAlignment: TextAlignment = .leading
5151

52-
public var layoutDirection: LayoutDirection
52+
public var layoutDirection: LayoutDirection = .leftToRight
5353

54-
package var transitionStyle: ContentTransition.Style
54+
package var transitionStyle: ContentTransition.Style = .default
5555

5656
public var minScaleFactor: CGFloat = 1.0
5757

5858
public var lineSpacing: CGFloat = .zero
5959

6060
public var lineHeightMultiple: CGFloat = .zero
6161

62-
// public var maximumLineHeight: CGFloat =
62+
public var maximumLineHeight: CGFloat = MaximumLineHeightKey.defaultValue
6363

64-
// public var minimumLineHeight: CGFloat
64+
public var minimumLineHeight: CGFloat = MinimumLineHeightKey.defaultValue
6565

6666
public var hyphenationFactor: CGFloat = .zero
6767

@@ -75,45 +75,119 @@ public struct TextLayoutProperties: Equatable {
7575

7676
package var textSizing: Text.Sizing = .standard
7777

78-
// package var textShape: TextShape
78+
private var textShape: TextShape = .bounds
7979

80-
// package var flags: Flags
80+
private struct Flags: OptionSet {
81+
var rawValue: UInt8
82+
83+
static let widthIsFlexible = Flags(rawValue: 1 << 0)
84+
85+
static let sizeFitting = Flags(rawValue: 1 << 1)
86+
}
87+
88+
private var flags: Flags = []
8189

8290
package var widthIsFlexible: Bool {
83-
get { _openSwiftUIUnimplementedFailure() }
84-
set { _openSwiftUIUnimplementedFailure() }
91+
get { flags.contains(.widthIsFlexible) }
92+
set { flags.setValue(newValue, for: .widthIsFlexible) }
8593
}
8694

8795
package var sizeFitting: Bool {
88-
get { _openSwiftUIUnimplementedFailure() }
89-
set { _openSwiftUIUnimplementedFailure() }
96+
get { flags.contains(.sizeFitting) }
97+
set { flags.setValue(newValue, for: .sizeFitting) }
9098
}
9199

92100
package init() {
93-
_openSwiftUIUnimplementedFailure()
101+
_openSwiftUIEmptyStub()
102+
}
94103

104+
public init(_ env: EnvironmentValues) {
105+
self = env[Key.self]
95106
}
96107

97108
private struct Key: DerivedEnvironmentKey {
98109
static func value(in environment: EnvironmentValues) -> TextLayoutProperties {
99-
// TODO
100-
.init()
110+
TextLayoutProperties(from: environment)
101111
}
102112
}
103113

104-
public init(_ env: EnvironmentValues) {
105-
self = env[Key.self]
114+
init(from env: EnvironmentValues) {
115+
lineLimit = env.lineLimit
116+
lowerLineLimit = env.lowerLineLimit
117+
truncationMode = env.truncationMode
118+
multilineTextAlignment = env.multilineTextAlignment
119+
layoutDirection = env.layoutDirection
120+
transitionStyle = env.contentTransitionStyle
121+
minScaleFactor = env.minimumScaleFactor
122+
lineSpacing = env.lineSpacing
123+
lineHeightMultiple = env.lineHeightMultiple
124+
maximumLineHeight = env.maximumLineHeight
125+
minimumLineHeight = env.minimumLineHeight
126+
hyphenationFactor = env.hyphenationFactor
127+
hyphenationDisabled = env.hyphenationDisabled
128+
writingMode = env.writingMode
129+
bodyHeadOutdent = env.bodyHeadOutdent
130+
pixelLength = env.pixelLength
131+
textSizing = env.textSizing
132+
textShape = env.textShape
133+
widthIsFlexible = switch env.textJustification.storage {
134+
case .full(let full): full.flexible
135+
case .none: false
136+
}
106137
}
107138

108139
package func update(
109140
_ env: inout EnvironmentValues,
110141
from old: TextLayoutProperties
111142
) {
112-
_openSwiftUIUnimplementedFailure()
113-
}
114-
115-
public static func == (a: TextLayoutProperties, b: TextLayoutProperties) -> Bool {
116-
_openSwiftUIUnimplementedFailure()
143+
if lineLimit != old.lineLimit {
144+
env.lineLimit = lineLimit
145+
}
146+
if lowerLineLimit != old.lowerLineLimit {
147+
env.lowerLineLimit = lowerLineLimit
148+
}
149+
if truncationMode != old.truncationMode {
150+
env.truncationMode = truncationMode
151+
}
152+
if multilineTextAlignment != old.multilineTextAlignment {
153+
env.multilineTextAlignment = multilineTextAlignment
154+
}
155+
if layoutDirection != old.layoutDirection {
156+
env.layoutDirection = layoutDirection
157+
}
158+
if minScaleFactor != old.minScaleFactor {
159+
env.minimumScaleFactor = minScaleFactor
160+
}
161+
if lineSpacing != old.lineSpacing {
162+
env.lineSpacing = lineSpacing
163+
}
164+
if lineHeightMultiple != old.lineHeightMultiple {
165+
env.lineHeightMultiple = lineHeightMultiple
166+
}
167+
if maximumLineHeight != old.maximumLineHeight {
168+
env.maximumLineHeight = maximumLineHeight
169+
}
170+
if minimumLineHeight != old.minimumLineHeight {
171+
env.minimumLineHeight = minimumLineHeight
172+
}
173+
if hyphenationFactor != old.hyphenationFactor {
174+
env.hyphenationFactor = hyphenationFactor
175+
}
176+
if hyphenationDisabled != old.hyphenationDisabled {
177+
env.hyphenationDisabled = hyphenationDisabled
178+
}
179+
if transitionStyle != old.transitionStyle {
180+
env.contentTransitionStyle = transitionStyle
181+
}
182+
if textSizing != old.textSizing {
183+
env.textSizing = textSizing
184+
}
185+
if writingMode != old.writingMode {
186+
env.writingMode = writingMode
187+
}
188+
if textShape != old.textShape {
189+
env.textShape = textShape
190+
}
117191
}
118192
}
119193

@@ -132,7 +206,6 @@ extension TextLayoutProperties: ProtobufMessage {
132206
}
133207
}
134208

135-
136209
// MARK: - ResolvedTextFilter [WIP]
137210

138211
struct ResolvedTextFilter: StatefulRule, AsyncAttribute {
@@ -195,3 +268,32 @@ extension ResolvedStyledText {
195268
private struct TextFilter {
196269

197270
}
271+
272+
// FIXME
273+
274+
extension EnvironmentValues {
275+
private struct LineLimitKey: EnvironmentKey {
276+
static var defaultValue: Int? { nil }
277+
}
278+
279+
public var lineLimit: Int? {
280+
get { self[LineLimitKey.self] }
281+
set { self[LineLimitKey.self] = newValue }
282+
}
283+
284+
private struct LowerLineLimitKey: EnvironmentKey {
285+
static var defaultValue: Int? { nil }
286+
}
287+
288+
package var lowerLineLimit: Int? {
289+
get { self[LowerLineLimitKey.self] }
290+
set { self[LowerLineLimitKey.self] = newValue }
291+
}
292+
}
293+
294+
extension EnvironmentValues {
295+
var contentTransitionStyle: ContentTransition.Style {
296+
get { _openSwiftUIUnimplementedFailure() }
297+
set { _openSwiftUIUnimplementedFailure() }
298+
}
299+
}

Sources/OpenSwiftUICore/View/Text/Util/TruncationMode.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,11 @@ extension EnvironmentValues {
248248
set { self[MinimumLineHeightKey.self] = newValue }
249249
}
250250

251+
var hyphenationDisabled: Bool {
252+
get { self[HyphenationDisabledKey.self] }
253+
set { self[HyphenationDisabledKey.self] = newValue }
254+
}
255+
251256
@_spi(Private)
252257
@available(OpenSwiftUI_v2_0, *)
253258
public var hyphenationFactor: CGFloat {
@@ -463,6 +468,10 @@ extension View {
463468
environment(\.minimumLineHeight, lineHeight)
464469
}
465470

471+
func hyphenationDisabled(_ flag: Bool) -> some View {
472+
environment(\.hyphenationDisabled, flag)
473+
}
474+
466475
@_spi(Private)
467476
@available(OpenSwiftUI_v2_0, *)
468477
nonisolated public func hyphenationFactor(_ factor: CGFloat) -> some View {

0 commit comments

Comments
 (0)