images: kitty support works well
We still need to handle querying for support. Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
This commit is contained in:
parent
ee85f49bde
commit
23a00ede55
9 changed files with 56 additions and 53 deletions
|
@ -33,8 +33,8 @@ Contributions are welcome.
|
|||
| Images (half block) | ✅ | planned | ✅ |
|
||||
| Images (quadrant) | ✅ | planned | ✅ |
|
||||
| Images (sextant) | ❌ | ❌ | ✅ |
|
||||
| Images (sixel) | ✅ | planned | ✅ |
|
||||
| Images (kitty) | ✅ | planned | ✅ |
|
||||
| Images (sixel) | ✅ | debating | ✅ |
|
||||
| Images (kitty) | ✅ | ✅ | ✅ |
|
||||
| Images (iterm2) | ❌ | ❌ | ✅ |
|
||||
| Video | ❌ | ❌ | ✅ |
|
||||
| Dank | 🆗 | 🆗 | ✅ |
|
||||
|
|
|
@ -3,89 +3,62 @@ const vaxis = @import("vaxis");
|
|||
|
||||
const log = std.log.scoped(.main);
|
||||
|
||||
// Our EventType. This can contain internal events as well as Vaxis events.
|
||||
// Internal events can be posted into the same queue as vaxis events to allow
|
||||
// for a single event loop with exhaustive switching. Booya
|
||||
const Event = union(enum) {
|
||||
key_press: vaxis.Key,
|
||||
winsize: vaxis.Winsize,
|
||||
focus_in,
|
||||
focus_out,
|
||||
foo: u8,
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
defer {
|
||||
const deinit_status = gpa.deinit();
|
||||
//fail test; can't try in defer as defer is executed after we return
|
||||
if (deinit_status == .leak) {
|
||||
log.err("memory leak", .{});
|
||||
}
|
||||
}
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
// Initialize Vaxis with our event type
|
||||
var vx = try vaxis.init(Event, .{});
|
||||
// deinit takes an optional allocator. If your program is exiting, you can
|
||||
// choose to pass a null allocator to save some exit time.
|
||||
defer vx.deinit(alloc);
|
||||
|
||||
// Start the read loop. This puts the terminal in raw mode and begins
|
||||
// reading user input
|
||||
try vx.startReadThread();
|
||||
defer vx.stopReadThread();
|
||||
|
||||
// Optionally enter the alternate screen
|
||||
try vx.enterAltScreen();
|
||||
|
||||
// Sends queries to terminal to detect certain features. This should
|
||||
// _always_ be called, but is left to the application to decide when
|
||||
try vx.queryTerminal();
|
||||
|
||||
const img = try vx.loadImage(alloc, .{ .path = "vaxis.png" });
|
||||
const imgs = [_]vaxis.Image{
|
||||
try vx.loadImage(alloc, .{ .path = "examples/zig.png" }),
|
||||
try vx.loadImage(alloc, .{ .path = "examples/vaxis.png" }),
|
||||
};
|
||||
|
||||
var n: usize = 0;
|
||||
|
||||
// The main event loop. Vaxis provides a thread safe, blocking, buffered
|
||||
// queue which can serve as the primary event queue for an application
|
||||
outer: while (true) {
|
||||
// nextEvent blocks until an event is in the queue
|
||||
while (true) {
|
||||
const event = vx.nextEvent();
|
||||
log.debug("event: {}\r\n", .{event});
|
||||
// exhaustive switching ftw. Vaxis will send events if your EventType
|
||||
// enum has the fields for those events (ie "key_press", "winsize")
|
||||
switch (event) {
|
||||
.key_press => |key| {
|
||||
n += 1;
|
||||
if (key.matches('c', .{ .ctrl = true })) {
|
||||
break :outer;
|
||||
return;
|
||||
} else if (key.matches('l', .{ .ctrl = true })) {
|
||||
vx.queueRefresh();
|
||||
} else if (key.matches('n', .{ .ctrl = true })) {
|
||||
try vx.notify("vaxis", "hello from vaxis");
|
||||
} else {}
|
||||
}
|
||||
},
|
||||
|
||||
.winsize => |ws| try vx.resize(alloc, ws),
|
||||
else => {},
|
||||
}
|
||||
|
||||
// vx.window() returns the root window. This window is the size of the
|
||||
// terminal and can spawn child windows as logical areas. Child windows
|
||||
// cannot draw outside of their bounds
|
||||
n = (n + 1) % imgs.len;
|
||||
const win = vx.window();
|
||||
|
||||
// Clear the entire space because we are drawing in immediate mode.
|
||||
// vaxis double buffers the screen. This new frame will be compared to
|
||||
// the old and only updated cells will be drawn
|
||||
win.clear();
|
||||
|
||||
const child = win.initChild(n, n, .expand, .expand);
|
||||
const img = imgs[n];
|
||||
const dims = try img.cellSize(win);
|
||||
const center = vaxis.alignment.center(win, dims.cols, dims.rows);
|
||||
const scale = false;
|
||||
const z_index = 0;
|
||||
img.draw(center, scale, z_index);
|
||||
|
||||
img.draw(child, false, 0);
|
||||
|
||||
// Render the screen
|
||||
try vx.render();
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
BIN
examples/zig.png
Normal file
BIN
examples/zig.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
|
@ -6,7 +6,6 @@ const base64 = std.base64.standard.Encoder;
|
|||
const zigimg = @import("zigimg");
|
||||
|
||||
const Window = @import("Window.zig");
|
||||
const Winsize = @import("Tty.zig").Winsize;
|
||||
|
||||
const log = std.log.scoped(.image);
|
||||
|
||||
|
@ -22,7 +21,7 @@ pub const Source = union(enum) {
|
|||
pub const Placement = struct {
|
||||
img_id: u32,
|
||||
z_index: i32,
|
||||
scale: bool,
|
||||
size: ?CellSize = null,
|
||||
};
|
||||
|
||||
pub const CellSize = struct {
|
||||
|
@ -42,15 +41,26 @@ pub fn draw(self: Image, win: Window, scale: bool, z_index: i32) void {
|
|||
const p = Placement{
|
||||
.img_id = self.id,
|
||||
.z_index = z_index,
|
||||
.scale = scale,
|
||||
.size = sz: {
|
||||
if (!scale) break :sz null;
|
||||
break :sz CellSize{
|
||||
.rows = win.height,
|
||||
.cols = win.width,
|
||||
};
|
||||
},
|
||||
};
|
||||
win.writeCell(0, 0, .{ .image = p });
|
||||
}
|
||||
|
||||
pub fn cellSize(self: Image, winsize: Winsize) !CellSize {
|
||||
pub fn cellSize(self: Image, win: Window) !CellSize {
|
||||
// cell geometry
|
||||
const pix_per_col = try std.math.divCeil(usize, winsize.x_pixel, winsize.cols);
|
||||
const pix_per_row = try std.math.divCeil(usize, winsize.y_pixel, winsize.rows);
|
||||
const x_pix = win.screen.width_pix;
|
||||
const y_pix = win.screen.height_pix;
|
||||
const w = win.screen.width;
|
||||
const h = win.screen.height;
|
||||
|
||||
const pix_per_col = try std.math.divCeil(usize, x_pix, w);
|
||||
const pix_per_row = try std.math.divCeil(usize, y_pix, h);
|
||||
|
||||
const cell_width = std.math.divCeil(usize, self.width, pix_per_col) catch 0;
|
||||
const cell_height = std.math.divCeil(usize, self.height, pix_per_row) catch 0;
|
||||
|
|
|
@ -9,6 +9,8 @@ pub const Key = @import("Key.zig");
|
|||
pub const Winsize = @import("Tty.zig").Winsize;
|
||||
|
||||
pub const widgets = @import("widgets/main.zig");
|
||||
pub const alignment = widgets.alignment;
|
||||
pub const border = widgets.border;
|
||||
|
||||
pub const Image = @import("Image.zig");
|
||||
|
||||
|
@ -30,7 +32,6 @@ test {
|
|||
_ = @import("ctlseqs.zig");
|
||||
_ = @import("event.zig");
|
||||
_ = @import("gwidth.zig");
|
||||
_ = @import("image/image.zig");
|
||||
_ = @import("queue.zig");
|
||||
_ = @import("vaxis.zig");
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ pub fn Vaxis(comptime T: type) type {
|
|||
|
||||
pub const Capabilities = struct {
|
||||
kitty_keyboard: bool = false,
|
||||
kitty_graphics: bool = false,
|
||||
rgb: bool = false,
|
||||
unicode: bool = false,
|
||||
};
|
||||
|
@ -60,8 +61,6 @@ pub fn Vaxis(comptime T: type) type {
|
|||
alt_screen: bool = false,
|
||||
/// if we have entered kitty keyboard
|
||||
kitty_keyboard: bool = false,
|
||||
// TODO: should be false but we aren't querying yet
|
||||
kitty_graphics: bool = true,
|
||||
bracketed_paste: bool = false,
|
||||
mouse: bool = false,
|
||||
} = .{},
|
||||
|
@ -337,7 +336,19 @@ pub fn Vaxis(comptime T: type) type {
|
|||
}
|
||||
|
||||
if (cell.image) |img| {
|
||||
try std.fmt.format(tty.buffered_writer.writer(), ctlseqs.kitty_graphics_place, .{ img.img_id, img.z_index });
|
||||
if (img.size) |size| {
|
||||
try std.fmt.format(
|
||||
tty.buffered_writer.writer(),
|
||||
ctlseqs.kitty_graphics_scale,
|
||||
.{ img.img_id, img.z_index, size.cols, size.rows },
|
||||
);
|
||||
} else {
|
||||
try std.fmt.format(
|
||||
tty.buffered_writer.writer(),
|
||||
ctlseqs.kitty_graphics_place,
|
||||
.{ img.img_id, img.z_index },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// something is different, so let's loop throuugh everything and
|
||||
|
|
7
src/widgets/align.zig
Normal file
7
src/widgets/align.zig
Normal file
|
@ -0,0 +1,7 @@
|
|||
const Window = @import("../Window.zig");
|
||||
|
||||
pub fn center(parent: Window, cols: usize, rows: usize) Window {
|
||||
const y_off = (parent.height / 2) - (rows / 2);
|
||||
const x_off = (parent.width / 2) - (cols / 2);
|
||||
return parent.initChild(x_off, y_off, .{ .limit = cols }, .{ .limit = rows });
|
||||
}
|
|
@ -1,2 +1,3 @@
|
|||
pub const TextInput = @import("TextInput.zig");
|
||||
pub const border = @import("border.zig");
|
||||
pub const alignment = @import("align.zig");
|
||||
|
|
Loading…
Reference in a new issue