@@ -27,47 +27,60 @@ public enum TileMapControlSubControlType: Sendable {
2727}
2828
2929public protocol TileControlSubControl : Equatable , Identifiable {
30+ associatedtype Control : TileControl
3031 var type : TileMapControlSubControlType { get }
3132 /// The arangement of coordinates (relative to zero) for this control.
3233 /// The position of this control is determined by TileMapControlScheme
3334 var coordinates : [ TileMap . Layer . Coordinate ] { get }
3435 /// The `regular` state tile for the layer
35- func regularStateTile( at coordinateIndex: Int , forLayer layer: String ? ) -> TileMap . Tile
36+ func regularStateTile( at coordinateIndex: Int , forLayer layer: String ? , mode : any TileMapControlMode , userData : any TileMapControlUserData ) -> TileMap . Tile
3637}
3738
38- public protocol TileControl : Equatable , Identifiable where ID == String {
39+ public protocol TileControl < Scheme> : Equatable , Identifiable where ID == String {
40+ associatedtype Scheme : TileMapControlScheme
3941 associatedtype SubControl : TileControlSubControl
4042 /// How this control behaves
4143 var type : TileMapControlType { get }
4244 var subControls : [ SubControl ] { get }
45+
46+ func currentStateForSubControl( _ subControl: any TileControlSubControl , mode: any TileMapControlMode , userData: any TileMapControlUserData ) -> TileMapControlState
47+ func stateDidChangeForSubControl( _ subControl: any TileControlSubControl , state: TileMapControlState , mode: any TileMapControlMode , userData: inout any TileMapControlUserData )
4348}
4449
4550public protocol TileMapControlScheme {
46- associatedtype Mode = AnyHashable
47- static var defaultMode : Mode { get }
48- static func control( at coordinate: TileMap . Layer . Coordinate , forMode mode: Mode ) -> ( any TileControl ) ?
51+ associatedtype Mode : TileMapControlMode
52+ associatedtype UserData : TileMapControlUserData
53+ static func control( at coordinate: TileMap . Layer . Coordinate , forMode mode: Mode , userData: UserData ) -> ( any TileControl < Self > ) ?
54+ }
55+
56+ public protocol TileMapControlUserData : Equatable , Hashable , Sendable {
57+ init ( )
58+ }
59+
60+ public protocol TileMapControlMode : Equatable , Hashable , CaseIterable , Sendable {
61+ static var `default` : Self { get }
4962}
5063
5164@MainActor
52- public protocol TileMapControlViewDelegate < ControlScheme> : AnyObject {
53- associatedtype ControlScheme : TileMapControlScheme
54- func tileMapControlView( _ tileMapControl: TileMapControlView < ControlScheme > , currentStateforControl control: any TileControl , subControlIndex: Int ) -> TileMapControlState
55- func tileMapControlView( _ tileMapControl: TileMapControlView < ControlScheme > , control: any TileControl , subControlIndex: Int , didChangeStateTo state: TileMapControlState )
56- func tileMapControlView( _ tileMapControl: TileMapControlView < ControlScheme > , didActivateControl control: any TileControl , subControlIndex: Int )
65+ public protocol TileMapControlViewDelegate < Scheme> : AnyObject {
66+ associatedtype Scheme : TileMapControlScheme
67+ func tileMapControlView( _ tileMapControl: TileMapControlView < Scheme > , didActivateControl control: any TileControl , subControlIndex: Int )
5768}
5869
59- public final class TileMapControlView < ControlScheme : TileMapControlScheme > : TileMapView {
70+ public final class TileMapControlView < Scheme : TileMapControlScheme > : TileMapView {
6071 private func baseOffset( forState state: TileMapControlState ) -> Int {
61- let count = tileSet. tiles. count / type ( of : state ) . allCases. count
72+ let count = tileSet. tiles. count / TileMapControlState . allCases. count
6273 return state. rawValue * count
6374 }
6475
6576 var modeDidChange : Bool = true
66- public var mode : ControlScheme . Mode = ControlScheme . defaultMode {
77+ public var mode : Scheme . Mode = Scheme . Mode . default {
6778 didSet { self . modeDidChange = true }
6879 }
69- public weak var controlDelegate : ( any TileMapControlViewDelegate < ControlScheme > ) ? = nil
80+ public weak var controlDelegate : ( any TileMapControlViewDelegate < Scheme > ) ? = nil
7081
82+ public var userData : any TileMapControlUserData = Scheme . UserData. init ( )
83+
7184 var controls : [ any TileControl ] = [ ]
7285 var controlOrigins : [ TileMap . Layer . Coordinate ] = [ ]
7386 var controlIndicies : [ Int ? ] = [ ]
@@ -78,21 +91,24 @@ public final class TileMapControlView<ControlScheme: TileMapControlScheme>: Tile
7891 self . controls. removeAll ( keepingCapacity: true )
7992 self . controlOrigins. removeAll ( keepingCapacity: true )
8093 self . controlStates. removeAll ( keepingCapacity: true )
94+ self . eraseAllLayers ( )
8195
8296 guard let layer = tileMap. layers. first else { return }
8397
98+ let userData : Scheme . UserData = userData as! Scheme . UserData
99+
84100 for column in 0 ..< layer. columns {
85101 for row in 0 ..< layer. rows {
86102 let origin = TileMap . Layer. Coordinate ( column: column, row: row)
87- if let control = ControlScheme . control ( at: origin, forMode: mode) {
103+ if let control = Scheme . control ( at: origin, forMode: mode, userData : userData ) {
88104 let controlIndex = controls. endIndex
89105 self . controls. append ( control)
90106 self . controlOrigins. append ( origin)
91107 var states : [ TileMapControlState ] = [ ]
92108 var controlOriginIsASubControl = false
93109 for subControlIndex in control. subControls. indices {
94110 let subControl = control. subControls [ subControlIndex]
95- states. append ( controlDelegate ? . tileMapControlView ( self , currentStateforControl : control , subControlIndex : subControlIndex ) ?? . regular )
111+ states. append ( control . currentStateForSubControl ( subControl , mode : mode , userData : userData ) )
96112 for coordIndex in subControl. coordinates. indices {
97113 let coord = subControl. coordinates [ coordIndex]
98114 if coord == . init( column: 0 , row: 0 ) {
@@ -154,7 +170,20 @@ public final class TileMapControlView<ControlScheme: TileMapControlScheme>: Tile
154170 self . repaintControl ( at: coord)
155171 }
156172
157- func repaintControl( at coord: TileMap . Layer . Coordinate ) {
173+ func eraseAllLayers( ) {
174+ for layer in self . layers {
175+ self . editLayer ( named: layer. name!) { layer in
176+ for column in 0 ..< layer. columns {
177+ for row in 0 ..< layer. rows {
178+ layer. setTile ( . empty, at: . init( column: column, row: row) )
179+ }
180+ }
181+ }
182+ }
183+ }
184+
185+ public func repaintControl( at coord: TileMap . Layer . Coordinate ) {
186+ guard modeDidChange == false else { return }
158187 guard let controlIndex = controlIndicies [ coordIndex ( of: coord) ] else { return }
159188 let control = controls [ controlIndex]
160189 let offset = controlOrigins [ controlIndex]
@@ -165,7 +194,8 @@ public final class TileMapControlView<ControlScheme: TileMapControlScheme>: Tile
165194 self . editLayer ( named: layer. name!) { layer in
166195 for coordIndex in subControl. coordinates. indices {
167196 let coord = subControl. coordinates [ coordIndex] + offset
168- let tile = subControl. regularStateTile ( at: coordIndex, forLayer: layer. name)
197+ let tile = subControl. regularStateTile ( at: coordIndex, forLayer: layer. name, mode: mode, userData: userData)
198+ if tile == . empty { continue }
169199 if subControl. type != . decorative && state != . disabled && state != . selected {
170200 if let tempHighlighted = hid. activeHover {
171201 if subControl. coordinates. contains ( where: { $0 + offset == tempHighlighted} ) {
@@ -214,7 +244,9 @@ public final class TileMapControlView<ControlScheme: TileMapControlScheme>: Tile
214244 if momentary. duration < 0 {
215245 self . momentaryToDeactivate. remove ( at: index)
216246 self . setState ( . regular, forControl: momentary. pair. control, subControlIndex: momentary. pair. subControlIndex)
217- self . controlDelegate? . tileMapControlView ( self , control: momentary. pair. control, subControlIndex: momentary. pair. subControlIndex, didChangeStateTo: . regular)
247+
248+ let subControl = momentary. pair. control. subControls [ momentary. pair. subControlIndex]
249+ momentary. pair. control. stateDidChangeForSubControl ( subControl, state: . regular, mode: mode, userData: & userData)
218250 }
219251 }
220252 }
@@ -223,25 +255,38 @@ public final class TileMapControlView<ControlScheme: TileMapControlScheme>: Tile
223255 guard let pair = control ( at: coord) else { return }
224256 guard pair. control. subControls [ pair. subControlIndex] . type != . decorative else { return }
225257
258+ var activate : Bool = false
259+
226260 switch pair. control. type {
227261 case . momentary:
228262 let currentState = self . state ( forControl: pair. control, subControlIndex: pair. subControlIndex)
229263 guard currentState != . selected && currentState != . disabled else { return }
230264 self . setState ( . selected, forControl: pair. control, subControlIndex: pair. subControlIndex)
231265 self . momentaryToDeactivate. append ( ( pair, 0.03 ) )
232- self . controlDelegate? . tileMapControlView ( self , control: pair. control, subControlIndex: pair. subControlIndex, didChangeStateTo: . selected)
266+ pair. control. stateDidChangeForSubControl ( pair. control. subControls [ pair. subControlIndex] , state: . selected, mode: mode, userData: & userData)
267+ activate = true
233268 case . segmented:
234269 let currentState = self . state ( forControl: pair. control, subControlIndex: pair. subControlIndex)
235270 guard currentState != . selected && currentState != . disabled else { return }
236271 for subControlIndex in pair. control. subControls. indices {
237- let state : TileMapControlState = if subControlIndex == pair. subControlIndex {
238- . selected
272+ let state : TileMapControlState
273+ if subControlIndex == pair. subControlIndex {
274+ state = . selected
239275 } else {
240- . regular
276+ let currentState = self . state ( forControl: pair. control, subControlIndex: subControlIndex)
277+ if currentState == . selected {
278+ // Deselect the old value
279+ state = . regular
280+ } else {
281+ state = currentState
282+ }
241283 }
242- self . setState ( state, forControl: pair. control, subControlIndex: subControlIndex)
284+
285+ // Update the state if it's different
243286 if self . state ( forControl: pair. control, subControlIndex: subControlIndex) != state {
244- self . controlDelegate? . tileMapControlView ( self , control: pair. control, subControlIndex: subControlIndex, didChangeStateTo: state)
287+ self . setState ( state, forControl: pair. control, subControlIndex: subControlIndex)
288+ pair. control. stateDidChangeForSubControl ( pair. control. subControls [ pair. subControlIndex] , state: state, mode: mode, userData: & userData)
289+ activate = true
245290 }
246291 }
247292 case . toggleable:
@@ -253,14 +298,15 @@ public final class TileMapControlView<ControlScheme: TileMapControlScheme>: Tile
253298 . selected
254299 }
255300 self . setState ( state, forControl: pair. control, subControlIndex: pair. subControlIndex)
256- self . controlDelegate? . tileMapControlView ( self , control: pair. control, subControlIndex: pair. subControlIndex, didChangeStateTo: state)
301+ pair. control. stateDidChangeForSubControl ( pair. control. subControls [ pair. subControlIndex] , state: state, mode: mode, userData: & userData)
302+ activate = true
257303 }
258304
259- self . controlDelegate? . tileMapControlView ( self , didActivateControl: pair. control, subControlIndex: pair. subControlIndex)
305+ if activate {
306+ self . controlDelegate? . tileMapControlView ( self , didActivateControl: pair. control, subControlIndex: pair. subControlIndex)
307+ }
260308 }
261309
262-
263-
264310 private var _hidOld : HIDState = . init( )
265311 private var hid : HIDState = . init( )
266312
0 commit comments