Skip to content

Commit

Permalink
Merge pull request #172 from OpenSwiftUIProject/optimize/layout
Browse files Browse the repository at this point in the history
Update View Layout
  • Loading branch information
Kyle-Ye authored Dec 8, 2024
2 parents 141e356 + 3239212 commit aa1d8a8
Show file tree
Hide file tree
Showing 69 changed files with 2,302 additions and 356 deletions.
2 changes: 1 addition & 1 deletion Sources/OpenSwiftUI/View/Control/Slider/Slider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@ private struct Clamping<Value>: Projection where Value: BinaryFloatingPoint {
}

func set(base: inout Value, newValue: Double) {
base = clamp(Value(newValue), min: 0, max: 1)
base = Value(newValue).clamp(min: 0, max: 1)
}
}

Expand Down
35 changes: 0 additions & 35 deletions Sources/OpenSwiftUICore/Animation/TODO/Animatable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
// Audited for iOS 15.5
// Status: Blocked by Graph

public import Foundation

// MARK: - Animatable

/// A type that describes how to animate a property of a view.
Expand Down Expand Up @@ -49,36 +47,3 @@ extension Animatable where AnimatableData == EmptyAnimatableData {
// TODO
}
}

// MARK: - Animatable + CoreGraphics

extension CGPoint: Animatable {
public var animatableData: AnimatablePair<CGFloat, CGFloat> {
@inlinable
get { .init(x, y) }
@inlinable
set { (x, y) = newValue[] }
}
}

extension CGSize: Animatable {
public var animatableData: AnimatablePair<CGFloat, CGFloat> {
@inlinable
get { .init(width, height) }
@inlinable
set { (width, height) = newValue[] }
}
}

extension CGRect: Animatable {
public var animatableData: AnimatablePair<CGPoint.AnimatableData, CGSize.AnimatableData> {
@inlinable
get {
.init(origin.animatableData, size.animatableData)
}
@inlinable
set {
(origin.animatableData, size.animatableData) = newValue[]
}
}
}
24 changes: 15 additions & 9 deletions Sources/OpenSwiftUICore/Data/Codable/CodableProxy.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
//
// CodableProxy.swift
// OpenSwiftUI
// OpenSwiftUICore
//
// Audited for iOS 15.5
// Status: Complete
// Audited for iOS 18.0
// Status: WIP

protocol CodableProxy: Codable {
associatedtype Base
var base: Base { get }
}

protocol CodableByProxy {
package protocol CodableByProxy {
associatedtype CodingProxy: Codable
var codingProxy: CodingProxy { get }

static func unwrap(codingProxy: CodingProxy) -> Self
}

package protocol CodableProxy: Codable {
associatedtype Base
var base: Base { get }
}

extension CodableByProxy where Self == CodingProxy.Base, CodingProxy: CodableProxy {
package static func unwrap(codingProxy: CodingProxy) -> Self {
codingProxy.base
}
}
4 changes: 2 additions & 2 deletions Sources/OpenSwiftUICore/Data/Update.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
//
// Audited for iOS 18.0
// Status: Blocked by Signpost
// ID: EA173074DA35FA471DC70643259B7E74 (RELEASE_2021)
// ID: 61534957AEEC2EDC447ABDC13B4D426F (RELEASE_2024)
// ID: EA173074DA35FA471DC70643259B7E74 (SwiftUI)
// ID: 61534957AEEC2EDC447ABDC13B4D426F (SwiftUICore)

import OpenSwiftUI_SPI
import OpenGraphShims
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
// CGAffineTransform+Extension.swift
// OpenSwiftUICore
//
// Audited for iOS 18.0
// Status: Complete

#if canImport(Darwin)

package import CoreGraphics

extension CGAffineTransform {
package init(rotation: Angle) {
let sin = sin(rotation.radians)
let cos = cos(rotation.radians)
self.init(a: cos, b: sin, c: -sin, d: cos, tx: 0, ty: 0)
}

package var isTranslation: Bool {
return a == 1 && b == 0 && c == 0 && d == 1
}

package var isRectilinear: Bool {
return (b == 0 && c == 0) || (a == 0 && d == 0)
}

package var isUniform: Bool {
guard isRectilinear else {
return false
}
return a == d && b == c
}

package func rotated(by angle: Angle) -> CGAffineTransform {
CGAffineTransform(rotation: angle).concatenating(self)
}

package var scale: CGFloat {
let m = a * a + b * b
let n = c * c + d * d

if m == 1.0 && n == 1.0 {
return 1.0
} else {
return (sqrt(m) + sqrt(n)) / 2
}
}
}

extension CGAffineTransform: ProtobufMessage {
package func encode(to encoder: inout ProtobufEncoder) throws {
encoder.cgFloatField(1, a, defaultValue: 1)
encoder.cgFloatField(2, b, defaultValue: 0)
encoder.cgFloatField(3, c, defaultValue: 0)
encoder.cgFloatField(4, d, defaultValue: 1)
encoder.cgFloatField(5, tx, defaultValue: 0)
encoder.cgFloatField(6, ty, defaultValue: 0)
}

package init(from decoder: inout ProtobufDecoder) throws {
var transform = CGAffineTransform.identity
while let field = try decoder.nextField() {
switch field.tag {
case 1: transform.a = try decoder.cgFloatField(field)
case 2: transform.b = try decoder.cgFloatField(field)
case 3: transform.c = try decoder.cgFloatField(field)
case 4: transform.d = try decoder.cgFloatField(field)
case 5: transform.tx = try decoder.cgFloatField(field)
case 6: transform.ty = try decoder.cgFloatField(field)
default: try decoder.skipField(field)
}
}
self = transform
}
}

#endif
151 changes: 151 additions & 0 deletions Sources/OpenSwiftUICore/Extension/CGPoint+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
//
// CGPoint+Extension.swift
// OpenSwiftUICore
//
// Audited for iOS 18.0
// Status: Complete

public import Foundation

@_spi(ForOpenSwiftUIOnly) public typealias PlatformPoint = CGPoint

extension CGPoint {
@inlinable
package static var infinity: CGPoint {
.init(x: CGFloat.infinity, y: CGFloat.infinity)
}

@inlinable
package init(_ size: CGSize) {
self.init(x: size.width, y: size.height)
}

@inlinable
package var isFinite: Bool {
x.isFinite && y.isFinite
}

@inlinable
package func offsetBy(dx: CGFloat, dy: CGFloat) -> CGPoint {
CGPoint(x: x + dx, y: y + dy)
}

@inlinable
package func offsetBy(dx: CGFloat) -> CGPoint {
offsetBy(dx: dx, dy: 0)
}

@inlinable
package func offsetBy(dy: CGFloat) -> CGPoint {
offsetBy(dx: 0, dy: dy)
}

@inlinable
package func offset(by offset: CGSize) -> CGPoint {
offsetBy(dx: offset.width, dy: offset.height)
}

@inlinable
package func scaledBy(x: CGFloat, y: CGFloat) -> CGPoint {
CGPoint(x: self.x * x, y: self.y * y)
}

@inlinable
package func scaledBy(x: CGFloat) -> CGPoint {
scaledBy(x: x, y: 1)
}

@inlinable
package func scaledBy(y: CGFloat) -> CGPoint {
scaledBy(x: 1, y: y)
}

@inlinable
package func scaled(by scale: CGFloat) -> CGPoint {
scaledBy(x: scale, y: scale)
}

@inlinable
package var isNaN: Bool {
x.isNaN || y.isNaN
}

@inlinable
package var flushingNaNs: CGPoint {
CGPoint(x: !x.isNaN ? x : 0, y: !y.isNaN ? y : 0)
}

@inlinable
package func approximates(_ other: CGPoint, epsilon: CGFloat) -> Bool {
x.approximates(other.x, epsilon: epsilon)
&& y.approximates(other.y, epsilon: epsilon)
}

@inlinable
package mutating func clamp(size: CGSize) {
x.clamp(to: 0...size.width)
y.clamp(to: 0...size.height)
}

@inlinable
package func clamped(size: CGSize) -> CGPoint {
var point = self
point.clamp(size: size)
return point
}

@inlinable
package mutating func clamp(rect: CGRect) {
x.clamp(to: rect.x...rect.size.width)
y.clamp(to: rect.y...rect.size.height)
}

@inlinable
package func clamped(rect: CGRect) -> CGPoint {
var point = self
point.clamp(rect: rect)
return point
}
}

extension CGPoint {
@inlinable
package subscript(d: Axis) -> CGFloat {
get { d == .horizontal ? x : y }
set { if d == .horizontal { x = newValue } else { y = newValue } }
}

@inlinable
package init(_ l1: CGFloat, in first: Axis, by l2: CGFloat) {
self = first == .horizontal ? CGPoint(x: l1, y: l2) : CGPoint(x: l2, y: l1)
}
}

extension CGPoint: Animatable {
public var animatableData: AnimatablePair<CGFloat, CGFloat> {
@inlinable
get { .init(x, y) }
@inlinable
set { (x, y) = (newValue.first, newValue.second) }
}
}

extension CGPoint: ProtobufMessage {
package func encode(to encoder: inout ProtobufEncoder) {
encoder.cgFloatField(1, x)
encoder.cgFloatField(2, y)
}

package init(from decoder: inout ProtobufDecoder) throws {
var x: CGFloat = .zero
var y: CGFloat = .zero
while let field = try decoder.nextField() {
switch field.tag {
case 1: x = try decoder.cgFloatField(field)
case 2: y = try decoder.cgFloatField(field)
default: try decoder.skipField(field)
}
}
self.init(x: x, y: y)
}
}
Loading

0 comments on commit aa1d8a8

Please sign in to comment.