this repo has no description
13
fork

Configure Feed

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

widgets(table): added ability to reorder and duplicate columns

- Changed the behavior of `ColumnIndexes.by_idx` (used f/ `TableContext.col_indexes`) to allow valid field indexes in any order. Indexes can also be removed or added multiple times to affect the table generation accordingly.

authored by

00JCIV00 and committed by
Tim Culverhouse
c89b75eb eaa9c158

+83 -80
+2 -2
examples/table.zig
··· 80 80 .active_bg = active_bg, 81 81 .active_fg = .{ .rgb = .{ 0, 0, 0 } }, 82 82 .selected_bg = selected_bg, 83 - .header_names = .{ .custom = &.{ "First", "Last", "Username", "Email", "Phone#" } }, 83 + .header_names = .{ .custom = &.{ "First", "Last", "Username", "Phone#", "Email" } }, 84 84 //.header_names = .{ .custom = &.{ "First", "Last", "Email", "Phone#" } }, 85 - //.col_indexes = .{ .by_idx = &.{ 0, 1, 3, 4 } }, 85 + .col_indexes = .{ .by_idx = &.{ 0, 1, 2, 4, 3 } }, 86 86 //.col_width = .{ .static_all = 15 }, 87 87 //.col_width = .{ .dynamic_header_len = 3 }, 88 88 //.col_width = .{ .static_individual = &.{ 10, 20, 15, 25, 15 } },
+81 -78
src/widgets/Table.zig
··· 158 158 } 159 159 }; 160 160 defer if (di_is_mal) alloc.?.free(data_items); 161 + const DataT = @TypeOf(data_items[0]); 162 + const fields = meta.fields(DataT); 163 + const field_indexes = switch (table_ctx.col_indexes) { 164 + .all => comptime allIdx: { 165 + var indexes_buf: [fields.len]usize = undefined; 166 + for (0..fields.len) |idx| indexes_buf[idx] = idx; 167 + const indexes = indexes_buf; 168 + break :allIdx indexes[0..]; 169 + }, 170 + .by_idx => |by_idx| by_idx, 171 + }; 161 172 162 173 // Headers for the Table 163 - var hdrs_buf: [100][]const u8 = undefined; 174 + var hdrs_buf: [fields.len][]const u8 = undefined; 164 175 const headers = hdrs: { 165 176 switch (table_ctx.header_names) { 166 177 .field_names => { 167 - const DataT = @TypeOf(data_items[0]); 168 - const fields = meta.fields(DataT); 169 - var num_hdrs: usize = 0; 170 - inline for (fields, 0..) |field, idx| contFields: { 171 - switch (table_ctx.col_indexes) { 172 - .all => {}, 173 - .by_idx => |idxs| { 174 - if (mem.indexOfScalar(usize, idxs, idx) == null) break :contFields; 175 - }, 178 + for (field_indexes) |f_idx| { 179 + inline for (fields, 0..) |field, idx| { 180 + if (f_idx == idx) 181 + hdrs_buf[idx] = field.name; 176 182 } 177 - num_hdrs += 1; 178 - hdrs_buf[idx] = field.name; 179 183 } 180 - break :hdrs hdrs_buf[0..num_hdrs]; 184 + break :hdrs hdrs_buf[0..]; 181 185 }, 182 186 .custom => |hdrs| break :hdrs hdrs, 183 187 } ··· 201 205 table_win, 202 206 ); 203 207 defer col_start += col_width; 204 - const hdr_fg, 205 - const hdr_bg = hdrColors: { 206 - if (table_ctx.active and idx == table_ctx.col) 207 - break :hdrColors .{ table_ctx.active_fg, table_ctx.active_bg } 208 - else if (idx % 2 == 0) 209 - break :hdrColors .{ .default, table_ctx.hdr_bg_1 } 210 - else 208 + const hdr_fg, const hdr_bg = hdrColors: { 209 + if (table_ctx.active and idx == table_ctx.col) 210 + break :hdrColors .{ table_ctx.active_fg, table_ctx.active_bg } 211 + else if (idx % 2 == 0) 212 + break :hdrColors .{ .default, table_ctx.hdr_bg_1 } 213 + else 211 214 break :hdrColors .{ .default, table_ctx.hdr_bg_2 }; 212 215 }; 213 216 const hdr_win = table_win.child(.{ ··· 256 259 table_ctx.start = @min(table_ctx.start, end); 257 260 table_ctx.active_y_off = 0; 258 261 for (data_items[table_ctx.start..end], 0..) |data, row| { 259 - const row_fg, 260 - const row_bg = rowColors: { 262 + const row_fg, const row_bg = rowColors: { 261 263 if (table_ctx.active and table_ctx.start + row == table_ctx.row) 262 264 break :rowColors .{ table_ctx.active_fg, table_ctx.active_bg }; 263 265 if (table_ctx.sel_rows) |rows| { 264 - if (mem.indexOfScalar(usize, rows, table_ctx.start + row) != null) 266 + if (mem.indexOfScalar(usize, rows, table_ctx.start + row) != null) 265 267 break :rowColors .{ table_ctx.selected_fg, table_ctx.selected_bg }; 266 268 } 267 269 if (row % 2 == 0) break :rowColors .{ .default, table_ctx.row_bg_1 }; ··· 276 278 if (table_ctx.start + row == table_ctx.row) { 277 279 table_ctx.active_y_off = if (table_ctx.active_content_fn) |content| try content(&row_win, table_ctx.active_ctx) else 0; 278 280 } 279 - const DataT = @TypeOf(data); 280 281 col_start = 0; 281 282 const item_fields = meta.fields(DataT); 282 - inline for (item_fields[0..], 0..) |item_field, item_idx| contFields: { 283 - switch (table_ctx.col_indexes) { 284 - .all => {}, 285 - .by_idx => |idxs| { 286 - if (mem.indexOfScalar(usize, idxs, item_idx) == null) break :contFields; 287 - }, 283 + for (field_indexes) |f_idx| { 284 + inline for (item_fields[0..], 0..) |item_field, item_idx| contFields: { 285 + switch (table_ctx.col_indexes) { 286 + .all => {}, 287 + .by_idx => { 288 + if (item_idx != f_idx) break :contFields; 289 + }, 290 + } 291 + const col_width = try calcColWidth( 292 + item_idx, 293 + headers, 294 + table_ctx.col_width, 295 + table_win, 296 + ); 297 + defer col_start += col_width; 298 + const item = @field(data, item_field.name); 299 + const ItemT = @TypeOf(item); 300 + const item_win = row_win.child(.{ 301 + .x_off = col_start, 302 + .y_off = 0, 303 + .width = .{ .limit = col_width }, 304 + .height = .{ .limit = 1 }, 305 + }); 306 + const item_txt = switch (ItemT) { 307 + []const u8 => item, 308 + [][]const u8, []const []const u8 => strSlice: { 309 + if (alloc) |_alloc| break :strSlice try fmt.allocPrint(_alloc, "{s}", .{item}); 310 + break :strSlice item; 311 + }, 312 + else => nonStr: { 313 + switch (@typeInfo(ItemT)) { 314 + .Enum => break :nonStr @tagName(item), 315 + .Optional => { 316 + const opt_item = item orelse break :nonStr "-"; 317 + switch (@typeInfo(ItemT).Optional.child) { 318 + []const u8 => break :nonStr opt_item, 319 + [][]const u8, []const []const u8 => { 320 + break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{s}", .{opt_item}) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); 321 + }, 322 + else => { 323 + break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{any}", .{opt_item}) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); 324 + }, 325 + } 326 + }, 327 + else => { 328 + break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{any}", .{item}) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); 329 + }, 330 + } 331 + }, 332 + }; 333 + item_win.fill(.{ .style = .{ .bg = row_bg } }); 334 + var seg = [_]vaxis.Cell.Segment{.{ 335 + .text = if (item_txt.len > col_width and alloc != null) try fmt.allocPrint(alloc.?, "{s}...", .{item_txt[0..(col_width -| 4)]}) else item_txt, 336 + .style = .{ .fg = row_fg, .bg = row_bg }, 337 + }}; 338 + _ = try item_win.print(seg[0..], .{ .wrap = .word, .col_offset = table_ctx.cell_x_off }); 288 339 } 289 - const col_width = try calcColWidth( 290 - item_idx, 291 - headers, 292 - table_ctx.col_width, 293 - table_win, 294 - ); 295 - defer col_start += col_width; 296 - const item = @field(data, item_field.name); 297 - const ItemT = @TypeOf(item); 298 - const item_win = row_win.child(.{ 299 - .x_off = col_start, 300 - .y_off = 0, 301 - .width = .{ .limit = col_width }, 302 - .height = .{ .limit = 1 }, 303 - }); 304 - const item_txt = switch (ItemT) { 305 - []const u8 => item, 306 - [][]const u8, []const []const u8 => strSlice: { 307 - if (alloc) |_alloc| break :strSlice try fmt.allocPrint(_alloc, "{s}", .{item}); 308 - break :strSlice item; 309 - }, 310 - else => nonStr: { 311 - switch (@typeInfo(ItemT)) { 312 - .Enum => break :nonStr @tagName(item), 313 - .Optional => { 314 - const opt_item = item orelse break :nonStr "-"; 315 - switch (@typeInfo(ItemT).Optional.child) { 316 - []const u8 => break :nonStr opt_item, 317 - [][]const u8, []const []const u8 => { 318 - break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{s}", .{opt_item}) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); 319 - }, 320 - else => { 321 - break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{any}", .{opt_item}) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); 322 - }, 323 - } 324 - }, 325 - else => { 326 - break :nonStr if (alloc) |_alloc| try fmt.allocPrint(_alloc, "{any}", .{item}) else fmt.comptimePrint("[unsupported ({s})]", .{@typeName(DataT)}); 327 - }, 328 - } 329 - }, 330 - }; 331 - item_win.fill(.{ .style = .{ .bg = row_bg } }); 332 - var seg = [_]vaxis.Cell.Segment{.{ 333 - .text = if (item_txt.len > col_width and alloc != null) try fmt.allocPrint(alloc.?, "{s}...", .{item_txt[0..(col_width -| 4)]}) else item_txt, 334 - .style = .{ .fg = row_fg, .bg = row_bg }, 335 - }}; 336 - _ = try item_win.print(seg[0..], .{ .wrap = .word, .col_offset = table_ctx.cell_x_off }); 337 340 } 338 341 } 339 342 }