widgets(table): implemented customizable column widths
- Added the `WidthStyle` union to the Table Widget. This allows users to choose from 4 different options for Column Widths. - Updated the Table Example with demos of the various styles (via comments).
This commit is contained in:
parent
bbbfbaffbb
commit
a99fd3c29f
2 changed files with 73 additions and 21 deletions
|
@ -78,7 +78,10 @@ pub fn main() !void {
|
|||
var demo_tbl: vaxis.widgets.Table.TableContext = .{
|
||||
.active_bg = active_bg,
|
||||
.selected_bg = selected_bg,
|
||||
//.col_width = 10,
|
||||
//.col_width = .{ .static_all = 15 },
|
||||
//.col_width = .{ .dynamic_header_len = 3 },
|
||||
//.col_width = .{ .static_individual = &.{ 10, 20, 15, 25, 15 } },
|
||||
//.col_width = .dynamic_fill,
|
||||
//.y_off = 10,
|
||||
};
|
||||
defer if (demo_tbl.sel_rows) |rows| alloc.free(rows);
|
||||
|
|
|
@ -37,8 +37,26 @@ pub const TableContext = struct {
|
|||
y_off: usize = 0,
|
||||
|
||||
/// Column Width
|
||||
<<<<<<< HEAD
|
||||
/// Note, this should be treated as Read Only. The Column Width will be calculated during `drawTable()`.
|
||||
col_width: ?usize = 0,
|
||||
=======
|
||||
/// Note, if this is left `null` the Column Width will be dynamically calculated during `drawTable()`.
|
||||
//col_width: ?usize = null,
|
||||
col_width: WidthStyle = .dynamic_fill,
|
||||
};
|
||||
|
||||
/// Width Styles for `col_width`.
|
||||
pub const WidthStyle = union(enum) {
|
||||
/// Dynamically calculate Column Widths such that the entire (or most) of the screen is filled horizontally.
|
||||
dynamic_fill,
|
||||
/// Dynamically calculate the Column Width for each Column based on its Header Length and the provided Padding length.
|
||||
dynamic_header_len: usize,
|
||||
/// Statically set all Column Widths to the same value.
|
||||
static_all: usize,
|
||||
/// Statically set individual Column Widths to specific values.
|
||||
static_individual: []const usize,
|
||||
>>>>>>> 7918b49 (widgets(table): implemented customizable column widths)
|
||||
};
|
||||
|
||||
/// Draw a Table for the TUI.
|
||||
|
@ -118,16 +136,21 @@ pub fn drawTable(
|
|||
.{ .limit = win.height },
|
||||
);
|
||||
|
||||
table_ctx.col_width = table_win.width / headers.len;
|
||||
if (table_ctx.col_width % 2 != 0) table_ctx.col_width +|= 1;
|
||||
while (table_ctx.col_width * headers.len < table_win.width - 1) table_ctx.col_width +|= 1;
|
||||
|
||||
if (table_ctx.col > headers.len - 1) table_ctx.*.col = headers.len - 1;
|
||||
var col_start: usize = 0;
|
||||
for (headers[0..], 0..) |hdr_txt, idx| {
|
||||
const col_width = try calcColWidth(
|
||||
idx,
|
||||
headers,
|
||||
table_ctx.col_width,
|
||||
table_win,
|
||||
);
|
||||
defer col_start += col_width;
|
||||
const hdr_bg =
|
||||
if (table_ctx.active and idx == table_ctx.col) table_ctx.active_bg else if (idx % 2 == 0) table_ctx.hdr_bg_1 else table_ctx.hdr_bg_2;
|
||||
const hdr_win = table_win.child(.{
|
||||
.x_off = idx * col_width,
|
||||
//.x_off = idx * col_width,
|
||||
.x_off = col_start,
|
||||
.y_off = 0,
|
||||
.width = .{ .limit = col_width },
|
||||
.height = .{ .limit = 1 },
|
||||
|
@ -179,25 +202,25 @@ pub fn drawTable(
|
|||
.{ .limit = 1 },
|
||||
);
|
||||
const DataT = @TypeOf(data);
|
||||
if (DataT == []const u8) {
|
||||
row_win.fill(.{ .style = .{ .bg = row_bg } });
|
||||
var seg = [_]vaxis.Cell.Segment{.{
|
||||
.text = if (data.len > table_ctx.col_width and alloc != null) try fmt.allocPrint(alloc.?, "{s}...", .{data[0..(table_ctx.col_width -| 4)]}) else data,
|
||||
.style = .{ .bg = row_bg },
|
||||
}};
|
||||
_ = try row_win.print(seg[0..], .{ .wrap = .word });
|
||||
return;
|
||||
}
|
||||
col_start = 0;
|
||||
const item_fields = meta.fields(DataT);
|
||||
inline for (item_fields[0..], 0..) |item_field, item_idx| {
|
||||
const col_width = try calcColWidth(
|
||||
item_idx,
|
||||
headers,
|
||||
table_ctx.col_width,
|
||||
table_win,
|
||||
);
|
||||
defer col_start += col_width;
|
||||
const item = @field(data, item_field.name);
|
||||
const ItemT = @TypeOf(item);
|
||||
const item_win = row_win.initChild(
|
||||
item_idx * table_ctx.col_width,
|
||||
0,
|
||||
.{ .limit = table_ctx.col_width },
|
||||
.{ .limit = 1 },
|
||||
);
|
||||
const item_win = row_win.child(.{
|
||||
//.x_off = item_idx * col_width,
|
||||
.x_off = col_start,
|
||||
.y_off = 0,
|
||||
.width = .{ .limit = col_width },
|
||||
.height =.{ .limit = 1 },
|
||||
});
|
||||
const item_txt = switch (ItemT) {
|
||||
[]const u8 => item,
|
||||
else => nonStr: {
|
||||
|
@ -226,3 +249,29 @@ pub fn drawTable(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the Column Width of `col` using the provided Number of Headers (`num_hdrs`), Width Style (`style`), and Table Window (`table_win`).
|
||||
pub fn calcColWidth (
|
||||
col: usize,
|
||||
headers: []const []const u8,
|
||||
style: WidthStyle,
|
||||
table_win: vaxis.Window,
|
||||
) !usize {
|
||||
return switch (style) {
|
||||
.dynamic_fill => dynFill: {
|
||||
var cw = table_win.width / headers.len;
|
||||
if (cw % 2 != 0) cw +|= 1;
|
||||
while (cw * headers.len < table_win.width - 1) cw +|= 1;
|
||||
break :dynFill cw;
|
||||
},
|
||||
.dynamic_header_len => dynHdrs: {
|
||||
if (col >= headers.len) break :dynHdrs error.NotEnoughStaticWidthsProvided;
|
||||
break :dynHdrs headers[col].len + (style.dynamic_header_len * 2);
|
||||
},
|
||||
.static_all => style.static_all,
|
||||
.static_individual => statInd: {
|
||||
if (col >= headers.len) break :statInd error.NotEnoughStaticWidthsProvided;
|
||||
break :statInd style.static_individual[col];
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue