feat(container): negative layout padding
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Has been cancelled
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Has been cancelled
Negative paddings use the current size to calculate the padding from the opposite orientation. For a given dimension (horizontal or vertical) if the size is `30` a padding of `5` would be equivalent to a padding of `-25`. This enables to describe the size of the container using the padding property of the `Layout` and gives users more freedom to describe different layouts.
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user