this repo has no description
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

widgets(table): add support for Slices and MultiArrayLists

- Updated the Table Widget to support Slices and MultiArrayLists (in addtion to ArrayLists) for the `data_list` parameter of `drawTable()`.

authored by

00JCIV00 and committed by
Tim Culverhouse
94879164 707c050a

+71 -11
+1
.gitignore
··· 3 3 zig-out/ 4 4 *.log 5 5 Session*.*vim 6 + commit_msg
+5
examples/table.zig
··· 23 23 const users_buf = try alloc.dupe(User, users[0..]); 24 24 const user_list = std.ArrayList(User).fromOwnedSlice(alloc, users_buf); 25 25 defer user_list.deinit(); 26 + var user_mal = std.MultiArrayList(User){}; 27 + for (users_buf[0..]) |user| try user_mal.append(alloc, user); 28 + defer user_mal.deinit(alloc); 26 29 27 30 var tty = try vaxis.Tty.init(); 28 31 defer tty.deinit(); ··· 191 194 event_alloc, 192 195 middle_bar, 193 196 &.{ "First", "Last", "Username", "Email", "Phone#" }, 197 + //users_buf[0..], 194 198 user_list, 199 + //user_mal, 195 200 &demo_tbl, 196 201 ); 197 202 }
+65 -11
src/widgets/Table.zig
··· 34 34 35 35 /// Column Width 36 36 /// Note, this should be treated as Read Only. The Column Width will be calculated during `drawTable()`. 37 - col_width: usize = 0, 37 + col_width: ?usize = 0, 38 38 }; 39 39 40 40 /// Draw a Table for the TUI. 41 41 pub fn drawTable( 42 42 /// This should be an ArenaAllocator that can be deinitialized after each event call. 43 - /// The Allocator is only used in two cases: 44 - /// 1. If a cell is a non-String. If the Allocator is not provided, those cells will show "[unsupported (TypeName)]". 45 - /// 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. 43 + /// The Allocator is only used in three cases: 44 + /// 1. If a cell is a non-String. (If the Allocator is not provided, those cells will show "[unsupported (TypeName)]".) 45 + /// 2. To show that a value is too large to fit into a cell using '...'. (If the Allocator is not provided, they'll just be cutoff.) 46 + /// 3. To copy a MultiArrayList into a normal slice. (Note, this is an expensive operation. Prefer to pass a Slice or ArrayList if possible.) 46 47 alloc: ?mem.Allocator, 47 48 /// The parent Window to draw to. 48 49 win: vaxis.Window, 49 50 /// Headers for the Table 50 51 headers: []const []const u8, 51 - /// This must be an ArrayList. 52 + /// This must be a Slice, ArrayList, or MultiArrayList. 53 + /// Note, MultiArrayList support currently requires allocation. 52 54 data_list: anytype, 53 55 // The Table Context for this Table. 54 56 table_ctx: *TableContext, 55 57 ) !void { 58 + var di_is_mal = false; 59 + const data_items = getData: { 60 + const DataListT = @TypeOf(data_list); 61 + const data_ti = @typeInfo(DataListT); 62 + switch (data_ti) { 63 + .Pointer => |ptr| { 64 + if (ptr.size != .Slice) return error.UnsupportedTableDataType; 65 + break :getData data_list; 66 + }, 67 + .Struct => { 68 + const di_fields = meta.fields(DataListT); 69 + const al_fields = meta.fields(std.ArrayList([]const u8)); 70 + const mal_fields = meta.fields(std.MultiArrayList(struct{ a: u8 = 0, b: u32 = 0 })); 71 + // Probably an ArrayList 72 + const is_al = comptime if ( 73 + mem.indexOf(u8, @typeName(DataListT), "MultiArrayList") == null and 74 + mem.indexOf(u8, @typeName(DataListT), "ArrayList") != null and 75 + al_fields.len == di_fields.len 76 + ) isAL: { 77 + var is = true; 78 + for (al_fields, di_fields) |al_field, di_field| 79 + is = is and mem.eql(u8, al_field.name, di_field.name); 80 + break :isAL is; 81 + } else false; 82 + if (is_al) break :getData data_list.items; 83 + 84 + // Probably a MultiArrayList 85 + const is_mal = if ( 86 + mem.indexOf(u8, @typeName(DataListT), "MultiArrayList") != null and 87 + mal_fields.len == di_fields.len 88 + ) isMAL: { 89 + var is = true; 90 + inline for (mal_fields, di_fields) |mal_field, di_field| 91 + is = is and mem.eql(u8, mal_field.name, di_field.name); 92 + break :isMAL is; 93 + } else false; 94 + if (!is_mal) return error.UnsupportedTableDataType; 95 + if (alloc) |_alloc| { 96 + di_is_mal = true; 97 + const mal_slice = data_list.slice(); 98 + const DataT = @TypeOf(mal_slice.get(0)); 99 + var data_out_list = std.ArrayList(DataT).init(_alloc); 100 + for (0..mal_slice.len) |idx| try data_out_list.append(mal_slice.get(idx)); 101 + break :getData try data_out_list.toOwnedSlice(); 102 + } 103 + return error.UnsupportedTableDataType; 104 + }, 105 + else => return error.UnsupportedTableDataType, 106 + } 107 + }; 108 + defer if (di_is_mal) alloc.?.free(data_items); 109 + 56 110 const table_win = win.initChild( 57 111 0, 58 112 table_ctx.y_off, ··· 87 141 _ = try hdr.print(seg[0..], .{ .wrap = .word }); 88 142 } 89 143 90 - const max_items = if (data_list.items.len > table_win.height -| 1) table_win.height -| 1 else data_list.items.len; 144 + const max_items = if (data_items.len > table_win.height -| 1) table_win.height -| 1 else data_items.len; 91 145 var end = table_ctx.*.start + max_items; 92 - if (end > data_list.items.len) end = data_list.items.len; 146 + if (end > data_items.len) end = data_items.len; 93 147 table_ctx.*.start = tableStart: { 94 148 if (table_ctx.row == 0) 95 149 break :tableStart 0; 96 150 if (table_ctx.row < table_ctx.start) 97 151 break :tableStart table_ctx.start - (table_ctx.start - table_ctx.row); 98 - if (table_ctx.row >= data_list.items.len - 1) 99 - table_ctx.*.row = data_list.items.len - 1; 152 + if (table_ctx.row >= data_items.len - 1) 153 + table_ctx.*.row = data_items.len - 1; 100 154 if (table_ctx.row >= end) 101 155 break :tableStart table_ctx.start + (table_ctx.row - end + 1); 102 156 break :tableStart table_ctx.start; 103 157 }; 104 158 end = table_ctx.*.start + max_items; 105 - if (end > data_list.items.len) end = data_list.items.len; 106 - for (data_list.items[table_ctx.start..end], 0..) |data, idx| { 159 + if (end > data_items.len) end = data_items.len; 160 + for (data_items[table_ctx.start..end], 0..) |data, idx| { 107 161 const row_bg = 108 162 if (table_ctx.active and table_ctx.start + idx == table_ctx.row) table_ctx.selected_bg else if (idx % 2 == 0) table_ctx.row_bg_1 else table_ctx.row_bg_2; 109 163