|
| 1 | +public protocol StyledShape: Shape { |
| 2 | + var strokeColor: Color? { get } |
| 3 | + var fillColor: Color? { get } |
| 4 | + var strokeStyle: StrokeStyle? { get } |
| 5 | +} |
| 6 | + |
| 7 | +struct StyledShapeImpl<Base: Shape>: StyledShape { |
| 8 | + var base: Base |
| 9 | + var strokeColor: Color? |
| 10 | + var fillColor: Color? |
| 11 | + var strokeStyle: StrokeStyle? |
| 12 | + |
| 13 | + init( |
| 14 | + base: Base, strokeColor: Color? = nil, fillColor: Color? = nil, |
| 15 | + strokeStyle: StrokeStyle? = nil |
| 16 | + ) { |
| 17 | + self.base = base |
| 18 | + |
| 19 | + if let styledBase = base as? any StyledShape { |
| 20 | + self.strokeColor = strokeColor ?? styledBase.strokeColor |
| 21 | + self.fillColor = fillColor ?? styledBase.fillColor |
| 22 | + self.strokeStyle = strokeStyle ?? styledBase.strokeStyle |
| 23 | + } else { |
| 24 | + self.strokeColor = strokeColor |
| 25 | + self.fillColor = fillColor |
| 26 | + self.strokeStyle = strokeStyle |
| 27 | + } |
| 28 | + } |
| 29 | + |
| 30 | + func path(in bounds: Path.Rect) -> Path { |
| 31 | + return base.path(in: bounds) |
| 32 | + } |
| 33 | + |
| 34 | + func size(fitting proposal: SIMD2<Int>) -> ViewSize { |
| 35 | + return base.size(fitting: proposal) |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +extension Shape { |
| 40 | + public func fill(_ color: Color) -> some StyledShape { |
| 41 | + StyledShapeImpl(base: self, fillColor: color) |
| 42 | + } |
| 43 | + |
| 44 | + public func stroke(_ color: Color, style: StrokeStyle? = nil) -> some StyledShape { |
| 45 | + StyledShapeImpl(base: self, strokeColor: color, strokeStyle: style) |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +extension StyledShape { |
| 50 | + public func update<Backend: AppBackend>( |
| 51 | + _ widget: Backend.Widget, children: any ViewGraphNodeChildren, proposedSize: SIMD2<Int>, |
| 52 | + environment: EnvironmentValues, backend: Backend, dryRun: Bool |
| 53 | + ) -> ViewUpdateResult { |
| 54 | + let storage = children as! ShapeStorage |
| 55 | + let size = size(fitting: proposedSize) |
| 56 | + |
| 57 | + let path = path( |
| 58 | + in: Path.Rect(x: 0.0, y: 0.0, width: Double(size.size.x), height: Double(size.size.y)) |
| 59 | + ) |
| 60 | + |
| 61 | + let pointsChanged = storage.oldPath?.actions != path.actions |
| 62 | + storage.oldPath = path |
| 63 | + |
| 64 | + let backendPath = storage.backendPath as! Backend.Path |
| 65 | + backend.updatePath(backendPath, path, pointsChanged: pointsChanged) |
| 66 | + |
| 67 | + if !dryRun { |
| 68 | + backend.setSize(of: widget, to: size.size) |
| 69 | + backend.renderPath( |
| 70 | + backendPath, |
| 71 | + container: widget, |
| 72 | + strokeColor: strokeColor ?? .clear, |
| 73 | + fillColor: fillColor ?? .clear, |
| 74 | + overrideStrokeStyle: strokeStyle |
| 75 | + ) |
| 76 | + } |
| 77 | + |
| 78 | + return ViewUpdateResult.leafView(size: size) |
| 79 | + } |
| 80 | +} |
0 commit comments