this repo has no description
13
fork

Configure Feed

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

view: add draw method, modify allocations

+57 -55
+1 -1
src/Screen.zig
··· 63 63 self.buf[i] = cell; 64 64 } 65 65 66 - pub fn readCell(self: *Screen, col: usize, row: usize) ?Cell { 66 + pub fn readCell(self: *const Screen, col: usize, row: usize) ?Cell { 67 67 if (self.width <= col) { 68 68 // column out of bounds 69 69 return null;
+56 -54
src/View.zig
··· 5 5 6 6 const View = @This(); 7 7 8 + const gw = @import("gwidth.zig"); 9 + 8 10 const Screen = @import("Screen.zig"); 9 11 const Window = @import("Window.zig"); 10 12 const Unicode = @import("Unicode.zig"); ··· 12 14 13 15 /// View Allocator 14 16 alloc: mem.Allocator, 17 + 15 18 /// Underlying Screen 16 - screen: *Screen, 17 - /// Underlying Window 18 - win: Window, 19 + screen: Screen, 19 20 20 21 /// View Initialization Config 21 22 pub const Config = struct { 22 23 width: usize, 23 24 height: usize, 24 25 }; 26 + 25 27 /// Initialize a new View 26 28 pub fn init(alloc: mem.Allocator, unicode: *const Unicode, config: Config) !View { 27 - const screen = try alloc.create(Screen); 28 - screen.* = try Screen.init( 29 + const screen = try Screen.init( 29 30 alloc, 30 31 .{ 31 32 .cols = config.width, ··· 38 39 return .{ 39 40 .alloc = alloc, 40 41 .screen = screen, 41 - .win = .{ 42 - .x_off = 0, 43 - .y_off = 0, 44 - .width = config.width, 45 - .height = config.height, 46 - .screen = screen, 47 - }, 42 + }; 43 + } 44 + 45 + pub fn window(self: *View) Window { 46 + return .{ 47 + .x_off = 0, 48 + .y_off = 0, 49 + .width = self.screen.width, 50 + .height = self.screen.height, 51 + .screen = &self.screen, 48 52 }; 49 53 } 50 54 51 55 /// Deinitialize this View 52 56 pub fn deinit(self: *View) void { 53 57 self.screen.deinit(self.alloc); 54 - self.alloc.destroy(self.screen); 58 + } 59 + 60 + pub const DrawOptions = struct { 61 + x_off: usize = 0, 62 + y_off: usize = 0, 63 + }; 64 + 65 + pub fn draw(self: *View, win: Window, opts: DrawOptions) void { 66 + if (opts.x_off >= self.screen.width) return; 67 + if (opts.y_off >= self.screen.height) return; 68 + 69 + const width = @min(win.width, self.screen.width - opts.x_off); 70 + const height = @min(win.height, self.screen.height - opts.y_off); 71 + 72 + for (0..height) |row| { 73 + const src_start = opts.x_off + ((row + opts.y_off) * self.screen.width); 74 + const src_end = src_start + width; 75 + const dst_start = win.x_off + ((row + win.y_off) * win.screen.width); 76 + const dst_end = dst_start + width; 77 + @memcpy(win.screen.buf[dst_start..dst_end], self.screen.buf[src_start..src_end]); 78 + } 55 79 } 56 80 57 - /// Render Config f/ `toWin()` 81 + /// Render Config for `toWin()` 58 82 pub const RenderConfig = struct { 59 83 x: usize = 0, 60 84 y: usize = 0, ··· 66 90 max: usize, 67 91 }; 68 92 }; 93 + 69 94 /// Render a portion of this View to the provided Window (`win`). 70 95 /// This will return the bounded X (col), Y (row) coordinates based on the rendering. 71 96 pub fn toWin(self: *View, win: Window, config: RenderConfig) !struct { usize, usize } { ··· 89 114 }; 90 115 x = @min(x, self.screen.width -| width); 91 116 y = @min(y, self.screen.height -| height); 92 - 93 - for (0..height) |row| { 94 - for (0..width) |col| { 95 - win.writeCell( 96 - col, 97 - row, 98 - self.win.readCell( 99 - @min(self.screen.width -| 1, x +| col), 100 - @min(self.screen.height -| 1, y +| row), 101 - ) orelse { 102 - std.log.err( 103 - \\ Position Out of Bounds: 104 - \\ - Pos: {d}, {d} 105 - \\ - Size: {d}, {d} 106 - , 107 - .{ 108 - col, row, 109 - self.screen.width, self.screen.height, 110 - }, 111 - ); 112 - return error.PositionOutOfBounds; 113 - }, 114 - ); 115 - } 116 - } 117 + const child = win.child(.{ 118 + .x_off = x, 119 + .y_off = y, 120 + .width = .{ .limit = width }, 121 + .height = .{ .limit = height }, 122 + }); 123 + self.draw(child, .{}); 117 124 return .{ x, y }; 118 125 } 119 126 120 127 /// Writes a cell to the location in the View 121 - pub fn writeCell(self: View, col: usize, row: usize, cell: Cell) void { 122 - self.win.writeCell(col, row, cell); 128 + pub fn writeCell(self: *View, col: usize, row: usize, cell: Cell) void { 129 + self.screen.writeCell(col, row, cell); 123 130 } 124 131 125 132 /// Reads a cell at the location in the View 126 - pub fn readCell(self: View, col: usize, row: usize) ?Cell { 127 - return self.win.readCell(col, row); 133 + pub fn readCell(self: *const View, col: usize, row: usize) ?Cell { 134 + return self.screen.readCell(col, row); 128 135 } 129 136 130 137 /// Fills the View with the default cell 131 138 pub fn clear(self: View) void { 132 - self.win.clear(); 139 + self.fill(.{ .default = true }); 133 140 } 134 141 135 142 /// Returns the width of the grapheme. This depends on the terminal capabilities 136 143 pub fn gwidth(self: View, str: []const u8) usize { 137 - return self.win.gwidth(str); 144 + return gw.gwidth(str, self.screen.width_method, &self.screen.unicode.width_data) catch 1; 138 145 } 139 146 140 147 /// Fills the View with the provided cell 141 148 pub fn fill(self: View, cell: Cell) void { 142 - self.win.fill(cell); 149 + @memset(self.screen.buf, cell); 143 150 } 144 151 145 152 /// Prints segments to the View. Returns true if the text overflowed with the 146 153 /// given wrap strategy and size. 147 - pub fn print(self: View, segments: []const Cell.Segment, opts: Window.PrintOptions) !Window.PrintResult { 148 - return self.win.print(segments, opts); 154 + pub fn print(self: *View, segments: []const Cell.Segment, opts: Window.PrintOptions) !Window.PrintResult { 155 + return self.window().print(segments, opts); 149 156 } 150 157 151 158 /// Print a single segment. This is just a shortcut for print(&.{segment}, opts) 152 - pub fn printSegment(self: View, segment: Cell.Segment, opts: Window.PrintOptions) !Window.PrintResult { 159 + pub fn printSegment(self: *View, segment: Cell.Segment, opts: Window.PrintOptions) !Window.PrintResult { 153 160 return self.print(&.{segment}, opts); 154 161 } 155 - 156 - /// Create a child window 157 - pub fn child(self: View, opts: Window.ChildOptions) Window { 158 - return self.win.child(opts); 159 - }