mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-24 16:11:43 +00:00
terminal/c: resolve relative placement viewport positions
This commit is contained in:
@@ -10,6 +10,7 @@ const grid_ref = @import("grid_ref.zig");
|
||||
const selection_c = @import("selection.zig");
|
||||
const terminal_c = @import("terminal.zig");
|
||||
const Terminal = @import("../Terminal.zig");
|
||||
const PageList = @import("../PageList.zig");
|
||||
const Result = @import("result.zig").Result;
|
||||
|
||||
/// C: GhosttyKittyGraphics
|
||||
@@ -600,10 +601,35 @@ fn computeViewportPos(
|
||||
) struct { col: i32, row: i32, visible: bool } {
|
||||
// Virtual placements use unicode placeholders and don't have a
|
||||
// screen position — they are rendered inline by the text layout.
|
||||
const pin = switch (p.location) {
|
||||
.pin => |pin| pin,
|
||||
.virtual, .relative => return .{ .col = 0, .row = 0, .visible = false },
|
||||
// Relative placements are anchored at the root of their parent
|
||||
// chain, offset by the accumulated chain offsets. A chain rooted
|
||||
// at a virtual placement has no resolvable position here: its
|
||||
// origin is the parent's placeholder cells, which only a renderer
|
||||
// scanning the screen can locate.
|
||||
const origin: struct {
|
||||
pin: *const PageList.Pin,
|
||||
col_offset: i32 = 0,
|
||||
row_offset: i32 = 0,
|
||||
} = switch (p.location) {
|
||||
.pin => |pin| .{ .pin = pin },
|
||||
.virtual => return .{ .col = 0, .row = 0, .visible = false },
|
||||
.relative => |rel| origin: {
|
||||
const storage = &t.screens.active.kitty_images;
|
||||
const chain = storage.resolveChain(rel) orelse
|
||||
return .{ .col = 0, .row = 0, .visible = false };
|
||||
switch (chain.root.location) {
|
||||
.pin => |root_pin| break :origin .{
|
||||
.pin = root_pin,
|
||||
.col_offset = chain.horizontal_offset,
|
||||
.row_offset = chain.vertical_offset,
|
||||
},
|
||||
.virtual => return .{ .col = 0, .row = 0, .visible = false },
|
||||
.relative => unreachable, // resolveChain roots are never relative
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const pin = origin.pin;
|
||||
if (pin.garbage) return .{ .col = 0, .row = 0, .visible = false };
|
||||
|
||||
// Convert both the placement's pin and the viewport's top-left
|
||||
@@ -618,17 +644,23 @@ fn computeViewportPos(
|
||||
|
||||
// Subtracting viewport origin from the pin gives us viewport-
|
||||
// relative coordinates. The row can be negative when the
|
||||
// placement has partially scrolled above the viewport.
|
||||
const vp_row: i32 = @as(i32, @intCast(pin_screen.screen.y)) -
|
||||
@as(i32, @intCast(vp_screen.screen.y));
|
||||
const vp_col: i32 = @intCast(pin_screen.screen.x);
|
||||
// placement has partially scrolled above the viewport, and both
|
||||
// can be negative for relative placements with negative offsets.
|
||||
const vp_row: i32 = (@as(i32, @intCast(pin_screen.screen.y)) -
|
||||
@as(i32, @intCast(vp_screen.screen.y))) +| origin.row_offset;
|
||||
const vp_col: i32 = @as(i32, @intCast(pin_screen.screen.x)) +|
|
||||
origin.col_offset;
|
||||
|
||||
// A placement is invisible if its bottom edge (row + height)
|
||||
// is above the viewport, or its top edge is at or below the
|
||||
// viewport's last row.
|
||||
// A placement is invisible if its bottom edge (row + height) is
|
||||
// above the viewport, or its top edge is at or below the viewport's
|
||||
// last row. The same applies horizontally: a pin's column is always
|
||||
// in bounds, but a relative placement's offsets can push it fully
|
||||
// off either side.
|
||||
const grid_size = p.gridSize(image.*, t);
|
||||
const bottom_row = @as(i64, vp_row) + @as(i64, grid_size.rows);
|
||||
const visible = bottom_row > 0 and vp_row < @as(i32, t.rows);
|
||||
const right_col = @as(i64, vp_col) + @as(i64, grid_size.cols);
|
||||
const visible = bottom_row > 0 and vp_row < @as(i32, t.rows) and
|
||||
right_col > 0 and vp_col < @as(i32, t.cols);
|
||||
|
||||
return .{ .col = vp_col, .row = vp_row, .visible = visible };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user