diff options
Diffstat (limited to 'src/macos')
| -rw-r--r-- | src/macos/Sources/PardesView.swift | 77 | ||||
| -rw-r--r-- | src/macos/pardes.h | 3 |
2 files changed, 72 insertions, 8 deletions
diff --git a/src/macos/Sources/PardesView.swift b/src/macos/Sources/PardesView.swift index 2d43cc38..0b16458e 100644 --- a/src/macos/Sources/PardesView.swift +++ b/src/macos/Sources/PardesView.swift @@ -911,6 +911,7 @@ final class PardesView: NSView { if !animatedPanels { presentedImages = frameImages presentedBodyLayers = snapshotBodyLayers() + presentedTagLayers = snapshotTagLayers() } presentationSerial &+= 1 let animationWoke = pardes_frame_presented(animatedPanels) @@ -1167,7 +1168,13 @@ final class PardesView: NSView { } if frozenImages == nil { drawBodyLayers(ctx, hideCursor:hideCursor) + drawTagLayers(ctx, hideCursor:hideCursor) } else { + for layer in presentedTagLayers { + layer.cells.withUnsafeBufferPointer { cells in + if let base = cells.baseAddress { drawTagLayer(ctx, values:layer.values, cells:base, hideCursor:true) } + } + } for layer in presentedBodyLayers { layer.cells.withUnsafeBufferPointer { cells in if let base = cells.baseAddress { drawBodyLayer(ctx, values:layer.values, cells:base, hideCursor:true) } @@ -1176,6 +1183,67 @@ final class PardesView: NSView { } } + private var presentedTagLayers: [FrozenBodyLayer] = [] + + private func snapshotTagLayers() -> [FrozenBodyLayer] { + var result: [FrozenBodyLayer] = [] + for index in 0..<pardes_tag_layer_limit() { + let values = (0...10).map { Int(pardes_tag_layer_value(index, UInt32($0))) } + if values[0] == 0 { continue } + if let cells = pardes_tag_layer_cells(index) { + result.append(FrozenBodyLayer(values: values, cells: Array(UnsafeBufferPointer(start: cells, count: values[0])))) + } + } + return result + } + + private func drawTagLayers(_ ctx: CGContext, hideCursor: Bool) { + for index in 0..<pardes_tag_layer_limit() { + let values = (0...10).map { Int(pardes_tag_layer_value(index, UInt32($0))) } + if values[0] == 0 { continue } + if let cells = pardes_tag_layer_cells(index) { drawTagLayer(ctx, values: values, cells: cells, hideCursor: hideCursor) } + } + } + + private func drawTagLayer(_ ctx: CGContext, values: [Int], cells: UnsafePointer<pardes_cell_s>, hideCursor: Bool) { + let left = CGFloat(values[4]) * cellWidth + let y = CGFloat(values[5]) * cellHeight + taglines.top(row: values[5], canvasHeight: bounds.height) + let viewport = CGRect(x: left, y: y, width: CGFloat(values[6]) * cellWidth, height: taglines.height) + ctx.saveGState() + ctx.clip(to: viewport) + fill(ctx, viewport, UInt32(values[10]), 1) + for pass in 0...1 { + for col in 0..<values[0] { + var cell = cells[col] + let isCursor = !hideCursor && col == values[8] + let style = resolve(cell, block: isCursor && values[9] == 0, ground: UInt32(values[10]), clearGround: false) + let x = left + CGFloat(col) * taglines.width + if pass == 0 { + fill(ctx, CGRect(x: x, y: y, width: taglines.width, height: taglines.height), style.bg, 1) + continue + } + let text = withUnsafeBytes(of: &cell.text) { String(decoding: $0.prefix(Int(cell.len)), as: UTF8.self) } + if style.visible && !text.isEmpty && text != " " { + let face = Face(bold: cell.attrs & UInt16(PARDES_ATTR_BOLD) != 0, italic: cell.attrs & UInt16(PARDES_ATTR_ITALIC) != 0) + ctx.saveGState() + ctx.translateBy(x: 0, y: bounds.height) + ctx.scaleBy(x: 1, y: -1) + let baseline = bounds.height - y - taglines.ascent + drawRules(ctx, cell, style, x: x, width: taglines.width, baseline: baseline) + setFill(ctx, style.fg, style.alpha) + ctx.textPosition = CGPoint(x: x, y: baseline) + let line = NSAttributedString(string: text, attributes: [fontAttribute: taglines.fonts[face.rawValue]]) + CTLineDraw(CTLineCreateWithAttributedString(line as CFAttributedString), ctx) + ctx.restoreGState() + } + if isCursor && values[9] != 0 { + fill(ctx, CGRect(x: x, y: y, width: max(1, taglines.width / 8), height: taglines.height), style.fg, 1) + } + } + } + ctx.restoreGState() + } + private struct FrozenBodyLayer { let values: [Int] let cells: [pardes_cell_s] @@ -2012,14 +2080,7 @@ final class PardesView: NSView { } sampledBodyPointer = sampled let row = min(max(Int(sampled.y / cellHeight), 0), rows - 1) - // The column comes from the core, because a tag row's glyphs step at - // the tagline face's narrower pitch and a body-pitch click drifts one - // word further right for every word along the row. The SDL shell asks - // the identical rule (`pardes.gridColAt`). Points on both sides: only - // the ratio of x to the two widths is read. - let col = min(max(Int(pardes_grid_col_at( - Float(sampled.x), UInt16(clamping: row), - Float(cellWidth), Float(taglines.width))), 0), cols - 1) + let col = min(max(Int(sampled.x / cellWidth), 0), cols - 1) return GridPoint(col: UInt16(col), row: UInt16(row)) } diff --git a/src/macos/pardes.h b/src/macos/pardes.h index 9f9aef60..e72f134a 100644 --- a/src/macos/pardes.h +++ b/src/macos/pardes.h @@ -341,6 +341,9 @@ void pardes_mouse_pixel(pardes_mouse_button_e button, pardes_mouse_kind_e kind, uint16_t col, uint16_t row, uint32_t mods, float x, float y, float body_w, float body_h, float tagline_w, float tagline_h); void pardes_row_metrics(uint16_t body_w, uint16_t body_h, uint16_t tagline_w, uint16_t tagline_h); +uint32_t pardes_tag_layer_limit(void); +uint32_t pardes_tag_layer_value(uint32_t index, uint32_t field); +const pardes_cell_s *pardes_tag_layer_cells(uint32_t index); uint32_t pardes_body_layer_limit(void); uint32_t pardes_body_layer_value(uint32_t index, uint32_t field); const pardes_cell_s *pardes_body_layer_cells(uint32_t index); |
