Compare commits
2 Commits
9dc1a4b95a
...
eb89f7f98b
| Author | SHA1 | Date | |
|---|---|---|---|
| eb89f7f98b | |||
| cc847b7035 |
@@ -128,7 +128,7 @@ the primary use-case for myself to create this library in the first place.
|
||||
- [x] vertical
|
||||
- [x] horizontal
|
||||
- [x] grid
|
||||
- [ ] mixed (some sort of form)
|
||||
- [x] mixed (some sort of form)
|
||||
- [ ] Elements
|
||||
- [ ] Button
|
||||
- [ ] Text Input field
|
||||
|
||||
10
build.zig
10
build.zig
@@ -12,6 +12,7 @@ pub fn build(b: *std.Build) void {
|
||||
vertical,
|
||||
horizontal,
|
||||
grid,
|
||||
mixed,
|
||||
// styles:
|
||||
};
|
||||
|
||||
@@ -78,6 +79,14 @@ pub fn build(b: *std.Build) void {
|
||||
});
|
||||
grid.root_module.addImport("zterm", lib);
|
||||
|
||||
const mixed = b.addExecutable(.{
|
||||
.name = "mixed",
|
||||
.root_source_file = b.path("examples/layouts/mixed.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
mixed.root_module.addImport("zterm", lib);
|
||||
|
||||
// mapping of user selected example to compile step
|
||||
const exe = switch (example) {
|
||||
// elements:
|
||||
@@ -87,6 +96,7 @@ pub fn build(b: *std.Build) void {
|
||||
.vertical => vertical,
|
||||
.horizontal => horizontal,
|
||||
.grid => grid,
|
||||
.mixed => mixed,
|
||||
// styles:
|
||||
};
|
||||
b.installArtifact(exe);
|
||||
|
||||
113
examples/layouts/mixed.zig
Normal file
113
examples/layouts/mixed.zig
Normal file
@@ -0,0 +1,113 @@
|
||||
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,
|
||||
// no handle function required
|
||||
.vtable = &.{ .content = content },
|
||||
};
|
||||
}
|
||||
|
||||
fn content(ctx: *anyopaque, cells: []zterm.Cell, size: zterm.Size) !void {
|
||||
_ = ctx;
|
||||
std.debug.assert(cells.len == @as(usize, size.cols) * @as(usize, size.rows));
|
||||
|
||||
const row: u16 = 2;
|
||||
const col: u16 = size.cols / 2 -| (@as(u16, @truncate(text.len)) / 2);
|
||||
const anchor = (row * size.cols) + 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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 container = try App.Container.init(allocator, .{
|
||||
.layout = .{
|
||||
.gap = 2,
|
||||
.padding = .{ .top = 5, .bottom = 3, .left = 3, .right = 3 },
|
||||
.direction = .horizontal,
|
||||
},
|
||||
}, element);
|
||||
for (0..3) |i| {
|
||||
var column = try App.Container.init(allocator, .{
|
||||
.border = .{ .separator = .{ .enabled = true } },
|
||||
.layout = .{
|
||||
.direction = if (i > 0) .vertical else .horizontal,
|
||||
},
|
||||
}, .{});
|
||||
if (i != 1) {
|
||||
try column.append(try App.Container.init(allocator, .{
|
||||
.rectangle = .{ .fill = .green },
|
||||
}, .{}));
|
||||
try column.append(try App.Container.init(allocator, .{
|
||||
.rectangle = .{ .fill = .yellow },
|
||||
}, .{}));
|
||||
} else {
|
||||
try column.append(try App.Container.init(allocator, .{}, .{}));
|
||||
}
|
||||
try column.append(try App.Container.init(allocator, .{
|
||||
.rectangle = .{ .fill = .blue },
|
||||
}, .{}));
|
||||
try container.append(column);
|
||||
}
|
||||
defer container.deinit(); // also de-initializes the children
|
||||
|
||||
try app.start();
|
||||
defer app.stop() catch |err| log.err("Failed to stop application: {any}", .{err});
|
||||
|
||||
// event loop
|
||||
while (true) {
|
||||
const event = app.nextEvent();
|
||||
log.debug("received event: {s}", .{@tagName(event)});
|
||||
|
||||
switch (event) {
|
||||
.init => continue,
|
||||
.quit => break,
|
||||
.resize => |size| try renderer.resize(size),
|
||||
.key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(),
|
||||
// NOTE: errors could be displayed in another container in case one was received, etc. to provide the user with feedback
|
||||
.err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }),
|
||||
else => {},
|
||||
}
|
||||
|
||||
// NOTE: returned errors should be propagated back to the application
|
||||
container.handle(event) catch |err| app.postEvent(.{
|
||||
.err = .{
|
||||
.err = err,
|
||||
.msg = "Container Event handling failed",
|
||||
},
|
||||
});
|
||||
try renderer.render(@TypeOf(container), &container);
|
||||
try renderer.flush();
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,7 @@ pub fn value(this: Style, writer: anytype, cp: u21) !void {
|
||||
try std.fmt.format(writer, "m", .{});
|
||||
// content
|
||||
try std.fmt.format(writer, "{s}", .{buffer});
|
||||
try std.fmt.format(writer, "\x1b[0m", .{});
|
||||
}
|
||||
|
||||
// TODO: implement helper functions for terminal capabilities:
|
||||
|
||||
Reference in New Issue
Block a user