mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
Merge pull request #1924 from ghostty-org/kittygfx
Multiple Kitty Graphics Fixes
This commit is contained in:
@ -3124,7 +3124,7 @@ pub const Pin = struct {
|
|||||||
else
|
else
|
||||||
true;
|
true;
|
||||||
}
|
}
|
||||||
return self.x >= top.x;
|
if (self.x < top.x) return false;
|
||||||
}
|
}
|
||||||
if (self.page == bottom.page) {
|
if (self.page == bottom.page) {
|
||||||
if (self.y > bottom.y) return false;
|
if (self.y > bottom.y) return false;
|
||||||
|
@ -267,12 +267,17 @@ pub const ImageStorage = struct {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.intersect_cell => |v| intersect_cell: {
|
.intersect_cell => |v| intersect_cell: {
|
||||||
|
if (v.x <= 0 or v.y <= 0) {
|
||||||
|
log.warn("delete intersect cell coords must be at least 1", .{});
|
||||||
|
break :intersect_cell;
|
||||||
|
}
|
||||||
|
|
||||||
self.deleteIntersecting(
|
self.deleteIntersecting(
|
||||||
alloc,
|
alloc,
|
||||||
t,
|
t,
|
||||||
.{ .active = .{
|
.{ .active = .{
|
||||||
.x = std.math.cast(size.CellCountInt, v.x) orelse break :intersect_cell,
|
.x = std.math.cast(size.CellCountInt, v.x - 1) orelse break :intersect_cell,
|
||||||
.y = std.math.cast(size.CellCountInt, v.y) orelse break :intersect_cell,
|
.y = std.math.cast(size.CellCountInt, v.y - 1) orelse break :intersect_cell,
|
||||||
} },
|
} },
|
||||||
v.delete,
|
v.delete,
|
||||||
{},
|
{},
|
||||||
@ -281,12 +286,17 @@ pub const ImageStorage = struct {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.intersect_cell_z => |v| intersect_cell_z: {
|
.intersect_cell_z => |v| intersect_cell_z: {
|
||||||
|
if (v.x <= 0 or v.y <= 0) {
|
||||||
|
log.warn("delete intersect cell coords must be at least 1", .{});
|
||||||
|
break :intersect_cell_z;
|
||||||
|
}
|
||||||
|
|
||||||
self.deleteIntersecting(
|
self.deleteIntersecting(
|
||||||
alloc,
|
alloc,
|
||||||
t,
|
t,
|
||||||
.{ .active = .{
|
.{ .active = .{
|
||||||
.x = std.math.cast(size.CellCountInt, v.x) orelse break :intersect_cell_z,
|
.x = std.math.cast(size.CellCountInt, v.x - 1) orelse break :intersect_cell_z,
|
||||||
.y = std.math.cast(size.CellCountInt, v.y) orelse break :intersect_cell_z,
|
.y = std.math.cast(size.CellCountInt, v.y - 1) orelse break :intersect_cell_z,
|
||||||
} },
|
} },
|
||||||
v.delete,
|
v.delete,
|
||||||
v.z,
|
v.z,
|
||||||
@ -298,12 +308,18 @@ pub const ImageStorage = struct {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
.column => |v| {
|
.column => |v| column: {
|
||||||
|
if (v.x <= 0) {
|
||||||
|
log.warn("delete column must be greater than zero", .{});
|
||||||
|
break :column;
|
||||||
|
}
|
||||||
|
|
||||||
|
const x = v.x - 1;
|
||||||
var it = self.placements.iterator();
|
var it = self.placements.iterator();
|
||||||
while (it.next()) |entry| {
|
while (it.next()) |entry| {
|
||||||
const img = self.imageById(entry.key_ptr.image_id) orelse continue;
|
const img = self.imageById(entry.key_ptr.image_id) orelse continue;
|
||||||
const rect = entry.value_ptr.rect(img, t);
|
const rect = entry.value_ptr.rect(img, t);
|
||||||
if (rect.top_left.x <= v.x and rect.bottom_right.x >= v.x) {
|
if (rect.top_left.x <= x and rect.bottom_right.x >= x) {
|
||||||
entry.value_ptr.deinit(&t.screen);
|
entry.value_ptr.deinit(&t.screen);
|
||||||
self.placements.removeByPtr(entry.key_ptr);
|
self.placements.removeByPtr(entry.key_ptr);
|
||||||
if (v.delete) self.deleteIfUnused(alloc, img.id);
|
if (v.delete) self.deleteIfUnused(alloc, img.id);
|
||||||
@ -315,10 +331,15 @@ pub const ImageStorage = struct {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.row => |v| row: {
|
.row => |v| row: {
|
||||||
|
if (v.y <= 0) {
|
||||||
|
log.warn("delete row must be greater than zero", .{});
|
||||||
|
break :row;
|
||||||
|
}
|
||||||
|
|
||||||
// v.y is in active coords so we want to convert it to a pin
|
// v.y is in active coords so we want to convert it to a pin
|
||||||
// so we can compare by page offsets.
|
// so we can compare by page offsets.
|
||||||
const target_pin = t.screen.pages.pin(.{ .active = .{
|
const target_pin = t.screen.pages.pin(.{ .active = .{
|
||||||
.y = std.math.cast(size.CellCountInt, v.y) orelse break :row,
|
.y = std.math.cast(size.CellCountInt, v.y - 1) orelse break :row,
|
||||||
} }) orelse break :row;
|
} }) orelse break :row;
|
||||||
|
|
||||||
var it = self.placements.iterator();
|
var it = self.placements.iterator();
|
||||||
@ -629,11 +650,17 @@ pub const ImageStorage = struct {
|
|||||||
) Rect {
|
) Rect {
|
||||||
const grid_size = self.gridSize(image, t);
|
const grid_size = self.gridSize(image, t);
|
||||||
|
|
||||||
var br = switch (self.pin.downOverflow(grid_size.rows)) {
|
var br = switch (self.pin.downOverflow(grid_size.rows - 1)) {
|
||||||
.offset => |v| v,
|
.offset => |v| v,
|
||||||
.overflow => |v| v.end,
|
.overflow => |v| v.end,
|
||||||
};
|
};
|
||||||
br.x = @min(self.pin.x + grid_size.cols, t.cols - 1);
|
br.x = @min(
|
||||||
|
// We need to sub one here because the x value is
|
||||||
|
// one width already. So if the image is width "1"
|
||||||
|
// then we add zero to X because X itelf is width 1.
|
||||||
|
self.pin.x + (grid_size.cols - 1),
|
||||||
|
t.cols - 1,
|
||||||
|
);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.top_left = self.pin.*,
|
.top_left = self.pin.*,
|
||||||
@ -950,6 +977,39 @@ test "storage: delete by column" {
|
|||||||
}) != null);
|
}) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "storage: delete by column 1x1" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try terminal.Terminal.init(alloc, .{ .rows = 100, .cols = 100 });
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
t.width_px = 100;
|
||||||
|
t.height_px = 100;
|
||||||
|
|
||||||
|
var s: ImageStorage = .{};
|
||||||
|
defer s.deinit(alloc, &t.screen);
|
||||||
|
try s.addImage(alloc, .{ .id = 1, .width = 1, .height = 1 });
|
||||||
|
try s.addPlacement(alloc, 1, 1, .{ .pin = try trackPin(&t, .{ .x = 0, .y = 0 }) });
|
||||||
|
try s.addPlacement(alloc, 1, 2, .{ .pin = try trackPin(&t, .{ .x = 1, .y = 0 }) });
|
||||||
|
try s.addPlacement(alloc, 1, 3, .{ .pin = try trackPin(&t, .{ .x = 2, .y = 0 }) });
|
||||||
|
|
||||||
|
s.delete(alloc, &t, .{ .column = .{
|
||||||
|
.delete = false,
|
||||||
|
.x = 2,
|
||||||
|
} });
|
||||||
|
try testing.expectEqual(@as(usize, 2), s.placements.count());
|
||||||
|
try testing.expectEqual(@as(usize, 1), s.images.count());
|
||||||
|
|
||||||
|
// verify the placement is what we expect
|
||||||
|
try testing.expect(s.placements.get(.{
|
||||||
|
.image_id = 1,
|
||||||
|
.placement_id = .{ .tag = .external, .id = 1 },
|
||||||
|
}) != null);
|
||||||
|
try testing.expect(s.placements.get(.{
|
||||||
|
.image_id = 1,
|
||||||
|
.placement_id = .{ .tag = .external, .id = 3 },
|
||||||
|
}) != null);
|
||||||
|
}
|
||||||
|
|
||||||
test "storage: delete by row" {
|
test "storage: delete by row" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
@ -982,3 +1042,36 @@ test "storage: delete by row" {
|
|||||||
.placement_id = .{ .tag = .external, .id = 1 },
|
.placement_id = .{ .tag = .external, .id = 1 },
|
||||||
}) != null);
|
}) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "storage: delete by row 1x1" {
|
||||||
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try terminal.Terminal.init(alloc, .{ .rows = 100, .cols = 100 });
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
t.width_px = 100;
|
||||||
|
t.height_px = 100;
|
||||||
|
|
||||||
|
var s: ImageStorage = .{};
|
||||||
|
defer s.deinit(alloc, &t.screen);
|
||||||
|
try s.addImage(alloc, .{ .id = 1, .width = 1, .height = 1 });
|
||||||
|
try s.addPlacement(alloc, 1, 1, .{ .pin = try trackPin(&t, .{ .y = 0 }) });
|
||||||
|
try s.addPlacement(alloc, 1, 2, .{ .pin = try trackPin(&t, .{ .y = 1 }) });
|
||||||
|
try s.addPlacement(alloc, 1, 3, .{ .pin = try trackPin(&t, .{ .y = 2 }) });
|
||||||
|
|
||||||
|
s.delete(alloc, &t, .{ .row = .{
|
||||||
|
.delete = false,
|
||||||
|
.y = 2,
|
||||||
|
} });
|
||||||
|
try testing.expectEqual(@as(usize, 2), s.placements.count());
|
||||||
|
try testing.expectEqual(@as(usize, 1), s.images.count());
|
||||||
|
|
||||||
|
// verify the placement is what we expect
|
||||||
|
try testing.expect(s.placements.get(.{
|
||||||
|
.image_id = 1,
|
||||||
|
.placement_id = .{ .tag = .external, .id = 1 },
|
||||||
|
}) != null);
|
||||||
|
try testing.expect(s.placements.get(.{
|
||||||
|
.image_id = 1,
|
||||||
|
.placement_id = .{ .tag = .external, .id = 3 },
|
||||||
|
}) != null);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user