a modern tui library written in zig

widgets(table): implemented selectable rows

- Implemented `TableContext.sel_rows`, allowing users to specify which rows have been 'selected' (similar to ctrl+clicking items in a GUI file browser).
- Changed previous 'selected' verbiage to 'active' in all cases.

authored by

00JCIV00 and committed by rockorager.dev bbbfbaff 5972da8e

+46 -16
+22 -3
examples/table.zig
··· 70 70 defer cmd_input.deinit(); 71 71 72 72 // Colors 73 - const selected_bg: vaxis.Cell.Color = .{ .rgb = .{ 64, 128, 255 } }; 73 + const active_bg: vaxis.Cell.Color = .{ .rgb = .{ 64, 128, 255 } }; 74 + const selected_bg: vaxis.Cell.Color = .{ .rgb = .{ 32, 64, 255 } }; 74 75 const other_bg: vaxis.Cell.Color = .{ .rgb = .{ 32, 32, 48 } }; 75 76 76 77 // Table Context 77 - var demo_tbl: vaxis.widgets.Table.TableContext = .{ 78 + var demo_tbl: vaxis.widgets.Table.TableContext = .{ 79 + .active_bg = active_bg, 78 80 .selected_bg = selected_bg, 79 81 //.col_width = 10, 82 + //.y_off = 10, 80 83 }; 84 + defer if (demo_tbl.sel_rows) |rows| alloc.free(rows); 81 85 82 86 // TUI State 83 87 var active: ActiveSection = .mid; ··· 135 139 // Change Column 136 140 if (key.matchesAny(&.{ vaxis.Key.left, 'h' }, .{})) demo_tbl.col -|= 1; 137 141 if (key.matchesAny(&.{ vaxis.Key.right, 'l' }, .{})) demo_tbl.col +|= 1; 142 + // Select/Unselect Row 143 + if (key.matches(vaxis.Key.space, .{})) { 144 + const rows = demo_tbl.sel_rows orelse createRows: { 145 + demo_tbl.sel_rows = try alloc.alloc(usize, 1); 146 + break :createRows demo_tbl.sel_rows.?; 147 + }; 148 + var rows_list = std.ArrayList(usize).fromOwnedSlice(alloc, rows); 149 + for (rows_list.items, 0..) |row, idx| { 150 + if (row != demo_tbl.row) continue; 151 + _ = rows_list.orderedRemove(idx); 152 + break; 153 + } 154 + else try rows_list.append(demo_tbl.row); 155 + demo_tbl.sel_rows = try rows_list.toOwnedSlice(); 156 + } 138 157 }, 139 158 .btm => { 140 159 if (key.matchesAny(&.{ vaxis.Key.up, 'k' }, .{}) and moving) active = .mid ··· 216 235 .width = .{ .limit = win.width }, 217 236 .height = .{ .limit = 1 }, 218 237 }); 219 - if (active == .btm) bottom_bar.fill(.{ .style = .{ .bg = selected_bg } }); 238 + if (active == .btm) bottom_bar.fill(.{ .style = .{ .bg = active_bg } }); 220 239 cmd_input.draw(bottom_bar); 221 240 222 241 // Render the screen
+24 -13
src/widgets/Table.zig
··· 8 8 9 9 /// Table Context for maintaining state and drawing Tables with `drawTable()`. 10 10 pub const TableContext = struct { 11 - /// Current selected Row of the Table. 11 + /// Current active Row of the Table. 12 12 row: usize = 0, 13 - /// Current selected Column of the Table. 13 + /// Current active Column of the Table. 14 14 col: usize = 0, 15 15 /// Starting point within the Data List. 16 16 start: usize = 0, 17 + /// Selected Rows. 18 + sel_rows: ?[]usize = null, 17 19 18 20 /// Active status of the Table. 19 21 active: bool = false, 20 22 21 - /// The Background Color for Selected Rows and Column Headers. 23 + /// The Background Color for the Active Row and Column Header. 22 24 selected_bg: vaxis.Cell.Color, 25 + /// The Background Color for Selected Rows. 26 + active_bg: vaxis.Cell.Color, 23 27 /// First Column Header Background Color 24 28 hdr_bg_1: vaxis.Cell.Color = .{ .rgb = [_]u8{ 64, 64, 64 } }, 25 29 /// Second Column Header Background Color ··· 121 125 if (table_ctx.col > headers.len - 1) table_ctx.*.col = headers.len - 1; 122 126 for (headers[0..], 0..) |hdr_txt, idx| { 123 127 const hdr_bg = 124 - if (table_ctx.active and idx == table_ctx.col) table_ctx.selected_bg else if (idx % 2 == 0) table_ctx.hdr_bg_1 else table_ctx.hdr_bg_2; 125 - const hdr_win = table_win.initChild( 126 - idx * table_ctx.col_width, 127 - 0, 128 - .{ .limit = table_ctx.col_width }, 129 - .{ .limit = 1 }, 130 - ); 131 - var hdr = vaxis.widgets.alignment.center(hdr_win, @min(table_ctx.col_width -| 1, hdr_txt.len +| 1), 1); 128 + 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; 129 + const hdr_win = table_win.child(.{ 130 + .x_off = idx * col_width, 131 + .y_off = 0, 132 + .width = .{ .limit = col_width }, 133 + .height = .{ .limit = 1 }, 134 + }); 135 + var hdr = vaxis.widgets.alignment.center(hdr_win, @min(col_width -| 1, hdr_txt.len +| 1), 1); 132 136 hdr_win.fill(.{ .style = .{ .bg = hdr_bg } }); 133 137 var seg = [_]vaxis.Cell.Segment{.{ 134 138 .text = if (hdr_txt.len > table_ctx.col_width and alloc != null) try fmt.allocPrint(alloc.?, "{s}...", .{hdr_txt[0..(table_ctx.col_width -| 4)]}) else hdr_txt, ··· 158 162 end = table_ctx.*.start + max_items; 159 163 if (end > data_items.len) end = data_items.len; 160 164 for (data_items[table_ctx.start..end], 0..) |data, idx| { 161 - const row_bg = 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; 165 + const row_bg = rowBG: { 166 + if (table_ctx.active and table_ctx.start + idx == table_ctx.row) 167 + break :rowBG table_ctx.active_bg; 168 + if (table_ctx.sel_rows) |rows| { 169 + if (mem.indexOfScalar(usize, rows, table_ctx.start + idx) != null) break :rowBG table_ctx.selected_bg; 170 + } 171 + if (idx % 2 == 0) break :rowBG table_ctx.row_bg_1; 172 + break :rowBG table_ctx.row_bg_2; 173 + }; 163 174 164 175 const row_win = table_win.initChild( 165 176 0,