this repo has no description
13
fork

Configure Feed

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

at b58ae3a2fa16b3b7f11d2a7297c73a1e839d035b 128 lines 4.6 kB view raw
1const std = @import("std"); 2const vaxis = @import("../main.zig"); 3 4pub const Scroll = struct { 5 x: usize = 0, 6 y: usize = 0, 7 8 pub fn restrictTo(self: *@This(), w: usize, h: usize) void { 9 self.x = @min(self.x, w); 10 self.y = @min(self.y, h); 11 } 12}; 13 14pub const VerticalScrollbar = struct { 15 character: vaxis.Cell.Character = .{ .grapheme = "", .width = 1 }, 16 fg: vaxis.Style = .{}, 17 bg: vaxis.Style = .{ .fg = .{ .index = 8 } }, 18}; 19 20scroll: Scroll = .{}, 21vertical_scrollbar: ?VerticalScrollbar = .{}, 22 23/// Standard input mappings. 24/// It is not neccessary to use this, you can set `scroll` manually. 25pub fn input(self: *@This(), key: vaxis.Key) void { 26 if (key.matches(vaxis.Key.right, .{})) { 27 self.scroll.x +|= 1; 28 } else if (key.matches(vaxis.Key.right, .{ .shift = true })) { 29 self.scroll.x +|= 32; 30 } else if (key.matches(vaxis.Key.left, .{})) { 31 self.scroll.x -|= 1; 32 } else if (key.matches(vaxis.Key.left, .{ .shift = true })) { 33 self.scroll.x -|= 32; 34 } else if (key.matches(vaxis.Key.up, .{})) { 35 self.scroll.y -|= 1; 36 } else if (key.matches(vaxis.Key.page_up, .{})) { 37 self.scroll.y -|= 32; 38 } else if (key.matches(vaxis.Key.down, .{})) { 39 self.scroll.y +|= 1; 40 } else if (key.matches(vaxis.Key.page_down, .{})) { 41 self.scroll.y +|= 32; 42 } else if (key.matches(vaxis.Key.end, .{})) { 43 self.scroll.y = std.math.maxInt(usize); 44 } else if (key.matches(vaxis.Key.home, .{})) { 45 self.scroll.y = 0; 46 } 47} 48 49/// Must be called before doing any `writeCell` calls. 50pub fn draw(self: *@This(), parent: vaxis.Window, content_size: struct { 51 cols: usize, 52 rows: usize, 53}) void { 54 const content_cols = if (self.vertical_scrollbar) |_| content_size.cols +| 1 else content_size.cols; 55 const max_scroll_x = content_cols -| parent.width; 56 const max_scroll_y = content_size.rows -| parent.height; 57 self.scroll.restrictTo(max_scroll_x, max_scroll_y); 58 if (self.vertical_scrollbar) |opts| { 59 const vbar: vaxis.widgets.Scrollbar = .{ 60 .character = opts.character, 61 .style = opts.fg, 62 .total = content_size.rows, 63 .view_size = parent.height, 64 .top = self.scroll.y, 65 }; 66 const bg = parent.child(.{ 67 .x_off = parent.width -| opts.character.width, 68 .width = opts.character.width, 69 .height = parent.height, 70 }); 71 bg.fill(.{ .char = opts.character, .style = opts.bg }); 72 vbar.draw(bg); 73 } 74} 75 76pub const BoundingBox = struct { 77 x1: usize, 78 y1: usize, 79 x2: usize, 80 y2: usize, 81 82 pub inline fn below(self: @This(), row: usize) bool { 83 return row < self.y1; 84 } 85 86 pub inline fn above(self: @This(), row: usize) bool { 87 return row >= self.y2; 88 } 89 90 pub inline fn rowInside(self: @This(), row: usize) bool { 91 return row >= self.y1 and row < self.y2; 92 } 93 94 pub inline fn colInside(self: @This(), col: usize) bool { 95 return col >= self.x1 and col < self.x2; 96 } 97 98 pub inline fn inside(self: @This(), col: usize, row: usize) bool { 99 return self.rowInside(row) and self.colInside(col); 100 } 101}; 102 103/// Boundary of the content, useful for culling to improve draw performance. 104pub fn bounds(self: *@This(), parent: vaxis.Window) BoundingBox { 105 const right_pad: usize = if (self.vertical_scrollbar != null) 1 else 0; 106 return .{ 107 .x1 = self.scroll.x, 108 .y1 = self.scroll.y, 109 .x2 = self.scroll.x +| parent.width -| right_pad, 110 .y2 = self.scroll.y +| parent.height, 111 }; 112} 113 114/// Use this function instead of `Window.writeCell` to draw your cells and they will magically scroll. 115pub fn writeCell(self: *@This(), parent: vaxis.Window, col: usize, row: usize, cell: vaxis.Cell) void { 116 const b = self.bounds(parent); 117 if (!b.inside(col, row)) return; 118 const win = parent.child(.{ .width = @intCast(b.x2 - b.x1), .height = @intCast(b.y2 - b.y1) }); 119 win.writeCell(@intCast(col -| self.scroll.x), @intCast(row -| self.scroll.y), cell); 120} 121 122/// Use this function instead of `Window.readCell` to read the correct cell in scrolling context. 123pub fn readCell(self: *@This(), parent: vaxis.Window, col: usize, row: usize) ?vaxis.Cell { 124 const b = self.bounds(parent); 125 if (!b.inside(col, row)) return; 126 const win = parent.child(.{ .width = @intCast(b.x2 - b.x1), .height = @intCast(b.y2 - b.y1) }); 127 return win.readCell(@intCast(col -| self.scroll.x), @intCast(row -| self.scroll.y)); 128}