Skip to content

Commit f7e5d69

Browse files
committed
Match OpenSwiftUI.Color to SwiftUI.Color
1 parent af143a4 commit f7e5d69

File tree

1 file changed

+169
-32
lines changed

1 file changed

+169
-32
lines changed

Sources/OpenSwiftUI/Views/Color.swift

+169-32
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,91 @@
1+
import Foundation
2+
3+
public class AnyColorBox {
4+
}
5+
6+
extension AnyColorBox: Hashable {
7+
public func hash(into hasher: inout Hasher) {
8+
hasher.combine(ObjectIdentifier(self).hashValue)
9+
}
10+
}
11+
12+
extension AnyColorBox: Equatable {
13+
public static func == (lhs: AnyColorBox, rhs: AnyColorBox) -> Bool {
14+
return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
15+
}
16+
}
17+
18+
public class SystemColorType: AnyColorBox {
19+
public enum SystemColor: String {
20+
case clear
21+
case black
22+
case white
23+
case gray
24+
case red
25+
case green
26+
case blue
27+
case orange
28+
case yellow
29+
case pink
30+
case purple
31+
case primary
32+
case secondary
33+
case accentColor
34+
}
35+
36+
public let value: SystemColor
37+
38+
internal init(value: SystemColorType.SystemColor) {
39+
self.value = value
40+
}
41+
42+
public var description: String {
43+
return value.rawValue
44+
}
45+
}
46+
47+
public class DisplayP3: AnyColorBox {
48+
public let red: Double
49+
public let green: Double
50+
public let blue: Double
51+
public let opacity: Double
52+
53+
internal init(red: Double, green: Double, blue: Double, opacity: Double) {
54+
self.red = red
55+
self.green = green
56+
self.blue = blue
57+
self.opacity = opacity
58+
}
59+
}
60+
61+
extension Double {
62+
fileprivate var hexString: String {
63+
return String(format: "%02X", Int((self * 255).rounded()))
64+
}
65+
}
66+
67+
public class _Resolved: AnyColorBox {
68+
public let linearRed: Double
69+
public let linearGreen: Double
70+
public let linearBlue: Double
71+
public let opacity: Double
72+
73+
internal init(linearRed: Double, linearGreen: Double, linearBlue: Double, opacity: Double) {
74+
self.linearRed = linearRed
75+
self.linearGreen = linearGreen
76+
self.linearBlue = linearBlue
77+
self.opacity = opacity
78+
}
79+
80+
public var description: String {
81+
return "#\(linearRed.hexString)\(linearGreen.hexString)\(linearBlue.hexString)\(opacity.hexString)"
82+
}
83+
}
84+
185
public struct Color: View, Hashable, CustomStringConvertible {
286
public typealias Body = Never
387

4-
// These values should be private,
5-
// but then they are not accessible
6-
// in implementations of OpenSwiftUI
7-
public let _red: Double
8-
public let _green: Double
9-
public let _blue: Double
10-
public let _opacity: Double
88+
public let provider: AnyColorBox
1189

1290
public enum RGBColorSpace: Equatable {
1391
case sRGB
@@ -16,47 +94,60 @@ public struct Color: View, Hashable, CustomStringConvertible {
1694
}
1795

1896
public init(_ colorSpace: Color.RGBColorSpace = .sRGB, red: Double, green: Double, blue: Double, opacity: Double = 1) {
19-
self._red = red
20-
self._green = green
21-
self._blue = blue
22-
self._opacity = opacity
97+
switch colorSpace {
98+
case .sRGB:
99+
self.provider = _Resolved(linearRed: red, linearGreen: green, linearBlue: blue, opacity: opacity)
100+
case .sRGBLinear:
101+
self.provider = _Resolved(linearRed: red, linearGreen: green, linearBlue: blue, opacity: opacity)
102+
case .displayP3:
103+
self.provider = DisplayP3(red: red, green: green, blue: blue, opacity: opacity)
104+
}
23105
}
24106

25107
public init(_ colorSpace: Color.RGBColorSpace = .sRGB, white: Double, opacity: Double = 1) {
26-
self._red = white
27-
self._green = white
28-
self._blue = white
29-
self._opacity = opacity
108+
switch colorSpace {
109+
case .sRGB:
110+
self.provider = _Resolved(linearRed: white, linearGreen: white, linearBlue: white, opacity: opacity)
111+
case .sRGBLinear:
112+
self.provider = _Resolved(linearRed: white, linearGreen: white, linearBlue: white, opacity: opacity)
113+
case .displayP3:
114+
self.provider = DisplayP3(red: white, green: white, blue: white, opacity: opacity)
115+
}
30116
}
31117

32118
public init(hue: Double, saturation: Double, brightness: Double, opacity: Double = 1) {
33-
// TODO: Implement HSBA to RGBA conversion.
34-
fatalError("Not implemented")
119+
let rgb = Color.hsbToRGB(hue: hue, saturation: saturation, brightness: brightness)
120+
self.provider = _Resolved(linearRed: rgb.red, linearGreen: rgb.green, linearBlue: rgb.blue, opacity: opacity)
121+
}
122+
123+
internal init(_ systemColor: SystemColorType.SystemColor) {
124+
self.provider = SystemColorType(value: systemColor)
35125
}
36126

37127
public var body: Never {
38128
fatalError()
39129
}
40130

41131
public var description: String {
42-
return "Red: \(_red), Green: \(_green), Blue: \(_blue)"
132+
return "\(provider)"
43133
}
44134
}
45135

46136
extension Color {
47-
public static let clear: Color = Color(hue: 0, saturation: 0, brightness: 0, opacity: 0)
48-
public static let black: Color = Color(red: 0, green: 0, blue: 0)
49-
public static let white: Color = Color(red: 1, green: 1, blue: 1)
50-
public static let gray: Color = Color(red: 0.5, green: 0.5, blue: 0.5)
51-
public static let red: Color = Color(red: 1, green: 0, blue: 0)
52-
public static let green: Color = Color(red: 0, green: 1, blue: 0)
53-
public static let blue: Color = Color(red: 0, green: 0, blue: 1)
54-
public static let orange: Color = Color(red: 1, green: 0.5, blue: 0)
55-
public static let yellow: Color = Color(red: 1, green: 1, blue: 0)
56-
public static let pink: Color = Color(red: 1, green: 0, blue: 1)
57-
public static let purple: Color = Color(red: 0.5, green: 0, blue: 1)
58-
public static let primary: Color = Color(red: 1, green: 1, blue: 1)
59-
public static let secondary: Color = Color(red: 0.8, green: 0.8, blue: 0.8)
137+
public static let clear: Color = Color(.clear)
138+
public static let black: Color = Color(.black)
139+
public static let white: Color = Color(.white)
140+
public static let gray: Color = Color(.gray)
141+
public static let red: Color = Color(.red)
142+
public static let green: Color = Color(.green)
143+
public static let blue: Color = Color(.blue)
144+
public static let orange: Color = Color(.orange)
145+
public static let yellow: Color = Color(.yellow)
146+
public static let pink: Color = Color(.pink)
147+
public static let purple: Color = Color(.purple)
148+
public static let primary: Color = Color(.primary)
149+
public static let secondary: Color = Color(.secondary)
150+
public static let accentColor: Color = Color(.accentColor)
60151
}
61152

62153
extension View {
@@ -77,7 +168,53 @@ extension EnvironmentValues {
77168
}
78169

79170

80-
171+
extension Color {
172+
internal static func hsbToRGB(hue: Double, saturation: Double, brightness: Double) -> (red: Double, green: Double, blue: Double) {
173+
// Based on:
174+
// http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
175+
176+
var red: Double = 0
177+
var green: Double = 0
178+
var blue: Double = 0
179+
180+
let i = floor(hue * 6)
181+
let f = hue * 6 - i
182+
let p = brightness * (1 - saturation)
183+
let q = brightness * (1 - f * saturation)
184+
let t = brightness * (1 - (1 - f) * saturation)
185+
186+
switch(i.truncatingRemainder(dividingBy: 6)) {
187+
case 0:
188+
red = brightness
189+
green = t
190+
blue = p
191+
case 1:
192+
red = q
193+
green = brightness
194+
blue = p
195+
case 2:
196+
red = p
197+
green = brightness
198+
blue = t
199+
case 3:
200+
red = p
201+
green = q
202+
blue = brightness
203+
case 4:
204+
red = t
205+
green = p
206+
blue = brightness
207+
case 5:
208+
red = brightness
209+
green = p
210+
blue = q
211+
default:
212+
break
213+
}
214+
215+
return (red, green, blue)
216+
}
217+
}
81218

82219
public enum ColorScheme: CaseIterable {
83220
case light

0 commit comments

Comments
 (0)