summaryrefslogtreecommitdiff
path: root/src/macos
diff options
context:
space:
mode:
Diffstat (limited to 'src/macos')
-rw-r--r--src/macos/Sources/PardesView.swift77
-rw-r--r--src/macos/pardes.h3
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);