From 2b046005d104d9c49ca41ac220e853b98cbf0546 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 26 Jul 2026 00:20:19 +0200 Subject: [PATCH] Converted get/set methods pairs to computed properties throughout the Playdate bindings target. --- .../Sources/HelloPlaydate/Game.swift | 2 +- README.md | 3 ++- Sources/PlaydateKit/Display/Display.swift | 10 ++++----- Sources/PlaydateKit/Graphics/Graphics.swift | 8 ++----- .../PlaydateKit.docc/GettingStarted.md | 2 +- .../PlaydateKit/Sound/Classes/Channel.swift | 22 +++++++++---------- .../Sound/Source/Classes/Source.swift | 20 ++++++++--------- .../Sound/Synth/Classes/Instrument.swift | 16 ++++++-------- 8 files changed, 36 insertions(+), 47 deletions(-) diff --git a/Examples/HelloPlaydate/Sources/HelloPlaydate/Game.swift b/Examples/HelloPlaydate/Sources/HelloPlaydate/Game.swift index 4c89f2e..4ea054a 100644 --- a/Examples/HelloPlaydate/Sources/HelloPlaydate/Game.swift +++ b/Examples/HelloPlaydate/Sources/HelloPlaydate/Game.swift @@ -32,7 +32,7 @@ final class Game { private let boxSize = 24 func start() { - Display.setRefreshRate(50) + Display.refreshRate = 50 System.addMenuItem(title: "reset") { _ in Game.shared.reset() diff --git a/README.md b/README.md index f3b85f9..85f11f8 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ final class Game { var player = Sprite() func start() { - Display.setRefreshRate(50) + Display.refreshRate = 50 System.setUpdateCallback { self.update() @@ -300,6 +300,7 @@ try Lua.addFunction(double, name: "mylib.double") ## Conventions - **Namespaces.** The subsystem namespaces (`System`, `Graphics`, `Sound`, …) live at the top level of the module; only the raw C API bootstrap stays under `Playdate` (`Playdate.initialize(with:)`, `Playdate.api`). On a name collision with another module, qualify with the module name: `PlaydateKit.System`. +- **Properties vs. methods.** State the OS can report back is a property: read-write where the C API has a get/set pair (`Display.refreshRate`, `Source.volume`), get-only where it only has a getter (`Display.fps`). A `set…` method means the C API is write-only there (`Display.setScale`, `Synth.setAttackTime`) or setting takes extra arguments — a property getter never invents a value the OS can't return. Callbacks are installed with `set…Callback`/`set…Function` methods. - **Errors.** Fallible operations use typed throws — `throws(PlaydateError)` generally, `throws(Network.NetError)` for network I/O — so `catch` gives you a concrete type, and no `any Error` existentials are needed. - **Ownership.** A wrapper that *creates* a C object frees it on `deinit`; keep the wrapper referenced for as long as you use it. Wrappers vending OS-owned objects (a `Bitmap` from a `BitmapTable`, a track from a `Sequence`, …) don't free them — keep the owner alive instead, as documented on each API. Resources a C object keeps referencing (a sprite's image, a synth's sample, modulators, menu-item option titles) are retained by the wrapper automatically. - **Callbacks.** Where the C API provides a userdata slot, closures are supported everywhere and delivered back with the right wrapper. A few C callbacks have no userdata (serial messages, headphone changes, scoreboard diff --git a/Sources/PlaydateKit/Display/Display.swift b/Sources/PlaydateKit/Display/Display.swift index 6e76406..5eb85ad 100644 --- a/Sources/PlaydateKit/Display/Display.swift +++ b/Sources/PlaydateKit/Display/Display.swift @@ -13,15 +13,13 @@ extension Display { /// The display height in pixels, taking the current scale into account. public static var height: Int { Int(api.pointee.getHeight.unsafelyUnwrapped()) } - /// Sets the nominal refresh rate in frames per second. Pass 0 to update + /// The nominal refresh rate in frames per second. Set to 0 to update /// as fast as possible (the update callback drives the pace). - public static func setRefreshRate(_ rate: Float) { - api.pointee.setRefreshRate.unsafelyUnwrapped(rate) + public static var refreshRate: Float { + get { api.pointee.getRefreshRate.unsafelyUnwrapped() } + set { api.pointee.setRefreshRate.unsafelyUnwrapped(newValue) } } - /// The current nominal refresh rate. - public static var refreshRate: Float { api.pointee.getRefreshRate.unsafelyUnwrapped() } - /// The measured average frames per second. public static var fps: Float { api.pointee.getFPS.unsafelyUnwrapped() } diff --git a/Sources/PlaydateKit/Graphics/Graphics.swift b/Sources/PlaydateKit/Graphics/Graphics.swift index f1fa54a..810f173 100644 --- a/Sources/PlaydateKit/Graphics/Graphics.swift +++ b/Sources/PlaydateKit/Graphics/Graphics.swift @@ -211,13 +211,9 @@ extension Graphics { } /// Extra space added between letters, in pixels. - public static func setTextTracking(_ tracking: Int) { - gfx.pointee.setTextTracking.unsafelyUnwrapped(Int32(tracking)) - } - - /// The extra space currently added between letters, in pixels. public static var textTracking: Int { - Int(gfx.pointee.getTextTracking.unsafelyUnwrapped()) + get { Int(gfx.pointee.getTextTracking.unsafelyUnwrapped()) } + set { gfx.pointee.setTextTracking.unsafelyUnwrapped(Int32(newValue)) } } /// Adjusts the line height used when drawing multi-line text. diff --git a/Sources/PlaydateKit/PlaydateKit.docc/GettingStarted.md b/Sources/PlaydateKit/PlaydateKit.docc/GettingStarted.md index 7615729..fa13c5f 100644 --- a/Sources/PlaydateKit/PlaydateKit.docc/GettingStarted.md +++ b/Sources/PlaydateKit/PlaydateKit.docc/GettingStarted.md @@ -31,7 +31,7 @@ final class Game { nonisolated(unsafe) static let shared = Game() func start() { - Display.setRefreshRate(50) + Display.refreshRate = 50 System.setUpdateCallback { self.update() diff --git a/Sources/PlaydateKit/Sound/Classes/Channel.swift b/Sources/PlaydateKit/Sound/Classes/Channel.swift index 395b168..530c796 100644 --- a/Sources/PlaydateKit/Sound/Classes/Channel.swift +++ b/Sources/PlaydateKit/Sound/Classes/Channel.swift @@ -119,13 +119,12 @@ extension Sound { } /// Modulates the channel's volume. - public func setVolumeModulator(_ modulator: SignalValue?) { - retain(modulator) - Channel.api.pointee.setVolumeModulator.unsafelyUnwrapped(pointer, modulator?.pointer) - } - public var volumeModulator: SignalValue? { - SignalValue.wrap(Channel.api.pointee.getVolumeModulator.unsafelyUnwrapped(pointer)) + get { SignalValue.wrap(Channel.api.pointee.getVolumeModulator.unsafelyUnwrapped(pointer)) } + set { + retain(newValue) + Channel.api.pointee.setVolumeModulator.unsafelyUnwrapped(pointer, newValue?.pointer) + } } /// The channel's stereo pan: -1 (left) to 1 (right). @@ -135,13 +134,12 @@ extension Sound { /// Modulates the channel's pan. The signal's range 0...1 maps to /// left...right. - public func setPanModulator(_ modulator: SignalValue?) { - retain(modulator) - Channel.api.pointee.setPanModulator.unsafelyUnwrapped(pointer, modulator?.pointer) - } - public var panModulator: SignalValue? { - SignalValue.wrap(Channel.api.pointee.getPanModulator.unsafelyUnwrapped(pointer)) + get { SignalValue.wrap(Channel.api.pointee.getPanModulator.unsafelyUnwrapped(pointer)) } + set { + retain(newValue) + Channel.api.pointee.setPanModulator.unsafelyUnwrapped(pointer, newValue?.pointer) + } } /// A signal following the channel's dry (unprocessed) level. diff --git a/Sources/PlaydateKit/Sound/Source/Classes/Source.swift b/Sources/PlaydateKit/Sound/Source/Classes/Source.swift index 07d6a9a..0cfd723 100644 --- a/Sources/PlaydateKit/Sound/Source/Classes/Source.swift +++ b/Sources/PlaydateKit/Sound/Source/Classes/Source.swift @@ -16,21 +16,19 @@ extension Sound { self.isOwned = isOwned } - /// Sets the playback volume for the left and right channels, 0...1. - public func setVolume(left: Float, right: Float) { - Source.api.pointee.setVolume.unsafelyUnwrapped(pointer, left, right) + /// The playback volume of the left and right channels, 0...1. + public var volume: (left: Float, right: Float) { + get { + var left: Float = 0, right: Float = 0 + Source.api.pointee.getVolume.unsafelyUnwrapped(pointer, &left, &right) + return (left, right) + } + set { Source.api.pointee.setVolume.unsafelyUnwrapped(pointer, newValue.left, newValue.right) } } /// Sets the playback volume of both channels. public func setVolume(_ volume: Float) { - setVolume(left: volume, right: volume) - } - - /// The playback volume of the left and right channels. - public var volume: (left: Float, right: Float) { - var left: Float = 0, right: Float = 0 - Source.api.pointee.getVolume.unsafelyUnwrapped(pointer, &left, &right) - return (left, right) + self.volume = (volume, volume) } public var isPlaying: Bool { diff --git a/Sources/PlaydateKit/Sound/Synth/Classes/Instrument.swift b/Sources/PlaydateKit/Sound/Synth/Classes/Instrument.swift index b940bcc..fb95c2a 100644 --- a/Sources/PlaydateKit/Sound/Synth/Classes/Instrument.swift +++ b/Sources/PlaydateKit/Sound/Synth/Classes/Instrument.swift @@ -93,16 +93,14 @@ extension Sound { Instrument.api.pointee.allNotesOff.unsafelyUnwrapped(pointer, when) } - /// Sets the volume of the left and right channels, 0...1. - public func setVolume(left: Float, right: Float) { - Instrument.api.pointee.setVolume.unsafelyUnwrapped(pointer, left, right) - } - - /// The volume of the left and right channels. + /// The volume of the left and right channels, 0...1. public var volume: (left: Float, right: Float) { - var left: Float = 0, right: Float = 0 - Instrument.api.pointee.getVolume.unsafelyUnwrapped(pointer, &left, &right) - return (left, right) + get { + var left: Float = 0, right: Float = 0 + Instrument.api.pointee.getVolume.unsafelyUnwrapped(pointer, &left, &right) + return (left, right) + } + set { Instrument.api.pointee.setVolume.unsafelyUnwrapped(pointer, newValue.left, newValue.right) } } /// The number of voices currently playing.