terminal/kitty-gfx: start working on placements

This commit is contained in:
Mitchell Hashimoto
2023-08-20 16:19:23 -07:00
parent 80c7f09a36
commit 7bec2820a7
4 changed files with 77 additions and 16 deletions

View File

@ -294,6 +294,15 @@ pub const Command = struct {
}; };
} }
/// Returns the display data if it has any.
pub fn display(self: Command) ?Display {
return switch (self.control) {
.display => |d| d,
.transmit_and_display => |t| t.display,
else => null,
};
}
pub fn deinit(self: Command, alloc: Allocator) void { pub fn deinit(self: Command, alloc: Allocator) void {
if (self.data.len > 0) alloc.free(self.data); if (self.data.len > 0) alloc.free(self.data);
} }
@ -399,6 +408,7 @@ pub const Transmission = struct {
pub const Display = struct { pub const Display = struct {
image_id: u32 = 0, // i image_id: u32 = 0, // i
image_number: u32 = 0, // I image_number: u32 = 0, // I
placement_id: u32 = 0, // p
x: u32 = 0, // x x: u32 = 0, // x
y: u32 = 0, // y y: u32 = 0, // y
width: u32 = 0, // w width: u32 = 0, // w
@ -427,6 +437,10 @@ pub const Display = struct {
result.image_number = v; result.image_number = v;
} }
if (kv.get('p')) |v| {
result.placement_id = v;
}
if (kv.get('x')) |v| { if (kv.get('x')) |v| {
result.x = v; result.x = v;
} }

View File

@ -111,10 +111,18 @@ fn display(
terminal: *Terminal, terminal: *Terminal,
cmd: *Command, cmd: *Command,
) Response { ) Response {
const d = cmd.display().?;
var result: Response = .{
.id = d.image_id,
.image_number = d.image_number,
.placement_id = d.placement_id,
};
// TODO
_ = alloc; _ = alloc;
_ = terminal; _ = terminal;
_ = cmd; return result;
return .{};
} }
/// A combination of transmit and display. Nothing special. /// A combination of transmit and display. Nothing special.
@ -138,7 +146,7 @@ fn loadAndAddImage(
errdefer img.deinit(alloc); errdefer img.deinit(alloc);
// Store our image // Store our image
try terminal.screen.kitty_images.add(alloc, img); try terminal.screen.kitty_images.addImage(alloc, img);
return img; return img;
} }

View File

@ -10,6 +10,7 @@ const max_dimension = 10000;
pub const Image = struct { pub const Image = struct {
id: u32 = 0, id: u32 = 0,
number: u32 = 0,
data: []const u8, data: []const u8,
pub const Error = error{ pub const Error = error{
@ -58,6 +59,7 @@ pub const Image = struct {
return Image{ return Image{
.id = t.image_id, .id = t.image_id,
.number = t.image_number,
.data = data, .data = data,
}; };
} }

View File

@ -3,35 +3,72 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator; const ArenaAllocator = std.heap.ArenaAllocator;
const Image = @import("graphics_image.zig").Image; const point = @import("../point.zig");
const command = @import("graphics_command.zig"); const command = @import("graphics_command.zig");
const Image = @import("graphics_image.zig").Image;
const Command = command.Command; const Command = command.Command;
const ScreenPoint = point.ScreenPoint;
/// An image storage is associated with a terminal screen (i.e. main /// An image storage is associated with a terminal screen (i.e. main
/// screen, alt screen) and contains all the transmitted images and /// screen, alt screen) and contains all the transmitted images and
/// placements. /// placements.
pub const ImageStorage = struct { pub const ImageStorage = struct {
/// The hash map type used to store our images. The key is the image ID const ImageMap = std.AutoHashMapUnmanaged(u32, Image);
/// and the value is the image itself. const PlacementMap = std.AutoHashMapUnmanaged(PlacementKey, Placement);
///
/// Note that the image ID is optional when transmitting images, in
/// which case the image ID is always 0.
const HashMap = std.AutoHashMapUnmanaged(u32, Image);
/// The set of images that are currently known. /// The set of images that are currently known.
images: HashMap = .{}, images: ImageMap = .{},
/// The set of placements for loaded images.
placements: PlacementMap = .{},
pub fn deinit(self: *ImageStorage, alloc: Allocator) void {
var it = self.images.iterator();
while (it.next()) |kv| kv.value_ptr.deinit(alloc);
self.images.deinit(alloc);
self.placements.deinit(alloc);
}
/// Add an already-loaded image to the storage. This will automatically /// Add an already-loaded image to the storage. This will automatically
/// free any existing image with the same ID. /// free any existing image with the same ID.
pub fn add(self: *ImageStorage, alloc: Allocator, img: Image) !void { pub fn addImage(self: *ImageStorage, alloc: Allocator, img: Image) Allocator.Error!void {
const gop = try self.images.getOrPut(alloc, img.id); const gop = try self.images.getOrPut(alloc, img.id);
if (gop.found_existing) gop.value_ptr.deinit(alloc); if (gop.found_existing) gop.value_ptr.deinit(alloc);
gop.value_ptr.* = img; gop.value_ptr.* = img;
} }
pub fn deinit(self: *ImageStorage, alloc: Allocator) void { /// Add a placement for a given image. The caller must verify in advance
var it = self.images.iterator(); /// the image exists to prevent memory corruption.
while (it.next()) |kv| kv.value_ptr.deinit(alloc); pub fn addPlacement(
self.images.deinit(alloc); self: *ImageStorage,
alloc: Allocator,
image_id: u32,
placement_id: u32,
p: Placement,
) !void {
assert(self.images.get(image_id) != null);
const key: PlacementKey = .{ .image_id = image_id, .placement_id = placement_id };
const gop = try self.placements.getOrPut(alloc, key);
gop.value_ptr.* = p;
} }
/// Get an image by its ID. If the image doesn't exist, null is returned.
pub fn imageById(self: *ImageStorage, image_id: u32) ?Image {
return self.images.get(image_id);
}
/// Every placement is uniquely identified by the image ID and the
/// placement ID. If an image ID isn't specified it is assumed to be 0.
/// Likewise, if a placement ID isn't specified it is assumed to be 0.
pub const PlacementKey = struct {
image_id: u32,
placement_id: u32,
};
pub const Placement = struct {
/// The location of the image on the screen.
point: ScreenPoint,
};
}; };