mod(renderer): initial version of double buffer intermediate renderer
This branch will implement the necessary changes for the widgets and their implementations to use the new renderer correctly.
This commit is contained in:
@@ -3,7 +3,7 @@ const zterm = @import("zterm");
|
||||
|
||||
const App = zterm.App(
|
||||
union(enum) {},
|
||||
zterm.Renderer.Direct,
|
||||
zterm.Renderer.Buffered,
|
||||
true,
|
||||
);
|
||||
const Key = zterm.Key;
|
||||
@@ -26,7 +26,8 @@ pub fn main() !void {
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var app: App = .{};
|
||||
var renderer: App.Renderer = .{};
|
||||
var renderer = App.Renderer.init(allocator);
|
||||
defer renderer.deinit();
|
||||
// TODO: when not running fullscreen, the application needs to screen down accordingly to display the contents
|
||||
// -> size hint how much should it use?
|
||||
|
||||
@@ -75,17 +76,19 @@ pub fn main() !void {
|
||||
},
|
||||
.{
|
||||
.layout = Layout.createFrom(Layout.VStack.init(allocator, .{
|
||||
Widget.createFrom(blk: {
|
||||
const file = try std.fs.cwd().openFile("./examples/stack.zig", .{});
|
||||
defer file.close();
|
||||
break :blk Widget.RawText.init(allocator, file);
|
||||
}),
|
||||
// Widget.createFrom(blk: {
|
||||
// const file = try std.fs.cwd().openFile("./examples/stack.zig", .{});
|
||||
// defer file.close();
|
||||
// break :blk Widget.RawText.init(allocator, file);
|
||||
// }),
|
||||
Widget.createFrom(Widget.Spacer.init(allocator)),
|
||||
Widget.createFrom(blk: {
|
||||
const file = try std.fs.cwd().openFile("./examples/stack.zig", .{});
|
||||
defer file.close();
|
||||
break :blk Widget.RawText.init(allocator, file);
|
||||
}),
|
||||
Widget.createFrom(Widget.Spacer.init(allocator)),
|
||||
Widget.createFrom(Widget.Spacer.init(allocator)),
|
||||
// Widget.createFrom(blk: {
|
||||
// const file = try std.fs.cwd().openFile("./examples/stack.zig", .{});
|
||||
// defer file.close();
|
||||
// break :blk Widget.RawText.init(allocator, file);
|
||||
// }),
|
||||
})),
|
||||
},
|
||||
),
|
||||
|
||||
@@ -7,7 +7,7 @@ const App = zterm.App(
|
||||
tui, // view instance to the corresponding view for 'tui'
|
||||
},
|
||||
},
|
||||
zterm.Renderer.Direct,
|
||||
zterm.Renderer.Buffered,
|
||||
true,
|
||||
);
|
||||
const Cell = zterm.Cell;
|
||||
@@ -24,49 +24,26 @@ const Tui = struct {
|
||||
pub fn init(allocator: std.mem.Allocator) *Tui {
|
||||
var tui = allocator.create(Tui) catch @panic("Out of memory: tui.zig");
|
||||
tui.allocator = allocator;
|
||||
// FIXME: the layout creates an 'incorrect alignment'?
|
||||
tui.layout = Layout.createFrom(Layout.VContainer.init(allocator, .{
|
||||
.{
|
||||
Layout.createFrom(Layout.Framing.init(allocator, .{
|
||||
.title = .{
|
||||
.str = "Welcome to my terminal website",
|
||||
.style = .{
|
||||
.ul = .{ .index = 6 },
|
||||
.ul_style = .single,
|
||||
},
|
||||
},
|
||||
}, .{
|
||||
.layout = Layout.createFrom(Layout.HContainer.init(allocator, .{
|
||||
.{
|
||||
Widget.createFrom(Widget.Text.init(allocator, .left, &[1]Cell{
|
||||
.{ .content = "Yves Biener", .style = .{ .bold = true } },
|
||||
})),
|
||||
25,
|
||||
},
|
||||
.{
|
||||
Widget.createFrom(Widget.Text.init(allocator, .left, &[1]Cell{
|
||||
.{ .content = "File name", .style = .{ .bold = true } },
|
||||
})),
|
||||
50,
|
||||
},
|
||||
.{
|
||||
Widget.createFrom(Widget.Text.init(allocator, .left, &[1]Cell{
|
||||
.{ .content = "Contacts", .style = .{ .bold = true } },
|
||||
})),
|
||||
25,
|
||||
},
|
||||
})),
|
||||
tui.layout = Layout.createFrom(Layout.VStack.init(allocator, .{
|
||||
Layout.createFrom(Layout.HStack.init(allocator, .{
|
||||
Widget.createFrom(Widget.Text.init(allocator, .left, &[1]Cell{
|
||||
.{ .rune = 'Y', .style = .{ .fg = .{ .index = 6 }, .bold = true } },
|
||||
})),
|
||||
10,
|
||||
},
|
||||
.{
|
||||
Layout.createFrom(Layout.Margin.init(allocator, .{ .left = 15, .right = 15 }, .{
|
||||
.widget = Widget.createFrom(Widget.Text.init(allocator, .default, &[1]Cell{
|
||||
.{ .content = "Does this change anything", .style = .{ .ul = .default, .ul_style = .single } },
|
||||
})),
|
||||
Widget.createFrom(Widget.Text.init(allocator, .left, &[1]Cell{
|
||||
.{ .rune = 'F', .style = .{ .fg = .{ .index = 6 }, .bold = true } },
|
||||
})),
|
||||
90,
|
||||
},
|
||||
Widget.createFrom(Widget.Text.init(allocator, .left, &[1]Cell{
|
||||
.{ .rune = 'C', .style = .{ .fg = .{ .index = 6 }, .bold = true } },
|
||||
})),
|
||||
})),
|
||||
// .{
|
||||
// Layout.createFrom(Layout.Margin.init(allocator, .{ .left = 15, .right = 15 }, .{
|
||||
// .widget = Widget.createFrom(Widget.Text.init(allocator, .default, &[1]Cell{
|
||||
// .{ .rune = 'D', .style = .{ .ul = .default, .ul_style = .single } },
|
||||
// })),
|
||||
// })),
|
||||
// 90,
|
||||
// },
|
||||
}));
|
||||
return tui;
|
||||
}
|
||||
@@ -76,6 +53,14 @@ const Tui = struct {
|
||||
this.allocator.destroy(this);
|
||||
}
|
||||
|
||||
pub fn enable(this: *Tui) void {
|
||||
_ = this;
|
||||
}
|
||||
|
||||
pub fn disable(this: *Tui) void {
|
||||
_ = this;
|
||||
}
|
||||
|
||||
pub fn handle(this: *Tui, event: App.Event) !*Events {
|
||||
return try this.layout.handle(event);
|
||||
}
|
||||
@@ -99,7 +84,9 @@ pub fn main() !void {
|
||||
const allocator = arena.allocator();
|
||||
|
||||
var app: App = .{};
|
||||
var renderer: App.Renderer = .{};
|
||||
var renderer = App.Renderer.init(allocator);
|
||||
defer renderer.deinit();
|
||||
|
||||
var view: View = undefined;
|
||||
|
||||
var tui_view = View.createFrom(Tui.init(allocator));
|
||||
@@ -147,5 +134,6 @@ pub fn main() !void {
|
||||
app.postEvent(e);
|
||||
}
|
||||
try view.render(&renderer);
|
||||
try renderer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,8 +126,8 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
|
||||
return &this.events;
|
||||
}
|
||||
|
||||
const round_frame = .{ "╭", "─", "╮", "│", "╰", "╯" };
|
||||
const square_frame = .{ "┌", "─", "┐", "│", "└", "┘" };
|
||||
const round_frame: [6][]const u8 = .{ "╭", "─", "╮", "│", "╰", "╯" };
|
||||
const square_frame: [6][]const u8 = .{ "┌", "─", "┐", "│", "└", "┘" };
|
||||
|
||||
fn renderFrame(this: *@This(), renderer: *Renderer) !void {
|
||||
// FIXME: use renderer instead!
|
||||
@@ -140,14 +140,14 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
|
||||
// render top: +---+
|
||||
try terminal.setCursorPosition(this.size.anchor);
|
||||
const writer = terminal.writer();
|
||||
try this.config.style.value(writer, frame[0]);
|
||||
if (this.config.title.str.len > 0) {
|
||||
try this.config.title.style.value(writer, this.config.title.str);
|
||||
// try this.config.style.value(writer, frame[0]);
|
||||
for (0..this.config.title.str.len) |i| {
|
||||
try this.config.title.style.value(writer, this.config.title.str[i]);
|
||||
}
|
||||
for (0..this.size.cols -| 2 -| this.config.title.str.len) |_| {
|
||||
try this.config.style.value(writer, frame[1]);
|
||||
// try this.config.style.value(writer, frame[1]);
|
||||
}
|
||||
try this.config.style.value(writer, frame[2]);
|
||||
// try this.config.style.value(writer, frame[2]);
|
||||
// render left: |
|
||||
for (1..this.size.rows -| 1) |r| {
|
||||
const row: u16 = @truncate(r);
|
||||
@@ -155,7 +155,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
|
||||
.col = this.size.anchor.col,
|
||||
.row = this.size.anchor.row + row,
|
||||
});
|
||||
try this.config.style.value(writer, frame[3]);
|
||||
// try this.config.style.value(writer, frame[3]);
|
||||
}
|
||||
// render right: |
|
||||
for (1..this.size.rows -| 1) |r| {
|
||||
@@ -164,18 +164,18 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
|
||||
.col = this.size.anchor.col + this.size.cols -| 1,
|
||||
.row = this.size.anchor.row + row,
|
||||
});
|
||||
try this.config.style.value(writer, frame[3]);
|
||||
// try this.config.style.value(writer, frame[3]);
|
||||
}
|
||||
// render bottom: +---+
|
||||
try terminal.setCursorPosition(.{
|
||||
.col = this.size.anchor.col,
|
||||
.row = this.size.anchor.row + this.size.rows - 1,
|
||||
});
|
||||
try this.config.style.value(writer, frame[4]);
|
||||
// try this.config.style.value(writer, frame[4]);
|
||||
for (0..this.size.cols -| 2) |_| {
|
||||
try this.config.style.value(writer, frame[1]);
|
||||
// try this.config.style.value(writer, frame[1]);
|
||||
}
|
||||
try this.config.style.value(writer, frame[5]);
|
||||
// try this.config.style.value(writer, frame[5]);
|
||||
}
|
||||
|
||||
pub fn render(this: *@This(), renderer: *Renderer) !void {
|
||||
|
||||
168
src/render.zig
168
src/render.zig
@@ -10,97 +10,107 @@
|
||||
const std = @import("std");
|
||||
const terminal = @import("terminal.zig");
|
||||
|
||||
const Cells = []const terminal.Cell;
|
||||
const Cell = terminal.Cell;
|
||||
const Position = terminal.Position;
|
||||
const Size = terminal.Size;
|
||||
|
||||
pub fn Direct(comptime fullscreen: bool) type {
|
||||
const log = std.log.scoped(.renderer_direct);
|
||||
_ = log;
|
||||
/// Double-buffered intermediate rendering pipeline
|
||||
pub fn Buffered(comptime fullscreen: bool) type {
|
||||
const log = std.log.scoped(.renderer_buffered);
|
||||
// _ = log;
|
||||
_ = fullscreen;
|
||||
return struct {
|
||||
size: Size = undefined,
|
||||
allocator: std.mem.Allocator,
|
||||
created: bool,
|
||||
size: Size,
|
||||
screen: []Cell,
|
||||
virtual_screen: []Cell,
|
||||
|
||||
pub fn resize(this: *@This(), size: Size) void {
|
||||
this.size = size;
|
||||
pub fn init(allocator: std.mem.Allocator) @This() {
|
||||
return .{
|
||||
.allocator = allocator,
|
||||
.created = false,
|
||||
.size = undefined,
|
||||
.screen = undefined,
|
||||
.virtual_screen = undefined,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn clear(this: *@This(), size: Size) !void {
|
||||
_ = this;
|
||||
// NOTE: clear on the entire screen may introduce too much overhead and could instead clear the entire screen instead.
|
||||
// - it could also then try to optimize for further *clear* calls, that result in pretty much a nop? -> how to identify those clear calls?
|
||||
// TODO: this should instead by dynamic and correct of size (terminal could be too large currently)
|
||||
std.debug.assert(1028 > size.cols);
|
||||
var buf: [1028]u8 = undefined;
|
||||
@memset(buf[0..], ' ');
|
||||
for (0..size.rows) |r| {
|
||||
const row: u16 = @truncate(r);
|
||||
try terminal.setCursorPosition(.{
|
||||
.col = size.anchor.col,
|
||||
.row = size.anchor.row + row,
|
||||
});
|
||||
_ = try terminal.write(buf[0..size.cols]);
|
||||
pub fn deinit(this: *@This()) void {
|
||||
if (this.created) {
|
||||
this.allocator.free(this.screen);
|
||||
this.allocator.free(this.virtual_screen);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(this: *@This(), size: Size, cells: Cells) !void {
|
||||
_ = this;
|
||||
try terminal.setCursorPosition(size.anchor);
|
||||
var row: u16 = 0;
|
||||
var remaining_cols = size.cols;
|
||||
pub fn resize(this: *@This(), size: Size) void {
|
||||
this.size = size;
|
||||
if (!this.created) {
|
||||
this.screen = this.allocator.alloc(Cell, size.cols * size.rows) catch @panic("render.zig: Out of memory.");
|
||||
this.virtual_screen = this.allocator.alloc(Cell, size.cols * size.rows) catch @panic("render.zig: Out of memory.");
|
||||
this.created = true;
|
||||
return;
|
||||
}
|
||||
if (this.allocator.resize(this.screen, size.cols * size.rows)) {
|
||||
@panic("render.zig: Could not resize `screen` buffer");
|
||||
}
|
||||
if (this.allocator.resize(this.virtual_screen, size.cols * size.rows)) {
|
||||
@panic("render.zig: Could not resize `virtual screen` buffer.");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(this: *@This(), size: Size) !void {
|
||||
log.debug("renderer::clear", .{});
|
||||
var vs = this.virtual_screen;
|
||||
const anchor = (size.anchor.row * this.size.rows) + size.anchor.col;
|
||||
for (0..size.rows) |row| {
|
||||
for (0..size.cols) |col| {
|
||||
vs[anchor + (row * this.size.cols) + col].reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Render provided cells at size (anchor and dimension) into the *virtual screen*.
|
||||
pub fn render(this: *@This(), size: Size, cells: []const Cell) !void {
|
||||
log.debug("renderer:render: cells: {any}", .{cells});
|
||||
std.debug.assert(cells.len > 0);
|
||||
|
||||
var idx: usize = 0;
|
||||
var vs = this.virtual_screen;
|
||||
const anchor = (size.anchor.row * this.size.rows) + size.anchor.col;
|
||||
|
||||
for (0..size.rows) |row| {
|
||||
for (0..size.cols) |col| {
|
||||
const cell = cells[idx];
|
||||
idx += 1;
|
||||
|
||||
vs[anchor + (row * this.size.cols) + col].style = cell.style;
|
||||
vs[anchor + (row * this.size.cols) + col].rune = cell.rune;
|
||||
|
||||
if (cells.len == idx) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Write *virtual screen* to alternate screen (should be called once and last during each render loop iteration in the main loop).
|
||||
pub fn flush(this: *@This()) !void {
|
||||
log.debug("renderer::flush", .{});
|
||||
const writer = terminal.writer();
|
||||
for (cells) |cell| {
|
||||
var idx: usize = 0;
|
||||
print_cell: while (true) {
|
||||
const cell_len = cell.len(idx);
|
||||
if (cell_len > remaining_cols) {
|
||||
const result = try cell.writeUpToNewline(writer, idx, idx + remaining_cols);
|
||||
row += 1;
|
||||
if (row >= size.rows) {
|
||||
return; // we are done
|
||||
}
|
||||
try terminal.setCursorPosition(.{
|
||||
.col = size.anchor.col,
|
||||
.row = size.anchor.row + row,
|
||||
});
|
||||
remaining_cols = size.cols;
|
||||
idx = result.idx;
|
||||
if (result.newline) {
|
||||
idx += 1; // skip over newline
|
||||
} else {
|
||||
// there is still content to the newline (which will not be printed)
|
||||
for (idx..cell.content.len) |i| {
|
||||
if (cell.content[i] == '\n') {
|
||||
idx = i + 1;
|
||||
continue :print_cell;
|
||||
}
|
||||
}
|
||||
break; // go to next cell (as we went to the end of the cell and do not print on the next line)
|
||||
}
|
||||
} else {
|
||||
// print rest of cell
|
||||
const result = try cell.writeUpToNewline(writer, idx, idx + cell_len);
|
||||
if (result.newline) {
|
||||
row += 1;
|
||||
if (row >= size.rows) {
|
||||
return; // we are done
|
||||
}
|
||||
try terminal.setCursorPosition(.{
|
||||
.col = size.anchor.col,
|
||||
.row = size.anchor.row + row,
|
||||
});
|
||||
remaining_cols = size.cols;
|
||||
idx = result.idx + 1; // skip over newline
|
||||
} else {
|
||||
remaining_cols -= @truncate(cell_len -| idx);
|
||||
idx = 0;
|
||||
break; // go to next cell
|
||||
}
|
||||
}
|
||||
// written all cell contents
|
||||
if (idx >= cell.content.len) {
|
||||
break; // go to next cell
|
||||
}
|
||||
const s = this.screen;
|
||||
const vs = this.virtual_screen;
|
||||
for (0..this.size.rows) |row| {
|
||||
for (0..this.size.cols) |col| {
|
||||
const idx = (row * this.size.cols) + col;
|
||||
const cs = s[idx];
|
||||
const cvs = vs[idx];
|
||||
if (cs.eql(cvs))
|
||||
continue;
|
||||
// render differences found in virtual screen
|
||||
// TODO: improve the writing speed (many unecessary writes (i.e. the style for every character..))
|
||||
try terminal.setCursorPosition(.{ .row = @truncate(row), .col = @truncate(col) });
|
||||
try cvs.value(writer);
|
||||
// update screen to be the virtual screen for the next frame
|
||||
s[idx] = vs[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ pub const ReportMode = enum {
|
||||
pub fn getTerminalSize() Size {
|
||||
var ws: std.posix.winsize = undefined;
|
||||
_ = std.posix.system.ioctl(std.posix.STDIN_FILENO, std.posix.T.IOCGWINSZ, @intFromPtr(&ws));
|
||||
return .{ .cols = ws.col, .rows = ws.row };
|
||||
return .{ .cols = ws.col - 1, .rows = ws.row - 1 };
|
||||
}
|
||||
|
||||
pub fn saveScreen() !void {
|
||||
@@ -126,8 +126,8 @@ pub fn getCursorPosition() !Position {
|
||||
}
|
||||
|
||||
return .{
|
||||
.row = try std.fmt.parseInt(u16, row[0..ridx], 10),
|
||||
.col = try std.fmt.parseInt(u16, col[0..cidx], 10),
|
||||
.row = try std.fmt.parseInt(u16, row[0..ridx], 10) - 1,
|
||||
.col = try std.fmt.parseInt(u16, col[0..cidx], 10) - 1,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -2,60 +2,24 @@ const std = @import("std");
|
||||
pub const Style = @import("Style.zig");
|
||||
|
||||
style: Style = .{},
|
||||
content: []const u8 = undefined,
|
||||
rune: u8 = ' ',
|
||||
|
||||
pub const Result = struct {
|
||||
idx: usize,
|
||||
newline: bool,
|
||||
pub const Character = struct {
|
||||
grapheme: []const u8,
|
||||
width: u8,
|
||||
};
|
||||
|
||||
pub fn len(this: @This(), start: usize) usize {
|
||||
std.debug.assert(this.content.len > start);
|
||||
return this.content[start..].len;
|
||||
pub fn eql(this: @This(), other: @This()) bool {
|
||||
return this.rune == other.rune and this.style.eql(other.style);
|
||||
}
|
||||
|
||||
pub fn write(this: @This(), writer: anytype, start: usize, end: usize) !void {
|
||||
std.debug.assert(this.content.len > start);
|
||||
std.debug.assert(this.content.len >= end);
|
||||
std.debug.assert(start < end);
|
||||
|
||||
try this.style.value(writer, this.content[start..end]);
|
||||
pub fn reset(this: *@This()) void {
|
||||
this.style = .{ .fg = .default, .bg = .default, .ul = .default, .ul_style = .off };
|
||||
this.rune = ' ';
|
||||
}
|
||||
|
||||
pub fn writeUpToNewline(this: @This(), writer: anytype, start: usize, end: usize) !Result {
|
||||
std.debug.assert(this.content.len > start);
|
||||
std.debug.assert(this.content.len >= end);
|
||||
std.debug.assert(start < end);
|
||||
|
||||
for (start..end) |i| {
|
||||
if (this.content[i] == '\n') {
|
||||
if (start < i) {
|
||||
// this is just an empty line with a newline
|
||||
try this.value(writer, start, i);
|
||||
}
|
||||
return .{
|
||||
.idx = i,
|
||||
.newline = true,
|
||||
};
|
||||
}
|
||||
}
|
||||
try this.write(writer, start, end);
|
||||
return .{
|
||||
.idx = end,
|
||||
.newline = false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn value(this: @This(), writer: anytype, start: usize, end: usize) !void {
|
||||
std.debug.assert(start < this.content.len);
|
||||
std.debug.assert(this.content.len >= end);
|
||||
std.debug.assert(start < end);
|
||||
try this.style.value(writer, this.content[start..end]);
|
||||
}
|
||||
|
||||
// not really supported
|
||||
pub fn format(this: @This(), writer: anytype, comptime fmt: []const u8, args: anytype) !void {
|
||||
try this.style.format(writer, fmt, args); // NOTE: args should contain this.content[start..end] or this.content
|
||||
pub fn value(this: @This(), writer: anytype) !void {
|
||||
try this.style.value(writer, this.rune);
|
||||
}
|
||||
|
||||
test {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const Position = @import("Position.zig");
|
||||
|
||||
anchor: Position = .{ .col = 1, .row = 1 }, // top left corner by default
|
||||
anchor: Position = .{ .col = 0, .row = 0 }, // top left corner by default
|
||||
cols: u16,
|
||||
rows: u16,
|
||||
|
||||
@@ -113,6 +113,20 @@ reverse: bool = false,
|
||||
invisible: bool = false,
|
||||
strikethrough: bool = false,
|
||||
|
||||
pub fn eql(this: @This(), other: @This()) bool {
|
||||
return this.fg.eql(other.fg) and
|
||||
this.bg.eql(other.bg) and
|
||||
this.ul.eql(other.ul) and
|
||||
other.ul_style == this.ul_style and
|
||||
other.bold == this.bold and
|
||||
other.dim == this.dim and
|
||||
other.italic == this.italic and
|
||||
other.blink == this.blink and
|
||||
other.reverse == this.reverse and
|
||||
other.invisible == this.invisible and
|
||||
other.strikethrough == this.strikethrough;
|
||||
}
|
||||
|
||||
/// Merge _other_ `Style` to _this_ style and overwrite _this_ `Style`'s value
|
||||
/// if the _other_ value differs from the default value.
|
||||
pub fn merge(this: *@This(), other: @This()) void {
|
||||
@@ -284,15 +298,9 @@ fn end(this: @This(), writer: anytype) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format(this: @This(), writer: anytype, comptime content: []const u8, args: anytype) !void {
|
||||
pub fn value(this: @This(), writer: anytype, content: u8) !void {
|
||||
try this.start(writer);
|
||||
try std.fmt.format(writer, content, args);
|
||||
try this.end(writer);
|
||||
}
|
||||
|
||||
pub fn value(this: @This(), writer: anytype, content: []const u8) !void {
|
||||
try this.start(writer);
|
||||
_ = try writer.write(content);
|
||||
_ = try writer.write(&[_]u8{content});
|
||||
try this.end(writer);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,10 +62,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
|
||||
switch (this.alignment) {
|
||||
.default => break :blk this.size,
|
||||
.center => {
|
||||
var length_usize: usize = 0;
|
||||
for (this.contents) |content| {
|
||||
length_usize += content.content.len;
|
||||
}
|
||||
const length_usize = this.contents.len;
|
||||
const length: u16 = @truncate(length_usize);
|
||||
const cols = @min(length, this.size.cols);
|
||||
const rows = cols / length;
|
||||
@@ -79,10 +76,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
|
||||
};
|
||||
},
|
||||
.top => {
|
||||
var length_usize: usize = 0;
|
||||
for (this.contents) |content| {
|
||||
length_usize += content.content.len;
|
||||
}
|
||||
const length_usize = this.contents.len;
|
||||
const length: u16 = @truncate(length_usize);
|
||||
const cols = @min(length, this.size.cols);
|
||||
const rows = cols / length;
|
||||
@@ -96,10 +90,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
|
||||
};
|
||||
},
|
||||
.bottom => {
|
||||
var length_usize: usize = 0;
|
||||
for (this.contents) |content| {
|
||||
length_usize += content.content.len;
|
||||
}
|
||||
const length_usize = this.contents.len;
|
||||
const length: u16 = @truncate(length_usize);
|
||||
const cols = @min(length, this.size.cols);
|
||||
const rows = cols / length;
|
||||
@@ -113,10 +104,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
|
||||
};
|
||||
},
|
||||
.left => {
|
||||
var length_usize: usize = 0;
|
||||
for (this.contents) |content| {
|
||||
length_usize += content.content.len;
|
||||
}
|
||||
const length_usize = this.contents.len;
|
||||
const length: u16 = @truncate(length_usize);
|
||||
const cols = @min(length, this.size.cols);
|
||||
const rows = cols / length;
|
||||
@@ -130,10 +118,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
|
||||
};
|
||||
},
|
||||
.right => {
|
||||
var length_usize: usize = 0;
|
||||
for (this.contents) |content| {
|
||||
length_usize += content.content.len;
|
||||
}
|
||||
const length_usize = this.contents.len;
|
||||
const length: u16 = @truncate(length_usize);
|
||||
const cols = @min(length, this.size.cols);
|
||||
const rows = cols / length;
|
||||
@@ -148,6 +133,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
|
||||
},
|
||||
}
|
||||
};
|
||||
log.debug("Text.contents: {any}", .{this.contents});
|
||||
try renderer.render(size, this.contents);
|
||||
this.require_render = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user