crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

GridThumbnailView.swift (1845B)


      1 import SwiftUI
      2 
      3 /// A miniature, non-interactive rendering of a crossword grid for use in
      4 /// game list rows. Drawn in a single `Canvas` pass: the whole thumbnail is
      5 /// filled black, then non-block cells are drawn on top, so the gaps between
      6 /// cells form the grid lines for free.
      7 struct GridThumbnailView: View {
      8     let width: Int
      9     let height: Int
     10     let cells: [GameThumbnailCell]
     11 
     12     private let size: CGFloat = 60
     13     private let spacing: CGFloat = 0.5
     14 
     15     var body: some View {
     16         Canvas(rendersAsynchronously: false) { ctx, canvasSize in
     17             ctx.fill(
     18                 Path(CGRect(origin: .zero, size: canvasSize)),
     19                 with: .color(.black)
     20             )
     21 
     22             let cols = CGFloat(width)
     23             let rows = CGFloat(height)
     24             let cellW = (canvasSize.width  - spacing * (cols + 1)) / cols
     25             let cellH = (canvasSize.height - spacing * (rows + 1)) / rows
     26             let cell  = min(cellW, cellH)
     27 
     28             let gridW = cell * cols + spacing * (cols + 1)
     29             let gridH = cell * rows + spacing * (rows + 1)
     30             let originX = (canvasSize.width  - gridW) / 2
     31             let originY = (canvasSize.height - gridH) / 2
     32 
     33             for index in cells.indices {
     34                 let cellValue = cells[index]
     35                 guard cellValue != .block else { continue }
     36                 let r = index / width
     37                 let c = index % width
     38                 let x = originX + spacing + CGFloat(c) * (cell + spacing)
     39                 let y = originY + spacing + CGFloat(r) * (cell + spacing)
     40                 ctx.fill(
     41                     Path(CGRect(x: x, y: y, width: cell, height: cell)),
     42                     with: .color(cellValue == .filled ? Color(.systemGray3) : .white)
     43                 )
     44             }
     45         }
     46         .frame(width: size, height: size)
     47     }
     48 }