fix(container): positioning; move separator options to layout struct
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 22s
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 22s
Added corresponding test cases for padding, borders and corresponding seperators.
This commit is contained in:
@@ -73,11 +73,9 @@ pub fn main() !void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var container = try App.Container.init(allocator, .{
|
var container = try App.Container.init(allocator, .{
|
||||||
.border = .{
|
|
||||||
.separator = .{ .enabled = true },
|
|
||||||
},
|
|
||||||
.layout = .{
|
.layout = .{
|
||||||
.gap = 2,
|
.gap = 2,
|
||||||
|
.separator = .{ .enabled = true },
|
||||||
.padding = .{ .top = 5, .bottom = 3, .left = 3, .right = 3 },
|
.padding = .{ .top = 5, .bottom = 3, .left = 3, .right = 3 },
|
||||||
.direction = .horizontal,
|
.direction = .horizontal,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -73,9 +73,9 @@ pub fn main() !void {
|
|||||||
defer top_box.deinit();
|
defer top_box.deinit();
|
||||||
|
|
||||||
var bottom_box = try App.Container.init(allocator, .{
|
var bottom_box = try App.Container.init(allocator, .{
|
||||||
.border = .{ .separator = .{ .enabled = true } },
|
|
||||||
.rectangle = .{ .fill = .blue },
|
.rectangle = .{ .fill = .blue },
|
||||||
.layout = .{
|
.layout = .{
|
||||||
|
.separator = .{ .enabled = true },
|
||||||
.direction = .vertical,
|
.direction = .vertical,
|
||||||
.padding = .vertical(1),
|
.padding = .vertical(1),
|
||||||
},
|
},
|
||||||
@@ -93,14 +93,12 @@ pub fn main() !void {
|
|||||||
defer bottom_box.deinit();
|
defer bottom_box.deinit();
|
||||||
|
|
||||||
var container = try App.Container.init(allocator, .{
|
var container = try App.Container.init(allocator, .{
|
||||||
.border = .{
|
.layout = .{
|
||||||
|
.gap = 2,
|
||||||
.separator = .{
|
.separator = .{
|
||||||
.enabled = true,
|
.enabled = true,
|
||||||
.line = .double,
|
.line = .double,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
.layout = .{
|
|
||||||
.gap = 2,
|
|
||||||
.padding = .all(5),
|
.padding = .all(5),
|
||||||
.direction = .vertical,
|
.direction = .vertical,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -50,16 +50,16 @@ pub fn main() !void {
|
|||||||
const element = quit_text.element();
|
const element = quit_text.element();
|
||||||
|
|
||||||
var container = try App.Container.init(allocator, .{
|
var container = try App.Container.init(allocator, .{
|
||||||
.border = .{ .separator = .{ .enabled = true } },
|
|
||||||
.layout = .{
|
.layout = .{
|
||||||
|
.separator = .{ .enabled = true },
|
||||||
.padding = .{ .top = 5, .bottom = 3, .left = 3, .right = 3 },
|
.padding = .{ .top = 5, .bottom = 3, .left = 3, .right = 3 },
|
||||||
.direction = .horizontal,
|
.direction = .horizontal,
|
||||||
},
|
},
|
||||||
}, element);
|
}, element);
|
||||||
for (0..3) |_| {
|
for (0..3) |_| {
|
||||||
var column = try App.Container.init(allocator, .{
|
var column = try App.Container.init(allocator, .{
|
||||||
.border = .{ .separator = .{ .enabled = true } },
|
|
||||||
.layout = .{
|
.layout = .{
|
||||||
|
.separator = .{ .enabled = true },
|
||||||
.direction = .vertical,
|
.direction = .vertical,
|
||||||
},
|
},
|
||||||
}, .{});
|
}, .{});
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ pub fn main() !void {
|
|||||||
}, element);
|
}, element);
|
||||||
for (0..3) |i| {
|
for (0..3) |i| {
|
||||||
var column = try App.Container.init(allocator, .{
|
var column = try App.Container.init(allocator, .{
|
||||||
.border = .{ .separator = .{ .enabled = true } },
|
|
||||||
.layout = .{
|
.layout = .{
|
||||||
|
.separator = .{ .enabled = true },
|
||||||
.direction = if (i > 0) .vertical else .horizontal,
|
.direction = if (i > 0) .vertical else .horizontal,
|
||||||
},
|
},
|
||||||
}, .{});
|
}, .{});
|
||||||
|
|||||||
@@ -12,12 +12,8 @@ const log = std.log.scoped(.container);
|
|||||||
/// Border configuration struct
|
/// Border configuration struct
|
||||||
pub const Border = packed struct {
|
pub const Border = packed struct {
|
||||||
// corners:
|
// corners:
|
||||||
pub const rounded_border: [6]u21 = .{ '╭', '─', '╮', '│', '╰', '╯' };
|
const rounded_border: [6]u21 = .{ '╭', '─', '╮', '│', '╰', '╯' };
|
||||||
pub const squared_border: [6]u21 = .{ '┌', '─', '┐', '│', '└', '┘' };
|
const squared_border: [6]u21 = .{ '┌', '─', '┐', '│', '└', '┘' };
|
||||||
// separator.line:
|
|
||||||
pub const line: [2]u21 = .{ '│', '─' };
|
|
||||||
pub const dotted: [2]u21 = .{ '┆', '┄' };
|
|
||||||
pub const double: [2]u21 = .{ '║', '═' };
|
|
||||||
|
|
||||||
/// Color to use for the border
|
/// Color to use for the border
|
||||||
color: Color = .default,
|
color: Color = .default,
|
||||||
@@ -40,19 +36,8 @@ pub const Border = packed struct {
|
|||||||
/// Enable border sides for the top and bottom sides
|
/// Enable border sides for the top and bottom sides
|
||||||
pub const vertical: @This() = .{ .top = true, .bottom = true };
|
pub const vertical: @This() = .{ .top = true, .bottom = true };
|
||||||
} = .{},
|
} = .{},
|
||||||
/// Configure separator borders between child element to added to the layout
|
|
||||||
separator: packed struct {
|
|
||||||
enabled: bool = false,
|
|
||||||
color: Color = .white,
|
|
||||||
line: enum(u2) {
|
|
||||||
line,
|
|
||||||
dotted,
|
|
||||||
double,
|
|
||||||
} = .line,
|
|
||||||
} = .{},
|
|
||||||
|
|
||||||
// NOTE: caller owns `cells` slice and ensures that `cells.len == size.cols * size.rows`
|
pub fn contents(this: @This(), cells: []Cell, size: Size) void {
|
||||||
pub fn contents(this: @This(), cells: []Cell, size: Size, layout: Layout, len: u16) void {
|
|
||||||
std.debug.assert(cells.len == @as(usize, size.cols) * @as(usize, size.rows));
|
std.debug.assert(cells.len == @as(usize, size.cols) * @as(usize, size.rows));
|
||||||
|
|
||||||
const frame = switch (this.corners) {
|
const frame = switch (this.corners) {
|
||||||
@@ -95,85 +80,6 @@ pub const Border = packed struct {
|
|||||||
cells[idx + size.cols - 1].style.fg = this.color;
|
cells[idx + size.cols - 1].style.fg = this.color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.separator.enabled) {
|
|
||||||
// calculate where the separator would need to be
|
|
||||||
// TODO: use the childrens size to determine the location of the separator instead?
|
|
||||||
const gap = layout.gap + 1;
|
|
||||||
const element_cols = blk: {
|
|
||||||
var cols = size.cols - gap * (len - 1);
|
|
||||||
if (this.sides.left) cols -= 1;
|
|
||||||
if (this.sides.right) cols -= 1;
|
|
||||||
cols -= layout.padding.left + layout.padding.right;
|
|
||||||
break :blk @divTrunc(cols, len);
|
|
||||||
};
|
|
||||||
const element_rows = blk: {
|
|
||||||
var rows = size.rows - gap * (len - 1);
|
|
||||||
if (this.sides.top) rows -= 1;
|
|
||||||
if (this.sides.bottom) rows -= 1;
|
|
||||||
rows -= layout.padding.top + layout.padding.bottom;
|
|
||||||
break :blk @divTrunc(rows, len);
|
|
||||||
};
|
|
||||||
var offset: u16 = switch (layout.direction) {
|
|
||||||
.horizontal => layout.padding.left,
|
|
||||||
.vertical => layout.padding.top,
|
|
||||||
};
|
|
||||||
var overflow = switch (layout.direction) {
|
|
||||||
.horizontal => blk: {
|
|
||||||
var cols = size.cols - gap * (len - 1);
|
|
||||||
if (this.sides.left) cols -= 1;
|
|
||||||
if (this.sides.right) cols -= 1;
|
|
||||||
cols -= layout.padding.left + layout.padding.right;
|
|
||||||
break :blk cols - element_cols * len;
|
|
||||||
},
|
|
||||||
.vertical => blk: {
|
|
||||||
var rows = size.rows - gap * (len - 1);
|
|
||||||
if (this.sides.top) rows -= 1;
|
|
||||||
if (this.sides.bottom) rows -= 1;
|
|
||||||
rows -= layout.padding.top + layout.padding.bottom;
|
|
||||||
break :blk rows - element_rows * len;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const line_cps: [2]u21 = switch (this.separator.line) {
|
|
||||||
.line => line,
|
|
||||||
.dotted => dotted,
|
|
||||||
.double => double,
|
|
||||||
};
|
|
||||||
switch (layout.direction) {
|
|
||||||
.horizontal => {
|
|
||||||
offset += gap / 2;
|
|
||||||
for (0..len - 1) |_| {
|
|
||||||
var cols = element_cols;
|
|
||||||
if (overflow > 0) {
|
|
||||||
overflow -|= 1;
|
|
||||||
cols += 1;
|
|
||||||
}
|
|
||||||
offset += cols;
|
|
||||||
for (1..size.rows -| 1) |row| {
|
|
||||||
cells[row * size.cols + offset].cp = line_cps[0];
|
|
||||||
cells[row * size.cols + offset].style.fg = this.separator.color;
|
|
||||||
}
|
|
||||||
offset += gap;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
.vertical => {
|
|
||||||
offset += gap / 2;
|
|
||||||
for (0..len - 1) |_| {
|
|
||||||
var rows = element_rows;
|
|
||||||
if (overflow > 0) {
|
|
||||||
overflow -|= 1;
|
|
||||||
rows += 1;
|
|
||||||
}
|
|
||||||
offset += rows;
|
|
||||||
for (1..size.cols -| 1) |col| {
|
|
||||||
cells[offset * size.cols + col].cp = line_cps[1];
|
|
||||||
cells[offset * size.cols + col].style.fg = this.separator.color;
|
|
||||||
}
|
|
||||||
offset += gap;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "all sides" {
|
test "all sides" {
|
||||||
@@ -229,79 +135,6 @@ pub const Border = packed struct {
|
|||||||
.cols = 30,
|
.cols = 30,
|
||||||
}, &container, @import("test/container/border.horizontal.zon"));
|
}, &container, @import("test/container/border.horizontal.zon"));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "separator without gaps" {
|
|
||||||
const event = @import("event.zig");
|
|
||||||
const testing = @import("testing.zig");
|
|
||||||
|
|
||||||
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
|
||||||
.border = .{
|
|
||||||
.separator = .{
|
|
||||||
.enabled = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, .{});
|
|
||||||
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
|
||||||
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
|
||||||
defer container.deinit();
|
|
||||||
|
|
||||||
try testing.expectContainerScreen(.{
|
|
||||||
.rows = 20,
|
|
||||||
.cols = 30,
|
|
||||||
}, &container, @import("test/container/separator_no_gaps.zon"));
|
|
||||||
}
|
|
||||||
|
|
||||||
test "separator(2x) without gaps" {
|
|
||||||
const event = @import("event.zig");
|
|
||||||
const testing = @import("testing.zig");
|
|
||||||
|
|
||||||
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
|
||||||
.border = .{
|
|
||||||
.separator = .{
|
|
||||||
.enabled = true,
|
|
||||||
.color = .red,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.layout = .{
|
|
||||||
.direction = .vertical,
|
|
||||||
},
|
|
||||||
}, .{});
|
|
||||||
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
|
||||||
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
|
||||||
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
|
||||||
defer container.deinit();
|
|
||||||
|
|
||||||
try testing.expectContainerScreen(.{
|
|
||||||
.rows = 20,
|
|
||||||
.cols = 30,
|
|
||||||
}, &container, @import("test/container/separator_2x_no_gaps.zon"));
|
|
||||||
}
|
|
||||||
|
|
||||||
test "separator(2x) with border(all)" {
|
|
||||||
const event = @import("event.zig");
|
|
||||||
const testing = @import("testing.zig");
|
|
||||||
|
|
||||||
// FIXME: without a gap this does not work as expected!
|
|
||||||
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
|
||||||
.border = .{
|
|
||||||
.color = .red,
|
|
||||||
.sides = .all,
|
|
||||||
.separator = .{
|
|
||||||
.enabled = true,
|
|
||||||
.color = .red,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, .{});
|
|
||||||
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
|
||||||
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
|
||||||
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
|
||||||
defer container.deinit();
|
|
||||||
|
|
||||||
try testing.expectContainerScreen(.{
|
|
||||||
.rows = 20,
|
|
||||||
.cols = 30,
|
|
||||||
}, &container, @import("test/container/separator_no_gaps.zon"));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Rectangle configuration struct
|
/// Rectangle configuration struct
|
||||||
@@ -325,6 +158,11 @@ pub const Rectangle = packed struct {
|
|||||||
|
|
||||||
/// Layout configuration struct
|
/// Layout configuration struct
|
||||||
pub const Layout = packed struct {
|
pub const Layout = packed struct {
|
||||||
|
// separator.line:
|
||||||
|
const line: [2]u21 = .{ '│', '─' };
|
||||||
|
const dotted: [2]u21 = .{ '┆', '┄' };
|
||||||
|
const double: [2]u21 = .{ '║', '═' };
|
||||||
|
|
||||||
/// control the direction in which child elements are laid out
|
/// control the direction in which child elements are laid out
|
||||||
direction: enum(u1) { horizontal, vertical } = .horizontal,
|
direction: enum(u1) { horizontal, vertical } = .horizontal,
|
||||||
/// Padding outside of the child elements
|
/// Padding outside of the child elements
|
||||||
@@ -351,6 +189,227 @@ pub const Layout = packed struct {
|
|||||||
} = .{},
|
} = .{},
|
||||||
/// Padding used in between child elements as gaps when laid out
|
/// Padding used in between child elements as gaps when laid out
|
||||||
gap: u16 = 0,
|
gap: u16 = 0,
|
||||||
|
/// Configure separator borders between child element to added to the layout
|
||||||
|
separator: packed struct {
|
||||||
|
enabled: bool = false,
|
||||||
|
color: Color = .white,
|
||||||
|
line: enum(u2) {
|
||||||
|
line,
|
||||||
|
dotted,
|
||||||
|
double,
|
||||||
|
} = .line,
|
||||||
|
} = .{},
|
||||||
|
|
||||||
|
pub fn contents(this: @This(), comptime C: type, cells: []Cell, size: Size, children: []const C) void {
|
||||||
|
std.debug.assert(cells.len == @as(usize, size.cols) * @as(usize, size.rows));
|
||||||
|
|
||||||
|
if (this.separator.enabled and children.len > 1) {
|
||||||
|
const line_cps: [2]u21 = switch (this.separator.line) {
|
||||||
|
.line => line,
|
||||||
|
.dotted => dotted,
|
||||||
|
.double => double,
|
||||||
|
};
|
||||||
|
const gap: u16 = (this.gap + 1) / 2;
|
||||||
|
|
||||||
|
for (0..children.len - 1) |idx| {
|
||||||
|
const child = children[idx];
|
||||||
|
const anchor = switch (this.direction) {
|
||||||
|
.horizontal => (child.size.anchor.row * size.cols) + child.size.anchor.col + child.size.cols + gap,
|
||||||
|
.vertical => ((child.size.anchor.row + child.size.rows + gap) * size.cols) + child.size.anchor.col,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (this.direction) {
|
||||||
|
.horizontal => for (0..child.size.rows) |row| {
|
||||||
|
cells[anchor + row * size.cols].cp = line_cps[0];
|
||||||
|
cells[anchor + row * size.cols].style.fg = this.separator.color;
|
||||||
|
},
|
||||||
|
.vertical => for (0..child.size.cols) |col| {
|
||||||
|
cells[anchor + col].cp = line_cps[1];
|
||||||
|
cells[anchor + col].style.fg = this.separator.color;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "separator without gaps" {
|
||||||
|
const event = @import("event.zig");
|
||||||
|
const testing = @import("testing.zig");
|
||||||
|
|
||||||
|
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
||||||
|
.layout = .{
|
||||||
|
.separator = .{
|
||||||
|
.enabled = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, .{});
|
||||||
|
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
||||||
|
defer container.deinit();
|
||||||
|
|
||||||
|
try testing.expectContainerScreen(.{
|
||||||
|
.rows = 20,
|
||||||
|
.cols = 30,
|
||||||
|
}, &container, @import("test/container/separator_no_gaps.zon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "separator without gaps with padding" {
|
||||||
|
const event = @import("event.zig");
|
||||||
|
const testing = @import("testing.zig");
|
||||||
|
|
||||||
|
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
||||||
|
.layout = .{
|
||||||
|
.padding = .all(1),
|
||||||
|
.separator = .{
|
||||||
|
.enabled = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, .{});
|
||||||
|
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
||||||
|
defer container.deinit();
|
||||||
|
|
||||||
|
try testing.expectContainerScreen(.{
|
||||||
|
.rows = 20,
|
||||||
|
.cols = 30,
|
||||||
|
}, &container, @import("test/container/separator_no_gaps_with_padding.zon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "separator(2x) without gaps" {
|
||||||
|
const event = @import("event.zig");
|
||||||
|
const testing = @import("testing.zig");
|
||||||
|
|
||||||
|
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
||||||
|
.layout = .{
|
||||||
|
.direction = .vertical,
|
||||||
|
.separator = .{
|
||||||
|
.enabled = true,
|
||||||
|
.color = .red,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, .{});
|
||||||
|
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{}, .{}));
|
||||||
|
defer container.deinit();
|
||||||
|
|
||||||
|
try testing.expectContainerScreen(.{
|
||||||
|
.rows = 20,
|
||||||
|
.cols = 30,
|
||||||
|
}, &container, @import("test/container/separator_2x_no_gaps.zon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "separator(2x) with border(all)" {
|
||||||
|
const event = @import("event.zig");
|
||||||
|
const testing = @import("testing.zig");
|
||||||
|
|
||||||
|
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
||||||
|
.border = .{
|
||||||
|
.color = .red,
|
||||||
|
.sides = .all,
|
||||||
|
},
|
||||||
|
.layout = .{
|
||||||
|
.separator = .{
|
||||||
|
.enabled = true,
|
||||||
|
.color = .red,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, .{});
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
defer container.deinit();
|
||||||
|
|
||||||
|
try testing.expectContainerScreen(.{
|
||||||
|
.rows = 20,
|
||||||
|
.cols = 30,
|
||||||
|
}, &container, @import("test/container/separator_2x_no_gaps_with_border.zon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "separator(2x) with border(all) and padding(all(1))" {
|
||||||
|
const event = @import("event.zig");
|
||||||
|
const testing = @import("testing.zig");
|
||||||
|
|
||||||
|
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
||||||
|
.border = .{
|
||||||
|
.color = .red,
|
||||||
|
.sides = .all,
|
||||||
|
},
|
||||||
|
.layout = .{
|
||||||
|
.padding = .all(1),
|
||||||
|
.separator = .{
|
||||||
|
.enabled = true,
|
||||||
|
.color = .red,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, .{});
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
defer container.deinit();
|
||||||
|
|
||||||
|
try testing.expectContainerScreen(.{
|
||||||
|
.rows = 20,
|
||||||
|
.cols = 30,
|
||||||
|
}, &container, @import("test/container/separator_2x_no_gaps_with_padding.zon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "separator(2x) with border(all) and gap" {
|
||||||
|
const event = @import("event.zig");
|
||||||
|
const testing = @import("testing.zig");
|
||||||
|
|
||||||
|
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
||||||
|
.border = .{
|
||||||
|
.color = .red,
|
||||||
|
.sides = .all,
|
||||||
|
},
|
||||||
|
.layout = .{
|
||||||
|
.gap = 2,
|
||||||
|
.separator = .{
|
||||||
|
.enabled = true,
|
||||||
|
.color = .red,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, .{});
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
defer container.deinit();
|
||||||
|
|
||||||
|
try testing.expectContainerScreen(.{
|
||||||
|
.rows = 20,
|
||||||
|
.cols = 30,
|
||||||
|
}, &container, @import("test/container/separator_2x_with_gaps_with_border.zon"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "separator(2x) with border(all) and gap and padding" {
|
||||||
|
const event = @import("event.zig");
|
||||||
|
const testing = @import("testing.zig");
|
||||||
|
|
||||||
|
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
||||||
|
.border = .{
|
||||||
|
.color = .red,
|
||||||
|
.sides = .all,
|
||||||
|
},
|
||||||
|
.layout = .{
|
||||||
|
.gap = 2,
|
||||||
|
.padding = .all(1),
|
||||||
|
.separator = .{
|
||||||
|
.enabled = true,
|
||||||
|
.color = .red,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, .{});
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
try container.append(try .init(std.testing.allocator, .{ .rectangle = .{ .fill = .white } }, .{}));
|
||||||
|
defer container.deinit();
|
||||||
|
|
||||||
|
try testing.expectContainerScreen(.{
|
||||||
|
.rows = 20,
|
||||||
|
.cols = 30,
|
||||||
|
}, &container, @import("test/container/separator_2x_with_gaps_with_border_with_padding.zon"));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn Container(comptime Event: type) type {
|
pub fn Container(comptime Event: type) type {
|
||||||
@@ -407,7 +466,7 @@ pub fn Container(comptime Event: type) type {
|
|||||||
size = size.merge(element.minSize());
|
size = size.merge(element.minSize());
|
||||||
}
|
}
|
||||||
var gap = this.properties.layout.gap;
|
var gap = this.properties.layout.gap;
|
||||||
if (this.properties.border.separator.enabled) gap += 1;
|
if (this.properties.layout.separator.enabled) gap += 1;
|
||||||
|
|
||||||
switch (this.properties.layout.direction) {
|
switch (this.properties.layout.direction) {
|
||||||
.horizontal => size.cols += gap * (len - 1),
|
.horizontal => size.cols += gap * (len - 1),
|
||||||
@@ -438,7 +497,7 @@ pub fn Container(comptime Event: type) type {
|
|||||||
const sides = this.properties.border.sides;
|
const sides = this.properties.border.sides;
|
||||||
const padding = layout.padding;
|
const padding = layout.padding;
|
||||||
var gap = layout.gap;
|
var gap = layout.gap;
|
||||||
if (this.properties.border.separator.enabled) gap += 1;
|
if (layout.separator.enabled) gap += 1;
|
||||||
|
|
||||||
const len: u16 = @truncate(this.elements.items.len);
|
const len: u16 = @truncate(this.elements.items.len);
|
||||||
const element_cols = blk: {
|
const element_cols = blk: {
|
||||||
@@ -552,9 +611,9 @@ pub fn Container(comptime Event: type) type {
|
|||||||
@memset(cells, .{});
|
@memset(cells, .{});
|
||||||
errdefer this.allocator.free(cells);
|
errdefer this.allocator.free(cells);
|
||||||
|
|
||||||
this.properties.border.contents(cells, this.size, this.properties.layout, @truncate(this.elements.items.len));
|
this.properties.layout.contents(@This(), cells, this.size, this.elements.items);
|
||||||
|
this.properties.border.contents(cells, this.size);
|
||||||
this.properties.rectangle.contents(cells, this.size);
|
this.properties.rectangle.contents(cells, this.size);
|
||||||
// NOTE: Layout has no contents to provide, hence no content method is called (or even exists in the `Layout` struct)
|
|
||||||
|
|
||||||
try this.element.content(cells, this.size);
|
try this.element.content(cells, this.size);
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,17 @@ pub fn Element(Event: type) type {
|
|||||||
/// `cells` slice has the size of (`size.cols * size.rows`). The
|
/// `cells` slice has the size of (`size.cols * size.rows`). The
|
||||||
/// renderer will know where to place the contents on the screen.
|
/// renderer will know where to place the contents on the screen.
|
||||||
///
|
///
|
||||||
/// This function should only fail with an error if the error is
|
/// # Note
|
||||||
/// non-recoverable (i.e. an allocation error, system error, etc.).
|
///
|
||||||
/// Otherwise user specific errors should be caught using the `handle`
|
/// - Caller owns `cells` slice and ensures that the size usually by assertion:
|
||||||
/// function before the rendering of the `Container` happens.
|
/// ```zig
|
||||||
|
/// std.debug.assert(cells.len == @as(usize, size.cols) * @as(usize, size.rows));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// - This function should only fail with an error if the error is
|
||||||
|
/// non-recoverable (i.e. an allocation error, system error, etc.).
|
||||||
|
/// Otherwise user specific errors should be caught using the `handle`
|
||||||
|
/// function before the rendering of the `Container` happens.
|
||||||
pub inline fn content(this: @This(), cells: []Cell, size: Size) !void {
|
pub inline fn content(this: @This(), cells: []Cell, size: Size) !void {
|
||||||
if (this.vtable.content) |content_fn|
|
if (this.vtable.content) |content_fn|
|
||||||
try content_fn(this.ptr, cells, size);
|
try content_fn(this.ptr, cells, size);
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
1
src/test/container/separator_2x_no_gaps_with_border.zon
Normal file
1
src/test/container/separator_2x_no_gaps_with_border.zon
Normal file
File diff suppressed because one or more lines are too long
1
src/test/container/separator_2x_no_gaps_with_padding.zon
Normal file
1
src/test/container/separator_2x_no_gaps_with_padding.zon
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/test/container/separator_no_gaps_with_padding.zon
Normal file
1
src/test/container/separator_no_gaps_with_padding.zon
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user