···1const std = @import("std");
2const vaxis = @import("vaxis");
034const Scrollbar = @This();
5···10style: vaxis.Style = .{},
1112/// The index of the bottom-most item, with 0 being "at the bottom"
13-bottom: usize = 0,
1415/// total items in the list
16-total: usize,
1718/// total items that fit within the view area
19-view_size: usize,
000000000000000000000002021-pub fn draw(self: Scrollbar, win: vaxis.Window) void {
0000022 // don't draw when 0 items
23- if (self.total < 1) return;
2425 // don't draw when all items can be shown
26- if (self.view_size >= self.total) return;
2728 // (view_size / total) * window height = size of the scroll bar
29- const bar_height = @max(std.math.divCeil(usize, self.view_size * win.height, self.total) catch unreachable, 1);
3031 // The row of the last cell of the bottom of the bar
32- const bar_bottom = (win.height - 1) -| (std.math.divCeil(usize, self.bottom * win.height, self.total) catch unreachable);
3334 var i: usize = 0;
35 while (i <= bar_height) : (i += 1)
36- win.writeCell(0, bar_bottom -| i, .{ .char = self.character, .style = self.style });
0037}
···1const std = @import("std");
2const vaxis = @import("vaxis");
3+const vxfw = vaxis.vxfw;
45const Scrollbar = @This();
6···11style: vaxis.Style = .{},
1213/// The index of the bottom-most item, with 0 being "at the bottom"
14+bottom: u16 = 0,
1516/// total items in the list
17+total: u16,
1819/// total items that fit within the view area
20+view_size: u16,
21+22+fn widget(self: *Scrollbar) vxfw.Widget {
23+ return .{
24+ .userdata = self,
25+ .drawFn = drawFn,
26+ };
27+}
28+29+fn drawFn(ptr: *anyopaque, ctx: vxfw.DrawContext) std.mem.Allocator.Error!vxfw.Surface {
30+ const self: *Scrollbar = @ptrCast(@alignCast(ptr));
31+ return self.draw(ctx);
32+}
33+34+pub fn draw(self: *Scrollbar, ctx: vxfw.DrawContext) std.mem.Allocator.Error!vxfw.Surface {
35+ const max = ctx.max.size();
36+ if (max.width == 0 or max.height == 0) {
37+ return .{
38+ .size = .{ .width = 0, .height = 0 },
39+ .widget = self.widget(),
40+ .buffer = &.{},
41+ .children = &.{},
42+ };
43+ }
4445+ const surface = try vxfw.Surface.init(
46+ ctx.arena,
47+ self.widget(),
48+ .{ .width = 2, .height = max.height },
49+ );
50+51 // don't draw when 0 items
52+ if (self.total < 1) return surface;
5354 // don't draw when all items can be shown
55+ if (self.view_size >= self.total) return surface;
5657 // (view_size / total) * window height = size of the scroll bar
58+ const bar_height = @max(std.math.divCeil(usize, self.view_size * max.height, self.total) catch unreachable, 1);
5960 // The row of the last cell of the bottom of the bar
61+ const bar_bottom = (max.height - 1) -| (std.math.divCeil(usize, self.bottom * max.height, self.total) catch unreachable);
6263 var i: usize = 0;
64 while (i <= bar_height) : (i += 1)
65+ surface.writeCell(0, @intCast(bar_bottom -| i), .{ .char = self.character, .style = self.style });
66+67+ return surface;
68}