terminal/kitty-gfx: move cursor after image placement

This commit is contained in:
Mitchell Hashimoto
2023-08-22 12:15:51 -07:00
parent 5a9bbcbc2d
commit 71f1f35cfc
3 changed files with 70 additions and 6 deletions

View File

@ -63,6 +63,10 @@ tabstops: Tabstops,
rows: usize,
cols: usize,
/// The size of the screen in pixels. This is used for pty events and images
width_px: u32 = 0,
height_px: u32 = 0,
/// The current scrolling region.
scrolling_region: ScrollingRegion,
@ -305,6 +309,9 @@ pub fn resize(self: *Terminal, alloc: Allocator, cols_req: usize, rows: usize) !
else
cols_req;
// If our cols/rows didn't change then we're done
if (self.cols == cols and self.rows == rows) return;
// Resize our tabstops
// TODO: use resize, but it doesn't set new tabstops
if (self.cols != cols) {

View File

@ -19,7 +19,6 @@ const log = std.log.scoped(.kitty_gfx);
// - terminal state around deleting images (i.e. CSI J)
// - terminal state around deleting placements (i.e. scrolling)
// (not exhaustive, almost every op is ignoring additional config)
/// Execute a Kitty graphics command against the given terminal. This
/// will never fail, but the response may indicate an error and the
/// terminal state may not be updated to reflect the command. This will
@ -175,6 +174,58 @@ fn display(
return result;
};
// Cursor needs to move after placement
switch (d.cursor_movement) {
.none => {},
.after => {
// Determine the rectangle of the image in grid cells
const image_grid_size: struct {
columns: u32,
rows: u32,
} = grid_size: {
// Calculate our cell size.
const terminal_width_f64: f64 = @floatFromInt(terminal.width_px);
const terminal_height_f64: f64 = @floatFromInt(terminal.height_px);
const grid_columns_f64: f64 = @floatFromInt(terminal.cols);
const grid_rows_f64: f64 = @floatFromInt(terminal.rows);
const cell_width_f64 = terminal_width_f64 / grid_columns_f64;
const cell_height_f64 = terminal_height_f64 / grid_rows_f64;
// Calculate our image size in grid cells
const width_f64: f64 = @floatFromInt(img.width);
const height_f64: f64 = @floatFromInt(img.height);
const width_cells: u32 = @intFromFloat(@ceil(width_f64 / cell_width_f64));
const height_cells: u32 = @intFromFloat(@ceil(height_f64 / cell_height_f64));
break :grid_size .{ .columns = width_cells, .rows = height_cells };
};
log.warn("terminal width={} height={} image_grid={}", .{
terminal.width_px,
terminal.height_px,
image_grid_size,
});
// If we are moving beneath the screen we need to scroll.
// TODO: handle scroll regions
var new_y = terminal.screen.cursor.y + image_grid_size.rows;
if (new_y >= terminal.rows) {
const scroll_amount = (new_y + 1) - terminal.rows;
terminal.screen.scroll(.{ .screen = @intCast(scroll_amount) }) catch |err| {
// If this failed we just warn, the screen will just be in a
// weird state but nothing fatal.
log.warn("scroll for image failed: {}", .{err});
};
new_y = terminal.rows - 1;
}
// Move the cursor
terminal.setCursorPos(
terminal.screen.cursor.x + image_grid_size.columns,
new_y,
);
},
}
return result;
}

View File

@ -103,6 +103,8 @@ pub fn init(alloc: Allocator, opts: termio.Options) !Exec {
);
errdefer term.deinit(alloc);
term.color_palette = opts.config.palette;
term.width_px = opts.screen_size.width;
term.height_px = opts.screen_size.height;
var subprocess = try Subprocess.init(alloc, opts);
errdefer subprocess.deinit();
@ -255,10 +257,6 @@ pub fn resize(
const padded_size = screen_size.subPadding(padding);
try self.subprocess.resize(grid_size, padded_size);
// If our grid size didn't change, then we don't need to change
// the underlying terminal.
if (grid_size.equals(self.grid_size)) return;
// Update our cached grid size
self.grid_size = grid_size;
@ -268,7 +266,15 @@ pub fn resize(
defer self.renderer_state.mutex.unlock();
// Update the size of our terminal state
try self.terminal.resize(self.alloc, grid_size.columns, grid_size.rows);
try self.terminal.resize(
self.alloc,
grid_size.columns,
grid_size.rows,
);
// Update our pixel sizes
self.terminal.width_px = screen_size.width;
self.terminal.height_px = screen_size.height;
}
}