WIP: add Container type with corresponding Properties configuration
The configuration of the `Container` types is very much inspired by [clay](https://github.com/nicbarker/clay).
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
const std = @import("std");
|
||||
|
||||
const isTaggedUnion = @import("event.zig").isTaggedUnion;
|
||||
|
||||
const Cell = @import("cell.zig");
|
||||
const Color = @import("color.zig").Color;
|
||||
const Size = @import("size.zig");
|
||||
|
||||
const log = std.log.scoped(.container);
|
||||
|
||||
/// Border configuration struct
|
||||
pub const Border = struct {
|
||||
/// Color to use for the border
|
||||
color: Color = .default,
|
||||
/// Configure the corner type to be used for the border
|
||||
corners: enum(u1) {
|
||||
squared,
|
||||
rounded,
|
||||
} = .squared,
|
||||
/// Configure the sides where the borders shall be rendered
|
||||
sides: packed struct {
|
||||
top: bool = true,
|
||||
bottom: bool = true,
|
||||
left: bool = true,
|
||||
right: bool = true,
|
||||
} = .{},
|
||||
/// Configure separator borders between child element to added to the layout
|
||||
separator: struct {
|
||||
enabled: bool = false,
|
||||
color: Color = .default,
|
||||
line: enum {
|
||||
line,
|
||||
dotted,
|
||||
// TODO: add more variations which could be used for the separator
|
||||
} = .line,
|
||||
} = .{},
|
||||
};
|
||||
|
||||
/// Rectangle configuration struct
|
||||
pub const Rectangle = struct {
|
||||
/// `Color` to use to fill the `Rectangle` with
|
||||
/// NOTE: used as background color when rendering! such that it renders the
|
||||
/// children accordingly without removing the coloring of the `Rectangle`
|
||||
fill: Color = .default,
|
||||
/// Configure the corners of the `Rectangle`
|
||||
corners: enum(u1) {
|
||||
squared,
|
||||
rounded,
|
||||
} = .squared,
|
||||
};
|
||||
|
||||
/// Scroll configuration struct
|
||||
pub const Scroll = packed struct {
|
||||
/// Enable horizontal scrolling for this element
|
||||
horizontal: bool = false,
|
||||
/// Enable vertical scrolling for this element
|
||||
vertical: bool = false,
|
||||
};
|
||||
|
||||
/// Layout configuration struct
|
||||
pub const Layout = struct {
|
||||
/// control the direction in which child elements are laid out
|
||||
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,
|
||||
|
||||
/// Create a padding with equivalent padding in all four directions.
|
||||
pub fn all(padding: u16) @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() {
|
||||
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() {
|
||||
return .{ .top = padding, .bottom = padding };
|
||||
}
|
||||
} = .{},
|
||||
/// Padding used in between child elements as gaps when laid out
|
||||
gap: u16 = 0,
|
||||
// TODO: is there a way to make x / y type copied by the compiler at comptime instead? such that this only has to be defined once?
|
||||
/// Alignment of where the child elements are positioned relative to the parent container when laid out
|
||||
alignment: packed struct {
|
||||
x: enum(u2) { center, left, right } = .center,
|
||||
y: enum(u2) { center, left, right } = .center,
|
||||
} = .{},
|
||||
// TODO: is there a way to make width / height type copied by the compiler at comptime instead? such that this only has to be defined once?
|
||||
// NOTE: `sizing` cannot be *packed* because of the tagged unions? is this necessary -> I would need to measure the size differences
|
||||
/// Sizing to be used for the width and height of this element to use
|
||||
sizing: struct {
|
||||
width: union(enum) { fit, grow, fixed: u16, percent: u16 } = .fit,
|
||||
height: union(enum) { fit, grow, fixed: u16, percent: u16 } = .fit,
|
||||
} = .{},
|
||||
};
|
||||
|
||||
pub fn Container(comptime Event: type) type {
|
||||
if (!isTaggedUnion(Event)) {
|
||||
@compileError("Provided user event `Event` for `Container(comptime Event: type)`");
|
||||
}
|
||||
return struct {
|
||||
size: Size,
|
||||
properties: Properties,
|
||||
elements: std.ArrayList(@This()),
|
||||
|
||||
/// Properties for each `Container` to configure their layout,
|
||||
/// border, styling, etc. For details see the corresponding individual
|
||||
/// documentation of the members of this struct accordingly.
|
||||
pub const Properties = struct {
|
||||
border: Border = .{},
|
||||
rectangle: Rectangle = .{},
|
||||
scroll: Scroll = .{},
|
||||
layout: Layout = .{},
|
||||
};
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, properties: Properties) !@This() {
|
||||
return .{
|
||||
.size = .{ .cols = 0, .rows = 0 },
|
||||
.properties = properties,
|
||||
.elements = std.ArrayList(@This()).init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(this: *@This()) void {
|
||||
for (this.elements.items) |*element| {
|
||||
element.deinit();
|
||||
}
|
||||
this.elements.deinit();
|
||||
}
|
||||
|
||||
pub fn append(this: *@This(), element: @This()) !void {
|
||||
try this.elements.append(element);
|
||||
}
|
||||
|
||||
pub fn handle(this: *@This(), event: Event) ?Event {
|
||||
switch (event) {
|
||||
.init => log.debug(".init event", .{}),
|
||||
.resize => |size| {
|
||||
this.size = size;
|
||||
for (this.elements.items) |*element| {
|
||||
const element_size: Size = size;
|
||||
// TODO; adjust size according to the layout of the `Container`
|
||||
if (element.handle(.{ .resize = element_size })) |e| {
|
||||
_ = e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
for (this.elements.items) |*element| {
|
||||
if (element.handle(event)) |e| {
|
||||
// TODO: if only the top level container returns a single
|
||||
// event (i.e. as a reaction to a certain other event) what
|
||||
// should happen to potential other events?
|
||||
_ = e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn contents(this: *const @This()) []const Cell {
|
||||
// TODO: use the size and the corresponding contents to determine what should be show in form of a `Cell` array
|
||||
_ = this;
|
||||
return &[0]Cell{};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user