Added convenience overloads to Rect and also, Collection conformance in the Playdate bindings target.
This commit is contained in:
@@ -56,3 +56,17 @@ extension Graphics {
|
|||||||
public var count: Int { info.count }
|
public var count: Int { info.count }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Graphics.BitmapTable: RandomAccessCollection {
|
||||||
|
public var startIndex: Int { 0 }
|
||||||
|
public var endIndex: Int { count }
|
||||||
|
|
||||||
|
/// The bitmap at `position`. The bitmap references storage owned by the
|
||||||
|
/// table; keep the table alive while using it.
|
||||||
|
public subscript(position: Int) -> Graphics.Bitmap {
|
||||||
|
guard let bitmap = bitmap(at: position) else {
|
||||||
|
preconditionFailure("bitmap table index out of range")
|
||||||
|
}
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -46,11 +46,21 @@ extension Graphics {
|
|||||||
gfx.pointee.setClipRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height))
|
gfx.pointee.setClipRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the clip rect in world coordinates (affected by the draw offset).
|
||||||
|
public static func setClipRect(_ rect: Rect) {
|
||||||
|
setClipRect(x: rect.left, y: rect.top, width: rect.width, height: rect.height)
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the clip rect in screen coordinates (unaffected by the draw offset).
|
/// Sets the clip rect in screen coordinates (unaffected by the draw offset).
|
||||||
public static func setScreenClipRect(x: Int, y: Int, width: Int, height: Int) {
|
public static func setScreenClipRect(x: Int, y: Int, width: Int, height: Int) {
|
||||||
gfx.pointee.setScreenClipRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height))
|
gfx.pointee.setScreenClipRect.unsafelyUnwrapped(Int32(x), Int32(y), Int32(width), Int32(height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the clip rect in screen coordinates (unaffected by the draw offset).
|
||||||
|
public static func setScreenClipRect(_ rect: Rect) {
|
||||||
|
setScreenClipRect(x: rect.left, y: rect.top, width: rect.width, height: rect.height)
|
||||||
|
}
|
||||||
|
|
||||||
/// Clears the current clip rect.
|
/// Clears the current clip rect.
|
||||||
public static func clearClipRect() {
|
public static func clearClipRect() {
|
||||||
gfx.pointee.clearClipRect.unsafelyUnwrapped()
|
gfx.pointee.clearClipRect.unsafelyUnwrapped()
|
||||||
@@ -103,6 +113,11 @@ extension Graphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draws the outline of a rectangle, stroked inside its frame.
|
||||||
|
public static func drawRect(_ rect: Rect, color: Color) {
|
||||||
|
drawRect(x: rect.left, y: rect.top, width: rect.width, height: rect.height, color: color)
|
||||||
|
}
|
||||||
|
|
||||||
/// Fills the rectangle with `color`.
|
/// Fills the rectangle with `color`.
|
||||||
public static func fillRect(x: Int, y: Int, width: Int, height: Int, color: Color) {
|
public static func fillRect(x: Int, y: Int, width: Int, height: Int, color: Color) {
|
||||||
color.withLCDColor {
|
color.withLCDColor {
|
||||||
@@ -110,6 +125,11 @@ extension Graphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fills the rectangle with `color`.
|
||||||
|
public static func fillRect(_ rect: Rect, color: Color) {
|
||||||
|
fillRect(x: rect.left, y: rect.top, width: rect.width, height: rect.height, color: color)
|
||||||
|
}
|
||||||
|
|
||||||
/// Draws the outline of a rectangle with rounded corners, stroked with
|
/// Draws the outline of a rectangle with rounded corners, stroked with
|
||||||
/// `lineWidth`.
|
/// `lineWidth`.
|
||||||
public static func drawRoundRect(x: Int, y: Int, width: Int, height: Int, radius: Int,
|
public static func drawRoundRect(x: Int, y: Int, width: Int, height: Int, radius: Int,
|
||||||
@@ -120,6 +140,13 @@ extension Graphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draws the outline of a rectangle with rounded corners, stroked with
|
||||||
|
/// `lineWidth`.
|
||||||
|
public static func drawRoundRect(_ rect: Rect, radius: Int, lineWidth: Int, color: Color) {
|
||||||
|
drawRoundRect(x: rect.left, y: rect.top, width: rect.width, height: rect.height,
|
||||||
|
radius: radius, lineWidth: lineWidth, color: color)
|
||||||
|
}
|
||||||
|
|
||||||
/// Fills a rectangle with rounded corners.
|
/// Fills a rectangle with rounded corners.
|
||||||
public static func fillRoundRect(x: Int, y: Int, width: Int, height: Int, radius: Int, color: Color) {
|
public static func fillRoundRect(x: Int, y: Int, width: Int, height: Int, radius: Int, color: Color) {
|
||||||
color.withLCDColor {
|
color.withLCDColor {
|
||||||
@@ -128,6 +155,12 @@ extension Graphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fills a rectangle with rounded corners.
|
||||||
|
public static func fillRoundRect(_ rect: Rect, radius: Int, color: Color) {
|
||||||
|
fillRoundRect(x: rect.left, y: rect.top, width: rect.width, height: rect.height,
|
||||||
|
radius: radius, color: color)
|
||||||
|
}
|
||||||
|
|
||||||
/// Draws an ellipse stroked inside the rect. If the angles differ, draws
|
/// Draws an ellipse stroked inside the rect. If the angles differ, draws
|
||||||
/// an arc from `startAngle` to `endAngle` (clockwise degrees, 0 at top).
|
/// an arc from `startAngle` to `endAngle` (clockwise degrees, 0 at top).
|
||||||
public static func drawEllipse(x: Int, y: Int, width: Int, height: Int, lineWidth: Int,
|
public static func drawEllipse(x: Int, y: Int, width: Int, height: Int, lineWidth: Int,
|
||||||
@@ -148,6 +181,22 @@ extension Graphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draws an ellipse stroked inside the rect. If the angles differ, draws
|
||||||
|
/// an arc from `startAngle` to `endAngle` (clockwise degrees, 0 at top).
|
||||||
|
public static func drawEllipse(in rect: Rect, lineWidth: Int,
|
||||||
|
startAngle: Float = 0, endAngle: Float = 0, color: Color) {
|
||||||
|
drawEllipse(x: rect.left, y: rect.top, width: rect.width, height: rect.height,
|
||||||
|
lineWidth: lineWidth, startAngle: startAngle, endAngle: endAngle, color: color)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fills an ellipse inside the rect. If the angles differ, fills the
|
||||||
|
/// wedge from `startAngle` to `endAngle` (clockwise degrees, 0 at top).
|
||||||
|
public static func fillEllipse(in rect: Rect,
|
||||||
|
startAngle: Float = 0, endAngle: Float = 0, color: Color) {
|
||||||
|
fillEllipse(x: rect.left, y: rect.top, width: rect.width, height: rect.height,
|
||||||
|
startAngle: startAngle, endAngle: endAngle, color: color)
|
||||||
|
}
|
||||||
|
|
||||||
/// Fills the polygon described by the points, connecting the last point
|
/// Fills the polygon described by the points, connecting the last point
|
||||||
/// back to the first.
|
/// back to the first.
|
||||||
public static func fillPolygon(points: [(x: Int, y: Int)], color: Color,
|
public static func fillPolygon(points: [(x: Int, y: Int)], color: Color,
|
||||||
@@ -205,6 +254,13 @@ extension Graphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draws `text` wrapped and aligned inside the given rectangle.
|
||||||
|
public static func drawText(_ text: String, in rect: Rect,
|
||||||
|
wrap: TextWrappingMode = .word, align: TextAlignment = .left) {
|
||||||
|
drawText(text, x: rect.left, y: rect.top, width: rect.width, height: rect.height,
|
||||||
|
wrap: wrap, align: align)
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets the font used by subsequent text drawing.
|
/// Sets the font used by subsequent text drawing.
|
||||||
public static func setFont(_ font: Font) {
|
public static func setFont(_ font: Font) {
|
||||||
gfx.pointee.setFont.unsafelyUnwrapped(font.pointer)
|
gfx.pointee.setFont.unsafelyUnwrapped(font.pointer)
|
||||||
|
|||||||
@@ -33,6 +33,12 @@ extension Graphics {
|
|||||||
top: Int32(top), bottom: Int32(bottom))
|
top: Int32(top), bottom: Int32(bottom))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The rect's width.
|
||||||
|
public var width: Int { right - left }
|
||||||
|
|
||||||
|
/// The rect's height.
|
||||||
|
public var height: Int { bottom - top }
|
||||||
|
|
||||||
/// Returns the rect offset by (dx, dy).
|
/// Returns the rect offset by (dx, dy).
|
||||||
public func translated(dx: Int, dy: Int) -> Rect {
|
public func translated(dx: Int, dy: Int) -> Rect {
|
||||||
Rect(left: left + dx, right: right + dx, top: top + dy, bottom: bottom + dy)
|
Rect(left: left + dx, right: right + dx, top: top + dy, bottom: bottom + dy)
|
||||||
|
|||||||
@@ -186,6 +186,12 @@ enum Mock {
|
|||||||
Mock.record("getTableBitmap(\(index))")
|
Mock.record("getTableBitmap(\(index))")
|
||||||
return index == 0 ? Mock.fakePointer() : nil
|
return index == 0 ? Mock.fakePointer() : nil
|
||||||
}
|
}
|
||||||
|
gfxAPI.pointee.getBitmapTableInfo = { _, count, cellsWide in
|
||||||
|
Mock.record("getBitmapTableInfo")
|
||||||
|
// One bitmap, matching getTableBitmap vending index 0 only.
|
||||||
|
count?.pointee = 1
|
||||||
|
cellsWide?.pointee = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Sprite
|
// MARK: - Sprite
|
||||||
|
|||||||
@@ -89,6 +89,16 @@ struct WrapperTests {
|
|||||||
#expect(Mock.eventCount("freeBitmapTable") == 1)
|
#expect(Mock.eventCount("freeBitmapTable") == 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func bitmapTableIsACollection() {
|
||||||
|
let table = Graphics.BitmapTable(count: 4, width: 8, height: 8)
|
||||||
|
#expect(table.count == 1) // the mock reports a single bitmap
|
||||||
|
#expect(table.first != nil)
|
||||||
|
|
||||||
|
var visited = 0
|
||||||
|
for _ in table { visited += 1 }
|
||||||
|
#expect(visited == 1)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Sprite
|
// MARK: Sprite
|
||||||
|
|
||||||
@Test func spriteUserdataRecoversWrapperInCallbacks() {
|
@Test func spriteUserdataRecoversWrapperInCallbacks() {
|
||||||
|
|||||||
Reference in New Issue
Block a user