this repo has no description
13
fork

Configure Feed

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

at 01605eebf65be21caa85ee9d840047f864553308 162 lines 4.9 kB view raw
1//! A View is effectively an "oversized" Window that can be written to and rendered in pieces. 2 3const std = @import("std"); 4const mem = std.mem; 5 6const View = @This(); 7 8const gw = @import("../gwidth.zig"); 9 10const Screen = @import("../Screen.zig"); 11const Window = @import("../Window.zig"); 12const Unicode = @import("../Unicode.zig"); 13const Cell = @import("../Cell.zig"); 14 15/// View Allocator 16alloc: mem.Allocator, 17 18/// Underlying Screen 19screen: Screen, 20 21/// View Initialization Config 22pub const Config = struct { 23 width: u16, 24 height: u16, 25}; 26 27/// Initialize a new View 28pub fn init(alloc: mem.Allocator, unicode: *const Unicode, config: Config) mem.Allocator.Error!View { 29 const screen = try Screen.init( 30 alloc, 31 .{ 32 .cols = config.width, 33 .rows = config.height, 34 .x_pixel = 0, 35 .y_pixel = 0, 36 }, 37 unicode, 38 ); 39 return .{ 40 .alloc = alloc, 41 .screen = screen, 42 }; 43} 44 45pub fn window(self: *View) Window { 46 return .{ 47 .x_off = 0, 48 .y_off = 0, 49 .parent_x_off = 0, 50 .parent_y_off = 0, 51 .width = self.screen.width, 52 .height = self.screen.height, 53 .screen = &self.screen, 54 }; 55} 56 57/// Deinitialize this View 58pub fn deinit(self: *View) void { 59 self.screen.deinit(self.alloc); 60} 61 62pub const DrawOptions = struct { 63 x_off: u16 = 0, 64 y_off: u16 = 0, 65}; 66 67pub fn draw(self: *View, win: Window, opts: DrawOptions) void { 68 if (opts.x_off >= self.screen.width) return; 69 if (opts.y_off >= self.screen.height) return; 70 71 const width = @min(win.width, self.screen.width - opts.x_off); 72 const height = @min(win.height, self.screen.height - opts.y_off); 73 74 for (0..height) |_row| { 75 const row: i17 = @intCast(_row); 76 const src_start: usize = @intCast(opts.x_off + ((row + opts.y_off) * self.screen.width)); 77 const src_end: usize = @intCast(src_start + width); 78 const dst_start: usize = @intCast(win.x_off + ((row + win.y_off) * win.screen.width)); 79 const dst_end: usize = @intCast(dst_start + width); 80 @memcpy(win.screen.buf[dst_start..dst_end], self.screen.buf[src_start..src_end]); 81 } 82} 83 84/// Render Config for `toWin()` 85pub const RenderConfig = struct { 86 x: u16 = 0, 87 y: u16 = 0, 88 width: Extent = .fit, 89 height: Extent = .fit, 90 91 pub const Extent = union(enum) { 92 fit, 93 max: u16, 94 }; 95}; 96 97/// Render a portion of this View to the provided Window (`win`). 98/// This will return the bounded X (col), Y (row) coordinates based on the rendering. 99pub fn toWin(self: *View, win: Window, config: RenderConfig) !struct { u16, u16 } { 100 var x = @min(self.screen.width - 1, config.x); 101 var y = @min(self.screen.height - 1, config.y); 102 const width = width: { 103 var width = switch (config.width) { 104 .fit => win.width, 105 .max => |w| @min(win.width, w), 106 }; 107 width = @min(width, self.screen.width); 108 break :width @min(width, self.screen.width -| 1 -| x +| win.width); 109 }; 110 const height = height: { 111 var height = switch (config.height) { 112 .fit => win.height, 113 .max => |h| @min(win.height, h), 114 }; 115 height = @min(height, self.screen.height); 116 break :height @min(height, self.screen.height -| 1 -| y +| win.height); 117 }; 118 x = @min(x, self.screen.width -| width); 119 y = @min(y, self.screen.height -| height); 120 const child = win.child(.{ 121 .width = width, 122 .height = height, 123 }); 124 self.draw(child, .{ .x_off = x, .y_off = y }); 125 return .{ x, y }; 126} 127 128/// Writes a cell to the location in the View 129pub fn writeCell(self: *View, col: u16, row: u16, cell: Cell) void { 130 self.screen.writeCell(col, row, cell); 131} 132 133/// Reads a cell at the location in the View 134pub fn readCell(self: *const View, col: u16, row: u16) ?Cell { 135 return self.screen.readCell(col, row); 136} 137 138/// Fills the View with the default cell 139pub fn clear(self: View) void { 140 self.fill(.{ .default = true }); 141} 142 143/// Returns the width of the grapheme. This depends on the terminal capabilities 144pub fn gwidth(self: View, str: []const u8) u16 { 145 return gw.gwidth(str, self.screen.width_method, &self.screen.unicode.width_data); 146} 147 148/// Fills the View with the provided cell 149pub fn fill(self: View, cell: Cell) void { 150 @memset(self.screen.buf, cell); 151} 152 153/// Prints segments to the View. Returns true if the text overflowed with the 154/// given wrap strategy and size. 155pub fn print(self: *View, segments: []const Cell.Segment, opts: Window.PrintOptions) Window.PrintResult { 156 return self.window().print(segments, opts); 157} 158 159/// Print a single segment. This is just a shortcut for print(&.{segment}, opts) 160pub fn printSegment(self: *View, segment: Cell.Segment, opts: Window.PrintOptions) Window.PrintResult { 161 return self.print(&.{segment}, opts); 162}