Files
zterm/examples/styles/text.zig
Yves Biener ec22e68e8c
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 40s
ref(event): remove .resize and replace with recursize method calls
This also means that currently the dynamic resizing through the app's
detached thread is not working, as it cannot send size updates. The
examples have been overhauled to still implement intermediate mode
applications accordingly.
2025-03-04 14:52:19 +01:00

157 lines
5.3 KiB
Zig

const std = @import("std");
const zterm = @import("zterm");
const App = zterm.App(union(enum) {});
const log = std.log.scoped(.default);
const QuitText = struct {
const text = "Press ctrl+c to quit.";
pub fn element(this: *@This()) App.Element {
return .{ .ptr = this, .vtable = &.{ .content = content } };
}
fn content(ctx: *anyopaque, cells: []zterm.Cell, origin: zterm.Point, size: zterm.Point) !void {
_ = ctx;
std.debug.assert(cells.len == @as(usize, size.x) * @as(usize, size.y));
_ = origin;
const row = 2;
const col = size.x / 2 -| (text.len / 2);
const anchor = (row * size.x) + col;
for (text, 0..) |cp, idx| {
cells[anchor + idx].style.fg = .white;
cells[anchor + idx].style.bg = .black;
cells[anchor + idx].cp = cp;
// NOTE do not write over the contents of this `Container`'s `Size`
if (anchor + idx == cells.len - 1) break;
}
}
};
const TextStyles = struct {
const text = "Example";
pub fn element(this: *@This()) App.Element {
return .{ .ptr = this, .vtable = &.{ .content = content } };
}
fn content(ctx: *anyopaque, cells: []zterm.Cell, origin: zterm.Point, size: zterm.Point) !void {
@setEvalBranchQuota(50000);
_ = ctx;
std.debug.assert(cells.len == @as(usize, size.x) * @as(usize, size.y));
_ = origin;
var row: usize = 0;
var col: usize = 0;
// Color
inline for (std.meta.fields(zterm.Color)) |bg_field| {
if (comptime bg_field.value == 0) continue; // zterm.Color.default == 0 -> skip
inline for (std.meta.fields(zterm.Color)) |fg_field| {
if (comptime fg_field.value == 0) continue; // zterm.Color.default == 0 -> skip
if (comptime fg_field.value == bg_field.value) continue;
// witouth any emphasis
for (text) |cp| {
cells[(row * size.x) + col].style.bg = @enumFromInt(bg_field.value);
cells[(row * size.x) + col].style.fg = @enumFromInt(fg_field.value);
cells[(row * size.x) + col].cp = cp;
col += 1;
}
// emphasis (no combinations)
inline for (std.meta.fields(zterm.Style.Emphasis)) |emp_field| {
if (comptime emp_field.value == 0) continue; // zterm.Style.Emphasis.reset == 0 -> skip
const emphasis: zterm.Style.Emphasis = @enumFromInt(emp_field.value);
for (text) |cp| {
cells[(row * size.x) + col].style.bg = @enumFromInt(bg_field.value);
cells[(row * size.x) + col].style.fg = @enumFromInt(fg_field.value);
cells[(row * size.x) + col].style.emphasis = &.{emphasis};
cells[(row * size.x) + col].cp = cp;
col += 1;
}
}
row += 1;
col = 0;
}
}
}
};
pub fn main() !void {
errdefer |err| log.err("Application Error: {any}", .{err});
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
defer if (gpa.deinit() == .leak) log.err("memory leak", .{});
const allocator = gpa.allocator();
var app: App = .init;
var renderer = zterm.Renderer.Buffered.init(allocator);
defer renderer.deinit();
var quit_text: QuitText = .{};
const element = quit_text.element();
var text_styles: TextStyles = .{};
var container = try App.Container.init(allocator, .{
.layout = .{
.gap = 2,
.padding = .{ .top = 5, .bottom = 3, .left = 3, .right = 3 },
},
}, element);
defer container.deinit();
var box = try App.Container.init(allocator, .{
.layout = .{ .direction = .vertical },
}, text_styles.element());
defer box.deinit();
var scrollable: App.Scrollable = .init(box, .{
.x = std.meta.fields(zterm.Style.Emphasis).len * TextStyles.text.len,
.y = (std.meta.fields(zterm.Color).len - 1) * (std.meta.fields(zterm.Color).len - 2),
}); // ensure enough rows and/or columns to render all text styles -> scrollable otherwise
try container.append(try App.Container.init(allocator, .{}, scrollable.element()));
try app.start();
defer app.stop() catch |err| log.err("Failed to stop application: {any}", .{err});
while (true) {
const event = app.nextEvent();
log.debug("received event: {s}", .{@tagName(event)});
// pre event handling
switch (event) {
.key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(),
.err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }),
else => {},
}
container.handle(event) catch |err| app.postEvent(.{
.err = .{
.err = err,
.msg = "Container Event handling failed",
},
});
// post event handling
switch (event) {
.quit => break,
else => {},
}
try renderer.resize();
container.reposition(.{});
container.resize(renderer.size);
try renderer.render(@TypeOf(container), &container);
try renderer.flush();
}
}