Skip to content

Commit 3df1441

Browse files
committed
Continue implementation
1 parent d7629bd commit 3df1441

File tree

1 file changed

+75
-29
lines changed

1 file changed

+75
-29
lines changed

Sources/GateEngine/UI/TileMapControl.swift

Lines changed: 75 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,47 +27,60 @@ public enum TileMapControlSubControlType: Sendable {
2727
}
2828

2929
public 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

4550
public 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

Comments
 (0)