Improved the Table Widget

- Added better Integer bounds checks with Saturated Operators.
- Implemented truncated cells using the "..." suffix.
This commit is contained in:
00JCIV00 2024-03-11 16:55:43 -04:00 committed by Tim Culverhouse
parent d75c44725e
commit 0329ae9b95

View file

@ -36,8 +36,9 @@ pub const TableContext = struct{
/// Draw a Table for the TUI. /// Draw a Table for the TUI.
pub fn drawTable( pub fn drawTable(
/// This should be an ArenaAllocator that can be deinitialized after each event call. /// This should be an ArenaAllocator that can be deinitialized after each event call.
/// The Allocator is only used if a row field is a non-String. /// The Allocator is only used in two cases:
/// If the Allocator is not provided, those fields will show "[unsupported (TypeName)]". /// 1. If a cell is a non-String. If the Allocator is not provided, those cells will show "[unsupported (TypeName)]".
/// 2. To show that a value is too large to fit into a cell. If the Allocator is not provided, they'll just be cutoff.
alloc: ?mem.Allocator, alloc: ?mem.Allocator,
/// The parent Window to draw to. /// The parent Window to draw to.
win: vaxis.Window, win: vaxis.Window,
@ -70,10 +71,13 @@ pub fn drawTable(
.{ .limit = item_width }, .{ .limit = item_width },
.{ .limit = 1 }, .{ .limit = 1 },
); );
var hdr = vaxis.widgets.alignment.center(hdr_win, @min(item_width - 1, hdr_txt.len + 1), 1); var hdr = vaxis.widgets.alignment.center(hdr_win, @min(item_width -| 1, hdr_txt.len +| 1), 1);
hdr_win.fill(.{ .style = .{ .bg = hdr_bg } }); hdr_win.fill(.{ .style = .{ .bg = hdr_bg } });
var seg = [_]vaxis.Cell.Segment{.{ var seg = [_]vaxis.Cell.Segment{.{
.text = hdr_txt, .text =
if (hdr_txt.len > item_width and alloc != null) try fmt.allocPrint(alloc.?, "{s}...", .{ hdr_txt[0..(item_width -| 4)] })
else hdr_txt
,
.style = .{ .style = .{
.bg = hdr_bg, .bg = hdr_bg,
.bold = true, .bold = true,
@ -83,7 +87,7 @@ pub fn drawTable(
try hdr.wrap(seg[0..]); try hdr.wrap(seg[0..]);
} }
const max_items = if (data_list.items.len > table_win.height - 1) table_win.height - 1 else data_list.items.len; const max_items = if (data_list.items.len > table_win.height -| 1) table_win.height -| 1 else data_list.items.len;
var end = table_ctx.*.start + max_items; var end = table_ctx.*.start + max_items;
if (end > data_list.items.len) end = data_list.items.len; if (end > data_list.items.len) end = data_list.items.len;
table_ctx.*.start = tableStart: { table_ctx.*.start = tableStart: {
@ -122,9 +126,7 @@ pub fn drawTable(
.{ .limit = item_width }, .{ .limit = item_width },
.{ .limit = 1 }, .{ .limit = 1 },
); );
item_win.fill(.{ .style = .{ .bg = row_bg } }); const item_txt = switch (ItemT) {
var seg = [_]vaxis.Cell.Segment{ .{
.text = switch(ItemT) {
[]const u8 => item, []const u8 => item,
else => nonStr: { else => nonStr: {
switch (@typeInfo(ItemT)) { switch (@typeInfo(ItemT)) {
@ -133,20 +135,22 @@ pub fn drawTable(
switch (@typeInfo(ItemT).Optional.child) { switch (@typeInfo(ItemT).Optional.child) {
[]const u8 => break :nonStr opt_item, []const u8 => break :nonStr opt_item,
else => { else => {
break :nonStr break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{any}", .{ opt_item }) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)});
if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{any}", .{ opt_item }) },
else fmt.comptimePrint("[unsupported ({s})]", .{ @typeName(DataT) });
}
} }
}, },
else => { else => {
break :nonStr break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{any}", .{ item }) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)});
if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{any}", .{ item }) },
else fmt.comptimePrint("[unsupported ({s})]", .{ @typeName(DataT) });
}
} }
}, },
}, };
item_win.fill(.{ .style = .{ .bg = row_bg } });
var seg = [_]vaxis.Cell.Segment{.{
.text =
if (item_txt.len > item_width and alloc != null) try fmt.allocPrint(alloc.?, "{s}...", .{ item_txt[0..(item_width -| 4)] })
else item_txt
,
.style = .{ .bg = row_bg }, .style = .{ .bg = row_bg },
} }; } };
try item_win.wrap(seg[0..]); try item_win.wrap(seg[0..]);