summaryrefslogtreecommitdiff
path: root/src/draw.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/draw.zig')
-rw-r--r--src/draw.zig90
1 files changed, 68 insertions, 22 deletions
diff --git a/src/draw.zig b/src/draw.zig
index b596fc22..7d91ad31 100644
--- a/src/draw.zig
+++ b/src/draw.zig
@@ -192,7 +192,6 @@ pub fn render(p: *Pardes, arena: std.mem.Allocator) !*Surface {
pane.context_row_limit = null;
s.body_layers[id].rows = 0;
try renderPane(p, s, arena, pane, p.rects[id], id, id == p.active);
- try body_layer.renderBodyLayer(p, arena, pane, p.rects[id], id);
}
// Each notice once, as a tag layer, and the grid's chip a copy of it.
for (s.regionList()) |region| {
@@ -494,7 +493,7 @@ fn renderPane(p: *Pardes, s: *Surface, arena: std.mem.Allocator, pane: *Pane, r:
return;
}
- try body_layer.renderBody(p, s, arena, pane, r, id, active, rail.*);
+ try body_layer.joinBody(p, s, arena, pane, r, id, active, rail.*);
}
/// The workspace and column tags: each line a tag layer, and the grid's
@@ -716,25 +715,6 @@ fn joinPaneTag(p: *Pardes, s: *Surface, arena: std.mem.Allocator, pane: *Pane, r
if (temporary.cursor) |cursor| if (cursor.x - TAG_TEXT_INSET < r.w - TAG_TEXT_INSET) {
s.cursor = .{ .x = r.x + cursor.x, .y = region.rect.y + cursor.y, .bar = cursor.bar };
};
- // A sweep begun on the tag and dragged into the body shows on the body
- // rows it crossed, which only the grid has.
- const th = p.theme();
- const tx = r.x + TAG_TEXT_INSET;
- const tw = r.w - TAG_TEXT_INSET;
- const tag_y = region.rect.y;
- const body_y = p.bodyTop(pane, r);
- if (p.look_hover_preview) |preview| {
- if (preview.pane == id and preview.serial == pane.serial) if (preview.sel) |sel| if (@min(sel.r0, sel.r1) < rows) {
- const page_rgb = th.bg orelse th.tag_bg;
- const preview_bg = colors.mix(page_rgb, colors.mix(page_rgb, th.sel_bg));
- body_layer.paintPointerSelection(p, s, pane, r, tx, tw, tag_y, body_y, sel, rows, preview_bg, null);
- };
- }
- for (pane.sel, 0..) |selection, button| {
- if (selection.state == .none or (selection.state == .done and button != 0)) continue;
- if (@min(selection.r0, selection.r1) >= rows) continue;
- body_layer.paintPointerSelection(p, s, pane, r, tx, tw, tag_y, body_y, selection, rows, th.sel_bg, th.sel_fg);
- }
}
/// A notice chip, painted once as a tag layer at the tagline's pitch, and the
@@ -924,11 +904,27 @@ pub fn paintPaneTag(p: *Pardes, s: *Surface, arena: std.mem.Allocator, pane: *Pa
if (col < tw) s.cursor = .{ .x = tx + @as(u16, @intCast(col)), .y = tag_y + @as(u16, @intCast(at.row)), .bar = mode == .insert };
}
+ // Pointer sweeps over the tag rows. A select sweep is the tag's own, in
+ // its selection colours; the look-hover affordance goes over it, and a
+ // middle or right sweep over both, tinted by its button the way the
+ // body tints it.
for (pane.sel, 0..) |selection, button| {
if (selection.state == .none or (selection.state == .done and button != 0)) continue;
- if (@min(selection.r0, selection.r1) >= rows) continue;
+ if (button != pardes.sel_slot or @min(selection.r0, selection.r1) >= rows) continue;
body_layer.paintPointerSelection(p, s, pane, r, tx, tw, tag_y, body_y, selection, 0, th.sel_bg, th.sel_fg);
}
+ if (p.look_hover_preview) |preview| {
+ if (preview.pane == id and preview.serial == pane.serial) if (preview.sel) |sel| if (@min(sel.r0, sel.r1) < rows) {
+ const preview_bg = colors.mix(page_rgb, colors.mix(page_rgb, th.sel_bg));
+ body_layer.paintPointerSelection(p, s, pane, r, tx, tw, tag_y, body_y, sel, 0, preview_bg, null);
+ };
+ }
+ const sel_btn = body_layer.buttonTints(th);
+ for (pane.sel, 0..) |selection, button| {
+ if (selection.state == .none or (selection.state == .done and button != 0)) continue;
+ if (button == pardes.sel_slot or @min(selection.r0, selection.r1) >= rows) continue;
+ body_layer.paintPointerSelection(p, s, pane, r, tx, tw, tag_y, body_y, selection, 0, sel_btn[button], th.sel_fg);
+ }
}
test "place puts every part where the painters and layers put it, in every layout" {
@@ -1036,3 +1032,53 @@ test "a wide glyph cut by a tag's or a notice's edge is joined into the grid as
}
}
}
+
+test "a body with context rows is painted once, and the grid's rows are what a plain paint of it gives" {
+ if (comptime !@import("syntax.zig").enabled) return error.SkipZigTest;
+ const p = try Pardes.init(std.testing.allocator, .{ .tty_only = true, .cols = 60, .rows = 16 });
+ defer p.deinit();
+ const pane = try p.setTestFile("pub const Box = struct {\n pub fn run() void {\n" ++ (" // body line\n" ** 30) ++ " }\n};\n");
+ p.gpa.free(pane.file.?.path);
+ pane.file.?.path = try p.gpa.dupe(u8, "/test.zig");
+ if (!panes.File.supportsContext(pane)) return error.SkipZigTest;
+ pane.file.?.tree_context = true;
+ pane.file.?.scroll = 8;
+ var arena: std.heap.ArenaAllocator = .init(std.testing.allocator);
+ defer arena.deinit();
+ for ([_]bool{ false, true }) |bottom| {
+ p.settings.tag_bottom = bottom;
+ // A selection and the cursor on body rows, painted in the one pass.
+ pane.body.cur_row = 12;
+ pane.body.cur_col = 3;
+ pane.body.vsel = .{ .active = true, .row = 10, .col = 2 };
+ pane.body.mode = .normal;
+ p.sync();
+ _ = arena.reset(.retain_capacity);
+ const s = try p.render(arena.allocator());
+ const layer = &s.body_layers[0];
+ try std.testing.expect(layer.context_rows > 0);
+ const body = s.region(.body, 0).?;
+ // The plain paint the grid used to take, of the same frame.
+ const cells = try arena.allocator().alloc(Cell, s.cells.len);
+ @memset(cells, .{});
+ var plain: Surface = .{ .cols = s.cols, .rows = s.rows, .cells = cells };
+ const saved = .{ pane.body_rows, pane.body_visible_rows, pane.context_row_limit };
+ pane.body_rows = 0;
+ pane.body_visible_rows = 0;
+ pane.context_row_limit = null;
+ try body_layer.renderBody(p, &plain, arena.allocator(), pane, p.rects[0], 0, true, null, null);
+ pane.body_rows, pane.body_visible_rows, pane.context_row_limit = saved;
+ for (0..body.rect.h) |row| {
+ const y = body.rect.y + row;
+ for (0..body.rect.w) |col| {
+ const x = body.rect.x + col;
+ const got = s.cells[y * s.cols + x];
+ const want = plain.cells[y * s.cols + x];
+ try std.testing.expect(got.visuallyEqual(&want));
+ }
+ }
+ try std.testing.expectEqual(plain.cursor, s.cursor);
+ // The layer's own rows run past the grid's.
+ try std.testing.expect(layer.rows > body.rect.h);
+ }
+}