diff options
Diffstat (limited to 'src/web.zig')
| -rw-r--r-- | src/web.zig | 77 |
1 files changed, 66 insertions, 11 deletions
diff --git a/src/web.zig b/src/web.zig index a1f3bad8..a944a4a5 100644 --- a/src/web.zig +++ b/src/web.zig @@ -99,6 +99,7 @@ comptime { const State = struct { core: *pardes.Pardes, + layer_cells: [pardes.MAX_PANES][]WebCell = @splat(&.{}), cells: []WebCell = &.{}, frame_len: usize = 0, frame_cols: u16 = 0, @@ -127,6 +128,7 @@ const State = struct { fn deinit(s: *State) void { if (s.cells.len > 0) gpa.free(s.cells); + for (s.layer_cells) |cells| gpa.free(cells); s.core.deinit(); pardes.image.stop(); if (comptime pardes.pdf_enabled) pardes.pdf.stop(); @@ -207,6 +209,22 @@ export fn pardes_paste(len_arg: u32) void { /// Buttons and kinds are their boundary enum ordinals. Invalid values are /// ignored rather than reaching an unchecked enum cast inside wasm. export fn pardes_mouse(button_arg: u32, kind_arg: u32, col_arg: u32, row_arg: u32, mods: u32) void { + mouseWithHit(button_arg, kind_arg, col_arg, row_arg, mods, null); +} + +export fn pardes_mouse_pixel(button_arg: u32, kind_arg: u32, col_arg: u32, row_arg: u32, mods: u32, x: f32, y: f32, bw: f32, bh: f32, tw: f32, th: f32) void { + const s = &(state orelse return); + const source = s.core.presentation.pointerFractional(s.core.screen_w, s.core.screen_h, x / @max(1, bw), y / @max(1, bh)); + var hit: ?pardes.Mouse.BodyHit = null; + for (&s.core.surface.body_layers) |*layer| { + const point = source orelse break; + hit = layer.hitAt(point.x * bw, point.y * bh, bw, bh, tw, th); + if (hit != null) break; + } + mouseWithHit(button_arg, kind_arg, col_arg, row_arg, mods, hit); +} + +fn mouseWithHit(button_arg: u32, kind_arg: u32, col_arg: u32, row_arg: u32, mods: u32, hit: ?pardes.Mouse.BodyHit) void { const s = &(state orelse return); const button: pardes.Mouse.Button = switch (button_arg) { 0 => .left, @@ -229,6 +247,7 @@ export fn pardes_mouse(button_arg: u32, kind_arg: u32, col_arg: u32, row_arg: u3 else => return, }; s.core.update(.{ .mouse = .{ + .body_hit = hit, .button = button, .kind = kind, .col = @intCast(@min(col_arg, std.math.maxInt(u16))), @@ -304,6 +323,46 @@ export fn pardes_cursor_x() i32 { return if (s.core.surface.cursor) |cursor| cursor.x else -1; } +export fn pardes_body_layer_value(index: u32, field: u32) u32 { + const s = &(state orelse return 0); + if (index >= pardes.MAX_PANES) return 0; + const layer = &s.core.surface.body_layers[index]; + return switch (field) { + 0 => layer.rows, + 1 => layer.cols, + 2 => layer.context_rows, + 3 => layer.viewport.x, + 4 => layer.viewport.y, + 5 => layer.viewport.w, + 6 => layer.viewport.h, + 7 => layer.serial, + 8 => if (layer.cursor) |c| c.x else 65535, + 9 => if (layer.cursor) |c| c.y else 65535, + 10 => if (layer.cursor) |c| @intFromBool(c.bar) else 0, + else => 0, + }; +} + +export fn pardes_body_layer_cells(index: u32) ?[*]const WebCell { + const s = &(state orelse return null); + if (index >= pardes.MAX_PANES) return null; + const layer = &s.core.surface.body_layers[index]; + if (layer.rows == 0) return null; + const cells = &s.layer_cells[index]; + if (cells.len != layer.cells.len) cells.* = gpa.realloc(cells.*, layer.cells.len) catch return null; + for (layer.cells, cells.*) |cell, *out| out.* = encodeWebCell(cell); + return cells.ptr; +} + +export fn pardes_body_layer_limit() u32 { + return pardes.MAX_PANES; +} + +export fn pardes_row_metrics(body_w: u16, body_h: u16, tagline_w: u16, tagline_h: u16) void { + const s = &(state orelse return); + s.core.update(.{ .resize = .{ .cols = s.core.screen_w, .rows = s.core.screen_h, .cell_pixels = s.core.cell_pixels, .row_metrics = .{ .body_w = @max(1, body_w), .body_h = @max(1, body_h), .tagline_w = @max(1, tagline_w), .tagline_h = @max(1, tagline_h) } } }); +} + export fn pardes_pointer_shape() u32 { const s = &(state orelse return 0); return @intFromEnum(s.core.surface.pointer_shape); @@ -384,17 +443,13 @@ fn present(ctx: ?*anyopaque, surface: *const pardes.Surface) void { s.frame_len = count; s.frame_cols = surface.cols; s.frame_rows = surface.rows; - for (surface.cells, s.cells[0..count]) |cell, *out| { - out.* = .{ - .text = @splat(0), - .fg = encodeColor(cell.style.fg), - .bg = encodeColor(cell.style.bg), - .attrs = encodeAttrs(cell.style), - .len = if (cell.default) 1 else cell.len, - .flags = @intFromBool(cell.default), - }; - if (cell.default) out.text[0] = ' ' else @memcpy(out.text[0..cell.len], cell.grapheme()); - } + for (surface.cells, s.cells[0..count]) |cell, *out| out.* = encodeWebCell(cell); +} + +fn encodeWebCell(cell: pardes.Cell) WebCell { + var out: WebCell = .{ .text = @splat(0), .fg = encodeColor(cell.style.fg), .bg = encodeColor(cell.style.bg), .attrs = encodeAttrs(cell.style), .len = if (cell.default) 1 else cell.len, .flags = @intFromBool(cell.default) }; + if (cell.default) out.text[0] = ' ' else @memcpy(out.text[0..cell.len], cell.grapheme()); + return out; } fn writeFile(_: ?*anyopaque, _: u8, path: []const u8, bytes: []const u8) void { |
