diff options
Diffstat (limited to 'src/macos/Sources/PardesView.swift')
| -rw-r--r-- | src/macos/Sources/PardesView.swift | 68 |
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) |
