summaryrefslogtreecommitdiff
path: root/src/macos/Sources/PardesView.swift
diff options
context:
space:
mode:
Diffstat (limited to 'src/macos/Sources/PardesView.swift')
-rw-r--r--src/macos/Sources/PardesView.swift68
1 files changed, 24 insertions, 44 deletions
diff --git a/src/macos/Sources/PardesView.swift b/src/macos/Sources/PardesView.swift
index 0b16458e..4c122a13 100644
--- a/src/macos/Sources/PardesView.swift
+++ b/src/macos/Sources/PardesView.swift
@@ -512,18 +512,10 @@ private struct TaglineMetrics {
UInt16(clamping: row), Float(canvasHeight * scale), cellPixels, bandPixels)) / scale
}
- /// Where a tagline cell's GLYPH sits, on the compact grid.
- ///
- /// Only the text compacts. The colour band behind it was already painted
- /// pane-wide on the body grid, which is what keeps a tag bar the width of
- /// its pane; this steps the characters on top of it at the tagline face's
- /// own pitch, anchored so the compact grid's column zero is the pane's
- /// physical left edge. The anchor is the core's — the SDL shell reaches the
- /// identical rule through `pardes.taglineOriginCol`, and pane rects are not
- /// otherwise on this shell's ABI at all.
+ /// Canonical tag cells are physical grip slots; TagLayer positions text.
func glyphX(col: Int, row: Int, bodyCellWidth: CGFloat) -> CGFloat {
- let origin = CGFloat(pardes_tagline_origin_col(UInt16(clamping: col), UInt16(clamping: row)))
- return origin * bodyCellWidth + (CGFloat(col) - origin) * width
+ // Canonical tag cells are physical grips; TagLayer owns compact text.
+ CGFloat(col) * bodyCellWidth
}
/// Thickness of the rule joining the topbar band to the first pane-tag band,
@@ -992,14 +984,6 @@ final class PardesView: NSView {
// Band geometry is stated against the whole canvas: the last row's rule
// depends on where the window edge is, not just on the row index.
let canvasHeight = bounds.height
- // The tag band's own colour, fetched once per frame. A compact tag row
- // is painted in TWO passes — pane-wide band on the body grid, then each
- // cell's own background on the narrower grid its glyph uses — which is
- // what the SDL shell spends its second quad per tagline cell on. Before
- // there is a session to ask there is no base and the single body-grid
- // fill below is all there is.
- let taglineBaseBG = pardes_tagline_bg()
- let taglineTwoPass = taglineBaseBG != UInt32(PARDES_COLOR_DEFAULT)
for row in 0..<rows {
let base = row * cols
let y = CGFloat(row) * cellHeight
@@ -1025,29 +1009,8 @@ final class PardesView: NSView {
if color != bgClear {
let bandY = tagline ? y + bandTop : y
let bandHeight = tagline ? taglines.height : cellHeight
- if tagline && taglineTwoPass {
- // The band keeps the BODY grid so it spans its pane
- // exactly. Anything that is NOT the band — a hovered
- // word, a selection, the block cursor — belongs to the
- // cell and has to land under the glyph, which moved to
- // the narrower grid. Runs are painted left to right and
- // a compact overlay always sits left of its own run's
- // right edge, so no later band can cover one.
- fill(ctx, CGRect(x: CGFloat(start) * cellWidth, y: bandY,
- width: CGFloat(col - start) * cellWidth, height: bandHeight),
- taglineBaseBG, 1)
- if color != taglineBaseBG {
- fill(ctx, CGRect(
- x: taglines.glyphX(col: start, row: row, bodyCellWidth: cellWidth),
- y: bandY,
- width: CGFloat(col - start) * taglines.width,
- height: bandHeight), color, 1)
- }
- } else {
- fill(ctx, CGRect(x: CGFloat(start) * cellWidth, y: bandY,
- width: CGFloat(col - start) * cellWidth, height: bandHeight),
- color, 1)
- }
+ fill(ctx, CGRect(x: CGFloat(start) * cellWidth, y: bandY,
+ width: CGFloat(col - start) * cellWidth, height: bandHeight), color, 1)
}
start = col
color = next
@@ -1168,9 +1131,10 @@ final class PardesView: NSView {
}
if frozenImages == nil {
drawBodyLayers(ctx, hideCursor:hideCursor)
- drawTagLayers(ctx, hideCursor:hideCursor)
+ drawTagLayers(ctx, hideCursor:hideCursor, canonical:cells, cols:cols, rows:rows)
} else {
for layer in presentedTagLayers {
+ drawTagGrip(ctx, values:layer.values, canonical:cells, cols:cols, rows:rows)
layer.cells.withUnsafeBufferPointer { cells in
if let base = cells.baseAddress { drawTagLayer(ctx, values:layer.values, cells:base, hideCursor:true) }
}
@@ -1197,14 +1161,30 @@ final class PardesView: NSView {
return result
}
- private func drawTagLayers(_ ctx: CGContext, hideCursor: Bool) {
+ private func drawTagLayers(_ ctx: CGContext, hideCursor: Bool, canonical: UnsafePointer<pardes_cell_s>, cols: Int, rows: Int) {
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 }
+ drawTagGrip(ctx, values:values, canonical:canonical, cols:cols, rows:rows)
if let cells = pardes_tag_layer_cells(index) { drawTagLayer(ctx, values: values, cells: cells, hideCursor: hideCursor) }
}
}
+ private func drawTagGrip(_ ctx: CGContext, values: [Int], canonical: UnsafePointer<pardes_cell_s>, cols: Int, rows: Int) {
+ let width = Int(pardes_grip_columns())
+ let x = values[4] - width, y = values[5]
+ if values[1] == 0 || x < 0 || x >= cols || y >= rows || taglines.height < 6 || taglines.width < 3 { return }
+ var cell = canonical[y * cols + x]
+ let text = withUnsafeBytes(of: &cell.text) { String(decoding: $0.prefix(Int(cell.len)), as: UTF8.self) }
+ if text != " " { return }
+ let style = resolve(cell, block:false, ground:themeBG ?? pardesDefaultBG, clearGround:false)
+ let centerX = (CGFloat(x) + CGFloat(width) / 2) * cellWidth
+ let centerY = CGFloat(y) * cellHeight + taglines.top(row:y, canvasHeight:bounds.height) + taglines.height / 2
+ let halfWidth = max(1, min(3, cellWidth - 2))
+ fill(ctx, CGRect(x:floor(centerX-halfWidth), y:floor(centerY-2), width:2*halfWidth, height:1), style.fg, 1)
+ fill(ctx, CGRect(x:floor(centerX-halfWidth), y:floor(centerY+1), width:2*halfWidth, height:1), style.fg, 1)
+ }
+
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)