this repo has no description
13
fork

Configure Feed

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

at 3943a6f42f7f4c73ab9493dfb0a4e123be15d302 146 lines 5.1 kB view raw
1const std = @import("std"); 2const vaxis = @import("../main.zig"); 3 4const Allocator = std.mem.Allocator; 5 6const vxfw = @import("vxfw.zig"); 7 8pub const BorderLabel = struct { 9 text: []const u8, 10 alignment: enum { 11 top_left, 12 top_center, 13 top_right, 14 bottom_left, 15 bottom_center, 16 bottom_right, 17 }, 18}; 19 20const Border = @This(); 21 22child: vxfw.Widget, 23style: vaxis.Style = .{}, 24labels: []const BorderLabel = &[_]BorderLabel{}, 25 26pub fn widget(self: *const Border) vxfw.Widget { 27 return .{ 28 .userdata = @constCast(self), 29 .drawFn = typeErasedDrawFn, 30 }; 31} 32 33fn typeErasedDrawFn(ptr: *anyopaque, ctx: vxfw.DrawContext) Allocator.Error!vxfw.Surface { 34 const self: *const Border = @ptrCast(@alignCast(ptr)); 35 return self.draw(ctx); 36} 37 38/// If Border has a bounded maximum size, it will shrink the maximum size to account for the border 39/// before drawing the child. If the size is unbounded, border will draw the child and then itself 40/// around the childs size 41pub fn draw(self: *const Border, ctx: vxfw.DrawContext) Allocator.Error!vxfw.Surface { 42 const max_width: ?u16 = if (ctx.max.width) |width| width -| 2 else null; 43 const max_height: ?u16 = if (ctx.max.height) |height| height -| 2 else null; 44 45 const child_ctx = ctx.withConstraints(ctx.min, .{ 46 .width = max_width, 47 .height = max_height, 48 }); 49 const child = try self.child.draw(child_ctx); 50 51 const children = try ctx.arena.alloc(vxfw.SubSurface, 1); 52 children[0] = .{ 53 .origin = .{ .col = 1, .row = 1 }, 54 .z_index = 0, 55 .surface = child, 56 }; 57 58 const size: vxfw.Size = .{ .width = child.size.width + 2, .height = child.size.height + 2 }; 59 60 var surf = try vxfw.Surface.initWithChildren(ctx.arena, self.widget(), size, children); 61 62 // Draw the border 63 const right_edge = size.width -| 1; 64 const bottom_edge = size.height -| 1; 65 surf.writeCell(0, 0, .{ .char = .{ .grapheme = "", .width = 1 }, .style = self.style }); 66 surf.writeCell(right_edge, 0, .{ .char = .{ .grapheme = "", .width = 1 }, .style = self.style }); 67 surf.writeCell(right_edge, bottom_edge, .{ .char = .{ .grapheme = "", .width = 1 }, .style = self.style }); 68 surf.writeCell(0, bottom_edge, .{ .char = .{ .grapheme = "", .width = 1 }, .style = self.style }); 69 70 var col: u16 = 1; 71 while (col < right_edge) : (col += 1) { 72 surf.writeCell(col, 0, .{ .char = .{ .grapheme = "", .width = 1 }, .style = self.style }); 73 surf.writeCell(col, bottom_edge, .{ .char = .{ .grapheme = "", .width = 1 }, .style = self.style }); 74 } 75 76 var row: u16 = 1; 77 while (row < bottom_edge) : (row += 1) { 78 surf.writeCell(0, row, .{ .char = .{ .grapheme = "", .width = 1 }, .style = self.style }); 79 surf.writeCell(right_edge, row, .{ .char = .{ .grapheme = "", .width = 1 }, .style = self.style }); 80 } 81 82 // Add border labels 83 for (self.labels) |label| { 84 const text_len: u16 = @intCast(ctx.stringWidth(label.text)); 85 if (text_len == 0) continue; 86 87 const text_row: u16 = switch (label.alignment) { 88 .top_left, .top_center, .top_right => 0, 89 .bottom_left, .bottom_center, .bottom_right => bottom_edge, 90 }; 91 92 var text_col: u16 = switch (label.alignment) { 93 .top_left, .bottom_left => 1, 94 .top_center, .bottom_center => @max((size.width - text_len) / 2, 1), 95 .top_right, .bottom_right => @max(size.width - 1 - text_len, 1), 96 }; 97 98 var iter = ctx.graphemeIterator(label.text); 99 while (iter.next()) |grapheme| { 100 const text = grapheme.bytes(label.text); 101 const width: u16 = @intCast(ctx.stringWidth(text)); 102 surf.writeCell(text_col, text_row, .{ 103 .char = .{ .grapheme = text, .width = @intCast(width) }, 104 .style = self.style, 105 }); 106 text_col += width; 107 } 108 } 109 110 return surf; 111} 112 113test Border { 114 const Text = @import("Text.zig"); 115 // Will be height=1, width=3 116 const text: Text = .{ .text = "abc" }; 117 118 const border: Border = .{ .child = text.widget() }; 119 120 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 121 defer arena.deinit(); 122 vxfw.DrawContext.init(.unicode); 123 124 // Border will draw itself tightly around the child 125 const ctx: vxfw.DrawContext = .{ 126 .arena = arena.allocator(), 127 .min = .{}, 128 .max = .{ .width = 10, .height = 10 }, 129 .cell_size = .{ .width = 10, .height = 20 }, 130 }; 131 132 const surface = try border.draw(ctx); 133 // Border should be the size of Text + 2 134 try std.testing.expectEqual(5, surface.size.width); 135 try std.testing.expectEqual(3, surface.size.height); 136 // Border has 1 child 137 try std.testing.expectEqual(1, surface.children.len); 138 const child = surface.children[0]; 139 // The child is 1x3 140 try std.testing.expectEqual(3, child.surface.size.width); 141 try std.testing.expectEqual(1, child.surface.size.height); 142} 143 144test "refAllDecls" { 145 std.testing.refAllDecls(@This()); 146}