diff --git a/src/container.zig b/src/container.zig index ebb2595..18ce1e4 100644 --- a/src/container.zig +++ b/src/container.zig @@ -195,6 +195,33 @@ pub const Rectangle = packed struct { }, &container, @import("test/container/rectangle_with_parent_padding.zon")); } + test "fill color padding to show parent fill (negative padding)" { + const event = @import("event.zig"); + const testing = @import("testing.zig"); + + var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{ + .layout = .{ + .padding = .{ + .top = -18, + .bottom = -18, + .left = -28, + .right = -28, + }, + }, + .rectangle = .{ .fill = .green }, + }, .{}); + try container.append(try .init(std.testing.allocator, .{ + .rectangle = .{ .fill = .white }, + }, .{})); + try container.append(try .init(std.testing.allocator, .{}, .{})); + defer container.deinit(); + + try testing.expectContainerScreen(.{ + .y = 20, + .x = 30, + }, &container, @import("test/container/rectangle_with_parent_padding.zon")); + } + test "fill color spacer with padding" { const event = @import("event.zig"); const testing = @import("testing.zig"); @@ -293,23 +320,23 @@ pub const Layout = packed struct { direction: enum(u1) { horizontal, vertical } = .horizontal, /// Padding outside of the child elements padding: packed struct { - top: u16 = 0, - bottom: u16 = 0, - left: u16 = 0, - right: u16 = 0, + top: i16 = 0, + bottom: i16 = 0, + left: i16 = 0, + right: i16 = 0, /// Create a padding with equivalent padding in all four directions. - pub fn all(padding: u16) @This() { + pub fn all(padding: i16) @This() { return .{ .top = padding, .bottom = padding, .left = padding, .right = padding }; } /// Create a padding with equivalent padding in the left and right directions; others directions remain the default value. - pub fn horizontal(padding: u16) @This() { + pub fn horizontal(padding: i16) @This() { return .{ .left = padding, .right = padding }; } /// Create a padding with equivalent padding in the top and bottom directions; others directions remain the default value. - pub fn vertical(padding: u16) @This() { + pub fn vertical(padding: i16) @This() { return .{ .top = padding, .bottom = padding }; } } = .{}, @@ -326,6 +353,11 @@ pub const Layout = packed struct { } = .line, } = .{}, + /// Calculate the absolute offset for the provided `padding` if it is negative to get the absolute padding for the given `size`. + pub fn getAbsolutePadding(padding: i16, size: u16) u16 { + return if (padding >= 0) @intCast(padding) else size -| @as(u16, @intCast(-padding)); + } + pub fn content(this: @This(), comptime C: type, cells: []Cell, origin: Point, size: Point, children: []const C) void { assert(cells.len == @as(usize, size.x) * @as(usize, size.y)); @@ -609,8 +641,8 @@ pub fn Container(comptime Event: type) type { this.element.reposition(origin); var offset = origin.add(.{ - .x = layout.padding.left, - .y = layout.padding.top, + .x = Layout.getAbsolutePadding(layout.padding.left, this.size.x), + .y = Layout.getAbsolutePadding(layout.padding.top, this.size.y), }); const sides = this.properties.border.sides; @@ -642,8 +674,8 @@ pub fn Container(comptime Event: type) type { }; if (this.elements.items.len > 0) switch (layout.direction) { - .horizontal => size.x += layout.padding.left + layout.padding.right, - .vertical => size.y += layout.padding.top + layout.padding.bottom, + .horizontal => size.x += Layout.getAbsolutePadding(layout.padding.left, this.size.x) + Layout.getAbsolutePadding(layout.padding.right, this.size.x), + .vertical => size.y += Layout.getAbsolutePadding(layout.padding.top, this.size.y) + Layout.getAbsolutePadding(layout.padding.bottom, this.size.y), }; const sides = this.properties.border.sides; @@ -691,16 +723,16 @@ pub fn Container(comptime Event: type) type { fn grow_resize(this: *@This(), max_size: Point) void { const layout = this.properties.layout; var remainder = switch (layout.direction) { - .horizontal => max_size.x -| (layout.padding.left + layout.padding.right), - .vertical => max_size.y -| (layout.padding.top + layout.padding.bottom), + .horizontal => max_size.x -| (Layout.getAbsolutePadding(layout.padding.left, this.size.x) + Layout.getAbsolutePadding(layout.padding.right, this.size.x)), + .vertical => max_size.y -| (Layout.getAbsolutePadding(layout.padding.top, this.size.y) + Layout.getAbsolutePadding(layout.padding.bottom, this.size.y)), }; remainder -|= layout.gap * @as(u16, @truncate(this.elements.items.len -| 1)); if (layout.separator.enabled) remainder -|= @as(u16, @truncate(this.elements.items.len -| 1)); var available = switch (layout.direction) { - .horizontal => max_size.y -| (layout.padding.top + layout.padding.bottom), - .vertical => max_size.x -| (layout.padding.left + layout.padding.right), + .horizontal => max_size.y -| (Layout.getAbsolutePadding(layout.padding.top, this.size.y) + Layout.getAbsolutePadding(layout.padding.bottom, this.size.y)), + .vertical => max_size.x -| (Layout.getAbsolutePadding(layout.padding.left, this.size.x) + Layout.getAbsolutePadding(layout.padding.right, this.size.x)), }; const sides = this.properties.border.sides; @@ -836,6 +868,7 @@ pub fn Container(comptime Event: type) type { pub fn resize(this: *@This(), size: Point) void { // NOTE assume that this function is only called for the root `Container` + this.size = size; const fit_size = this.fit_resize(); // if (fit_size.y > size.y or fit_size.x > size.x) @panic("error: cannot render in available space"); switch (this.properties.size.grow) {