this repo has no description
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

images: move to subfolder, use union enum for implementations

There will only ever be a handful of image implementations. Let's just
use a union enum for handling them.

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>

+77 -158
-84
src/Image.zig
··· 1 - const std = @import("std"); 2 - const math = std.math; 3 - const testing = std.testing; 4 - const zigimg = @import("zigimg"); 5 - 6 - const Window = @import("Window.zig"); 7 - const Winsize = @import("Tty.zig").Winsize; 8 - 9 - const Image = @This(); 10 - 11 - pub const Source = union(enum) { 12 - /// loads an image from a path. path can be relative to cwd, or absolute 13 - path: []const u8, 14 - /// loads an image from raw bytes 15 - mem: []const u8, 16 - }; 17 - 18 - pub const Protocol = enum { 19 - kitty, 20 - // TODO: sixel, full block, half block, quad block 21 - }; 22 - 23 - /// the decoded image 24 - img: zigimg.Image, 25 - 26 - /// unique identifier for this image 27 - id: u32, 28 - 29 - /// width of the image, in cells 30 - cell_width: usize, 31 - /// height of the image, in cells 32 - cell_height: usize, 33 - 34 - /// initialize a new image 35 - pub fn init( 36 - alloc: std.mem.Allocator, 37 - winsize: Winsize, 38 - src: Source, 39 - id: u32, 40 - ) !Image { 41 - const img = switch (src) { 42 - .path => |path| try zigimg.Image.fromFilePath(alloc, path), 43 - .mem => |bytes| try zigimg.Image.fromMemory(alloc, bytes), 44 - }; 45 - // cell geometry 46 - const pix_per_col = try math.divCeil(usize, winsize.x_pixel, winsize.cols); 47 - const pix_per_row = try math.divCeil(usize, winsize.y_pixel, winsize.rows); 48 - 49 - const cell_width = math.divCeil(usize, img.width, pix_per_col) catch 0; 50 - const cell_height = math.divCeil(usize, img.height, pix_per_row) catch 0; 51 - 52 - return Image{ 53 - .img = img, 54 - .cell_width = cell_width, 55 - .cell_height = cell_height, 56 - .id = id, 57 - }; 58 - } 59 - 60 - pub fn deinit(self: *Image) void { 61 - self.img.deinit(); 62 - } 63 - 64 - pub fn draw(self: *Image, win: Window, placement_id: u32) !void { 65 - try win.writeImage(win.x_off, win.y_off, self, placement_id); 66 - } 67 - 68 - test "image" { 69 - const alloc = testing.allocator; 70 - var img = try init( 71 - alloc, 72 - .{ 73 - .rows = 1, 74 - .cols = 1, 75 - .x_pixel = 1, 76 - .y_pixel = 1, 77 - }, 78 - .{ .path = "vaxis.png" }, 79 - 1, 80 - ); 81 - defer img.deinit(); 82 - try testing.expectEqual(200, img.cell_width); 83 - try testing.expectEqual(197, img.cell_height); 84 - }
+1 -1
src/InternalScreen.zig
··· 3 3 const Style = @import("cell.zig").Style; 4 4 const Cell = @import("cell.zig").Cell; 5 5 const Shape = @import("Mouse.zig").Shape; 6 - const Image = @import("Image.zig").Placement; 6 + const Image = @import("image/image.zig").Image; 7 7 const Placement = @import("Screen.zig").Placement; 8 8 9 9 const log = std.log.scoped(.internal_screen);
+9 -1
src/Screen.zig
··· 3 3 4 4 const Cell = @import("cell.zig").Cell; 5 5 const Shape = @import("Mouse.zig").Shape; 6 - const Image = @import("Image.zig"); 6 + const Image = @import("image/image.zig").Image; 7 7 8 8 const log = std.log.scoped(.screen); 9 9 ··· 14 14 placement_id: u32, 15 15 col: usize, 16 16 row: usize, 17 + 18 + /// two placements are considered equal if their image id and their 19 + /// placement id are equal 20 + pub fn eql(self: Placement, tgt: Placement) bool { 21 + if (self.img.getId() != tgt.img.getId()) return false; 22 + if (self.placement_id != tgt.placement_id) return false; 23 + return true; 24 + } 17 25 }; 18 26 19 27 width: usize = 0,
+3 -6
src/Window.zig
··· 2 2 3 3 const Screen = @import("Screen.zig"); 4 4 const Cell = @import("cell.zig").Cell; 5 - const Image = @import("Image.zig"); 5 + const Image = @import("image/image.zig").Image; 6 6 const gw = @import("gwidth.zig"); 7 7 8 8 const log = std.log.scoped(.window); ··· 69 69 self.screen.writeCell(col + self.x_off, row + self.y_off, cell); 70 70 } 71 71 72 - /// writes a cell to the location in the window 72 + /// writes an image to the location in the window 73 73 pub fn writeImage( 74 74 self: Window, 75 - col: usize, 76 - row: usize, 77 75 img: *Image, 78 76 placement_id: u32, 79 77 ) !void { 80 78 if (self.height == 0 or self.width == 0) return; 81 - if (self.height <= row or self.width <= col) return; 82 - self.screen.writeImage(col, row, img, placement_id); 79 + self.screen.writeImage(self.x_off, self.y_off, img, placement_id); 83 80 } 84 81 85 82 /// fills the window with the default cell
+12 -50
src/image/Kitty.zig
··· 12 12 /// the decoded image 13 13 img: zigimg.Image, 14 14 15 - /// unique identifier for this image 16 - id: u32, 15 + /// unique identifier for this image. This will be managed by the screen. The ID 16 + /// is only null for images which have not been transmitted to the screen 17 + id: ?u32 = null, 17 18 18 19 /// width of the image, in cells 19 20 cell_width: usize, 20 21 /// height of the image, in cells 21 22 cell_height: usize, 22 23 23 - /// initialize a new image 24 - pub fn init( 25 - alloc: std.mem.Allocator, 26 - winsize: Winsize, 27 - src: []const u8, 28 - id: u32, 29 - ) !Kitty { 30 - const img = switch (src) { 31 - .path => |path| try zigimg.Image.fromFilePath(alloc, path), 32 - .mem => |bytes| try zigimg.Image.fromMemory(alloc, bytes), 33 - }; 34 - // cell geometry 35 - const pix_per_col = try math.divCeil(usize, winsize.x_pixel, winsize.cols); 36 - const pix_per_row = try math.divCeil(usize, winsize.y_pixel, winsize.rows); 37 - 38 - const cell_width = math.divCeil(usize, img.width, pix_per_col) catch 0; 39 - const cell_height = math.divCeil(usize, img.height, pix_per_row) catch 0; 40 - 41 - return Image{ 42 - .img = img, 43 - .cell_width = cell_width, 44 - .cell_height = cell_height, 45 - .id = id, 46 - }; 47 - } 48 - 49 - pub fn deinit(self: *Image) void { 24 + pub fn deinit(self: *Kitty) void { 50 25 self.img.deinit(); 51 26 } 52 27 53 - pub fn draw(self: *Image, win: Window, placement_id: u32) !void { 54 - try win.writeImage(win.x_off, win.y_off, self, placement_id); 55 - } 56 - 57 - test "image" { 58 - const alloc = testing.allocator; 59 - var img = try init( 60 - alloc, 61 - .{ 62 - .rows = 1, 63 - .cols = 1, 64 - .x_pixel = 1, 65 - .y_pixel = 1, 66 - }, 67 - .{ .path = "vaxis.png" }, 68 - 0, 69 - .kitty, 70 - ); 71 - defer img.deinit(); 72 - try testing.expectEqual(200, img.cell_width); 73 - try testing.expectEqual(197, img.cell_height); 28 + pub fn draw(self: *Kitty, win: Window) !void { 29 + const row: u16 = @truncate(win.y_off); 30 + const col: u16 = @truncate(win.x_off); 31 + // the placement id has the high 16 bits as the column and the low 16 32 + // bits as the row. This means we can only place this image one time at 33 + // the same location - which is completely sane 34 + const pid: u32 = col << 16 | row; 35 + try win.writeImage(win.x_off, win.y_off, self, pid); 74 36 }
+37 -12
src/image/image.zig
··· 8 8 9 9 const Kitty = @import("Kitty.zig"); 10 10 11 + pub const Protocol = enum { 12 + kitty, 13 + // TODO: sixel, full block, half block, quad block 14 + }; 15 + 11 16 pub const Image = union(enum) { 12 17 kitty: Kitty, 13 18 14 - pub const Protocol = enum { 15 - kitty, 16 - // TODO: sixel, full block, half block, quad block 17 - }; 18 - 19 19 /// initialize a new image 20 20 pub fn init( 21 21 alloc: std.mem.Allocator, 22 22 winsize: Winsize, 23 23 src: []const u8, 24 - id: u32, 25 24 protocol: Protocol, 26 25 ) !Image { 26 + const img = switch (src) { 27 + .path => |path| try zigimg.Image.fromFilePath(alloc, path), 28 + .mem => |bytes| try zigimg.Image.fromMemory(alloc, bytes), 29 + }; 30 + // cell geometry 31 + const pix_per_col = try math.divCeil(usize, winsize.x_pixel, winsize.cols); 32 + const pix_per_row = try math.divCeil(usize, winsize.y_pixel, winsize.rows); 33 + 34 + const cell_width = math.divCeil(usize, img.width, pix_per_col) catch 0; 35 + const cell_height = math.divCeil(usize, img.height, pix_per_row) catch 0; 36 + 27 37 switch (protocol) { 28 38 .kitty => { 29 - const img = try Kitty.init(alloc, winsize, src, id); 30 - return .{ .kitty = img }; 39 + return .{ 40 + .kitty = Kitty{ 41 + .img = img, 42 + .cell_width = cell_width, 43 + .cell_height = cell_height, 44 + }, 45 + }; 31 46 }, 32 47 } 33 48 } 34 49 35 - pub fn deinit(self: *Image) void { 36 - self.img.deinit(); 50 + pub fn deinit(self: Image) void { 51 + switch (self) { 52 + inline else => |case| case.deinit(), 53 + } 37 54 } 38 55 39 - pub fn draw(self: *Image, win: Window, placement_id: u32) !void { 40 - try win.writeImage(win.x_off, win.y_off, self, placement_id); 56 + pub fn draw(self: Image, win: Window) !void { 57 + switch (self) { 58 + inline else => |case| case.draw(win), 59 + } 60 + } 61 + 62 + pub fn getId(self: Image) ?u32 { 63 + switch (self) { 64 + .kitty => |k| return k.id, 65 + } 41 66 } 42 67 };
+1 -1
src/main.zig
··· 17 17 18 18 test { 19 19 _ = @import("GraphemeCache.zig"); 20 - _ = @import("Image.zig"); 21 20 _ = @import("Key.zig"); 22 21 _ = @import("Mouse.zig"); 23 22 _ = @import("Options.zig"); ··· 29 28 _ = @import("ctlseqs.zig"); 30 29 _ = @import("event.zig"); 31 30 _ = @import("gwidth.zig"); 31 + _ = @import("image/image.zig"); 32 32 _ = @import("queue.zig"); 33 33 _ = @import("vaxis.zig"); 34 34 }
+14 -3
src/vaxis.zig
··· 280 280 var cursor: Style = .{}; 281 281 var link: Hyperlink = .{}; 282 282 283 - // delete remove images from the screen by looping through the 284 - // current state and comparing to the next state 283 + // remove images from the screen by looping through the last state 284 + // and comparing to the next state 285 285 for (self.screen_last.images.items) |last_img| { 286 286 const keep: bool = for (self.screen.images.items) |next_img| { 287 - if (std.meta.eql(last_img, next_img)) break true; 287 + if (last_img.eql(next_img)) break true; 288 288 } else false; 289 289 if (keep) continue; 290 + // TODO: remove image placements 291 + } 292 + 293 + // add new images. Could slightly optimize by knowing which images 294 + // we need to keep from the remove loop 295 + for (self.screen.images.items) |img| { 296 + const transmit: bool = for (self.screen_last.images.items) |last_img| { 297 + if (last_img.eql(img)) break false; 298 + } else true; 299 + if (!transmit) continue; 300 + // TODO: transmit the new image to the screen 290 301 } 291 302 292 303 var i: usize = 0;