diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-15 14:46:38 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-15 17:24:42 -0300 |
| commit | 40c19fd4f52d20df94c2dfa2d68102b89bd9d3f1 (patch) | |
| tree | 642150be8703f1d9a0766ff18516f06bfdc8801a /src/body_layer.zig | |
| parent | 379f4fe55c7c9c7c8cc7b97dc921c83e2c24698b (diff) | |
| download | pardes-40c19fd4f52d20df94c2dfa2d68102b89bd9d3f1.tar.gz pardes-40c19fd4f52d20df94c2dfa2d68102b89bd9d3f1.zip | |
Add optional compact tagline styling for source context
Diffstat (limited to 'src/body_layer.zig')
| -rw-r--r-- | src/body_layer.zig | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/src/body_layer.zig b/src/body_layer.zig new file mode 100644 index 00000000..3b5ee795 --- /dev/null +++ b/src/body_layer.zig @@ -0,0 +1,80 @@ +//! A file body's logical rows can outnumber its physical grid rows. Hosts +//! place the compact declaration rows first and clip the remaining body rows. +const std = @import("std"); +const pardes = @import("pardes.zig"); +const config = @import("config.zig"); + +pub const Metrics = struct { + body_w: u16 = 1, + body_h: u16 = 1, + tagline_w: u16 = 1, + tagline_h: u16 = 1, +}; + +pub const Layer = struct { + pane: u16 = 0, + serial: u32 = 0, + viewport: pardes.Rect = .{ .x = 0, .y = 0, .w = 0, .h = 0 }, + cols: u16 = 0, + rows: u16 = 0, + context_rows: u16 = 0, + cells: []pardes.Cell = &.{}, + cursor: ?struct { x: u16, y: u16, bar: bool = false } = null, + + pub fn rowTop(layer: *const Layer, row: u16, body_h: f32, tagline_h: f32) f32 { + const body = @max(1, body_h); + const tag = std.math.clamp(tagline_h, 1, body); + return @as(f32, @floatFromInt(layer.viewport.y)) * body + + @as(f32, @floatFromInt(@min(row, layer.context_rows))) * tag + + @as(f32, @floatFromInt(row -| layer.context_rows)) * body; + } + + pub fn rowHeight(layer: *const Layer, row: u16, body_h: f32, tagline_h: f32) f32 { + return if (row < layer.context_rows) std.math.clamp(tagline_h, 1, @max(1, body_h)) else @max(1, body_h); + } + + pub fn hitAt(layer: *const Layer, x: f32, y: f32, body_w: f32, body_h: f32, tagline_w: f32, tagline_h: f32) ?pardes.Mouse.BodyHit { + if (layer.rows == 0 or !std.math.isFinite(x) or !std.math.isFinite(y)) return null; + const bw = @max(1, body_w); + const bh = @max(1, body_h); + const tw = std.math.clamp(tagline_w, 1, bw); + const th = std.math.clamp(tagline_h, 1, bh); + const dx = x - @as(f32, @floatFromInt(layer.viewport.x)) * bw; + const dy = y - @as(f32, @floatFromInt(layer.viewport.y)) * bh; + if (dx < 0 or dy < 0 or dx >= @as(f32, @floatFromInt(layer.viewport.w)) * bw or dy >= @as(f32, @floatFromInt(layer.viewport.h)) * bh) return null; + const headers = @as(f32, @floatFromInt(layer.context_rows)) * th; + const row: u16 = @intFromFloat(if (dy < headers) @floor(dy / th) else @as(f32, @floatFromInt(layer.context_rows)) + @floor((dy - headers) / bh)); + if (row >= layer.rows) return null; + const col: u16 = @intFromFloat(@min(@as(f32, @floatFromInt(layer.cols -| 1)), @floor(dx / (if (row < layer.context_rows) tw else bw)))); + return .{ + .serial = layer.serial, + .row = row, + .col = col + config.GUTTER, + .pixel_x = x, + .pixel_y = y, + .metrics = .{ .body_w = @intFromFloat(bw), .body_h = @intFromFloat(bh), .tagline_w = @intFromFloat(tw), .tagline_h = @intFromFloat(th) }, + }; + } +}; + +test "compact body layer rows fill reclaimed height and invert exact boundaries" { + const layer: Layer = .{ .serial = 7, .viewport = .{ .x = 4, .y = 3, .w = 40, .h = 10 }, .cols = 40, .rows = 15, .context_rows = 5 }; + try std.testing.expectEqual(@as(f32, 120), layer.rowTop(5, 20, 12)); + try std.testing.expectEqual(@as(f32, 240), layer.rowTop(11, 20, 12)); + try std.testing.expectEqual(@as(f32, 12), layer.rowHeight(4, 20, 12)); + try std.testing.expectEqual(@as(f32, 20), layer.rowHeight(5, 20, 12)); + for (0..12) |index| { + const row: u16 = @intCast(index); + const y = layer.rowTop(row, 20, 12) + layer.rowHeight(row, 20, 12) / 2; + const width: f32 = if (row < 5) 6 else 10; + const hit = layer.hitAt(40 + 3.5 * width, y, 10, 20, 6, 12).?; + try std.testing.expectEqual(row, hit.row); + try std.testing.expectEqual(@as(u16, 3 + config.GUTTER), hit.col); + } + try std.testing.expectEqual(@as(u16, 4), layer.hitAt(45, 119.99, 10, 20, 6, 12).?.row); + try std.testing.expectEqual(@as(u16, 5), layer.hitAt(45, 120, 10, 20, 6, 12).?.row); + try std.testing.expectEqual(@as(u16, 11), layer.hitAt(45, 259.99, 10, 20, 6, 12).?.row); + try std.testing.expect(layer.hitAt(45, 260, 10, 20, 6, 12) == null); + try std.testing.expect(layer.hitAt(39.99, 80, 10, 20, 6, 12) == null); + try std.testing.expect(layer.hitAt(std.math.nan(f32), 80, 10, 20, 6, 12) == null); +} |
