Files
zterm/src/layout/Padding.zig
Yves Biener 0cc0ed10d2
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 35s
cleanup of obsolete comments and dead code
This removes the App.Renderer.Buffered, which was not improving on the
direct renderer, which has a simpler implementation and was keept for
this regard.
2024-11-13 19:14:13 +01:00

149 lines
5.8 KiB
Zig

//! Padding layout for a nested `Layout`s or `Widget`s.
//!
//! # Example
//! ...
const std = @import("std");
const terminal = @import("../terminal.zig");
const isTaggedUnion = @import("../event.zig").isTaggedUnion;
const Error = @import("../event.zig").Error;
const Key = terminal.Key;
const log = std.log.scoped(.layout_padding);
pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: type) type {
if (!isTaggedUnion(Event)) {
@compileError("Provided user event `Event` for `Layout(comptime Event: type, comptime Element: type, comptime Renderer: type)` is not of type `union(enum)`.");
}
if (!isTaggedUnion(Element)) {
@compileError("Provided type `Element` for `Layout(comptime Event: type, comptime Element: type, comptime Renderer: type)` is not of type `union(enum)`.");
}
if (!std.mem.eql(u8, @typeInfo(Element).Union.fields[0].name, "layout")) {
@compileError("Expected `layout: Layout` to be the first union element, but has name: " ++ @typeInfo(Element).Union.fields[0].name);
}
if (!std.mem.eql(u8, @typeInfo(Element).Union.fields[1].name, "widget")) {
@compileError("Expected `widget: Widget` to be the first union element, but has name: " ++ @typeInfo(Element).Union.fields[1].name);
}
const Events = std.ArrayList(Event);
return struct {
size: terminal.Size = undefined,
require_render: bool = false,
element: Element = undefined,
events: Events = undefined,
config: Config = undefined,
const Config = struct {
padding: ?u16 = undefined,
left: u16 = 0,
right: u16 = 0,
top: u16 = 0,
bottom: u16 = 0,
};
pub fn init(allocator: std.mem.Allocator, config: Config, element: Element) @This() {
return .{
.config = config,
.element = element,
.events = Events.init(allocator),
};
}
pub fn deinit(this: *@This()) void {
this.events.deinit();
switch ((&this.element).*) {
.layout => |*layout| {
layout.deinit();
},
.widget => |*widget| {
widget.deinit();
},
}
}
pub fn handle(this: *@This(), event: Event) !*Events {
this.events.clearRetainingCapacity();
// order is important
switch (event) {
.resize => |size| {
this.size = size;
this.require_render = true;
log.debug("Event .resize: {{ .anchor = {{ .col = {d}, .row = {d} }}, .cols = {d}, .rows = {d} }}", .{
size.anchor.col,
size.anchor.row,
size.cols,
size.rows,
});
var sub_event: Event = undefined;
if (this.config.padding) |padding| {
// used overall padding
sub_event = .{
.resize = .{
.anchor = .{
.col = size.anchor.col + padding,
.row = size.anchor.row + padding,
},
.cols = size.cols -| (padding * 2),
.rows = size.rows -| (padding * 2),
},
};
} else {
// use all for directions individually
sub_event = .{
.resize = .{
.anchor = .{
.col = size.anchor.col + this.config.left,
.row = size.anchor.row + this.config.top,
},
.cols = size.cols -| this.config.left -| this.config.right,
.rows = size.rows -| this.config.top -| this.config.bottom,
},
};
}
// adjust size according to the containing elements
switch ((&this.element).*) {
.layout => |*layout| {
const events = try layout.handle(sub_event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
if (widget.handle(sub_event)) |e| {
try this.events.append(e);
}
},
}
},
else => {
switch ((&this.element).*) {
.layout => |*layout| {
const events = try layout.handle(event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
if (widget.handle(event)) |e| {
try this.events.append(e);
}
},
}
},
}
return &this.events;
}
pub fn render(this: *@This(), renderer: *Renderer) !void {
if (this.require_render) {
try renderer.clear(this.size);
this.require_render = false;
}
switch ((&this.element).*) {
.layout => |*layout| {
try layout.render(renderer);
},
.widget => |*widget| {
try widget.render(renderer);
},
}
}
};
}