From 270ca9b1be87b0f8dac725868a434d54deee32f7 Mon Sep 17 00:00:00 2001 From: Yves Biener Date: Wed, 13 Nov 2024 15:07:26 +0100 Subject: [PATCH] mod(renderer): dynamic clear of size for widgets to improve render performance --- src/layout/Framing.zig | 9 +++++++-- src/render.zig | 15 +++++++++++---- src/widget/RawText.zig | 22 +++++++++++++++------- src/widget/Spacer.zig | 7 ++++++- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/layout/Framing.zig b/src/layout/Framing.zig index 72b4506..7fe64db 100644 --- a/src/layout/Framing.zig +++ b/src/layout/Framing.zig @@ -22,6 +22,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t const Events = std.ArrayList(Event); return struct { size: terminal.Size = undefined, + require_render: bool = true, element: Element = undefined, events: Events = undefined, config: Config = undefined, @@ -68,6 +69,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t switch (event) { .resize => |size| { this.size = size; + this.require_render = true; log.debug("Event .resize: {{ .anchor = {{ .col = {d}, .row = {d} }}, .cols = {d}, .rows = {d} }}", .{ size.anchor.col, size.anchor.row, @@ -167,8 +169,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t } pub fn render(this: *@This(), renderer: *Renderer) !void { - try renderer.clear(this.size); - try this.renderFrame(renderer); + if (this.require_render) { + try renderer.clear(this.size); + try this.renderFrame(renderer); + this.require_render = false; + } switch ((&this.element).*) { .layout => |*layout| { diff --git a/src/render.zig b/src/render.zig index de62c8d..0a7a91a 100644 --- a/src/render.zig +++ b/src/render.zig @@ -128,12 +128,19 @@ pub fn Direct(comptime _: bool) type { _ = this; _ = size; } + pub fn clear(this: *@This(), size: Size) !void { _ = this; - const anchor = size.anchor; - // NOTE: clear entire screen for the first content (derived from the anchor being at the very left-top) - if (anchor.col == 1 and anchor.row == 1) { - try terminal.clearScreen(); + std.debug.assert(1028 > size.cols); + var buf: [1028]u8 = undefined; + @memset(buf[0..], ' '); + for (0..size.rows) |r| { + const row: u16 = @truncate(r); + try terminal.setCursorPosition(.{ + .col = size.anchor.col, + .row = size.anchor.row + row, + }); + _ = try terminal.write(buf[0..size.cols]); } } diff --git a/src/widget/RawText.zig b/src/widget/RawText.zig index 1324729..cf9cf29 100644 --- a/src/widget/RawText.zig +++ b/src/widget/RawText.zig @@ -18,6 +18,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type { line_index: std.ArrayList(usize) = undefined, line: usize = 0, size: terminal.Size = undefined, + require_render: bool = false, pub fn init(allocator: std.mem.Allocator, file: std.fs.File) @This() { var contents = Contents.init(allocator); @@ -42,6 +43,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type { } pub fn handle(this: *@This(), event: Event) ?Event { + var require_render = true; switch (event) { // store the received size .resize => |size| { @@ -54,28 +56,33 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type { if (key.matches(.{ .cp = 'g' })) { // top this.line = 0; - } - if (key.matches(.{ .cp = 'G' })) { + } else if (key.matches(.{ .cp = 'G' })) { // bottom this.line = this.line_index.items.len -| 1 -| this.size.rows; - } - if (key.matches(.{ .cp = 'j' })) { + } else if (key.matches(.{ .cp = 'j' })) { // down if (this.line < this.line_index.items.len -| 1 -| this.size.rows) { this.line +|= 1; } - } - if (key.matches(.{ .cp = 'k' })) { + } else if (key.matches(.{ .cp = 'k' })) { // up this.line -|= 1; + } else { + require_render = false; } }, - else => {}, + else => { + require_render = false; + }, } + this.require_render = require_render; return null; } pub fn render(this: *@This(), renderer: *Renderer) !void { + if (!this.require_render) { + return; + } try renderer.clear(this.size); if (this.size.rows >= this.line_index.items.len) { try renderer.render(this.size, &[_]terminal.Cell{ @@ -96,6 +103,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type { .{ .content = this.contents.items[i..x], .style = .{ .dim = true, .fg = .{ .index = 9 } } }, }); } + this.require_render = false; } }; } diff --git a/src/widget/Spacer.zig b/src/widget/Spacer.zig index 633c960..3c608ae 100644 --- a/src/widget/Spacer.zig +++ b/src/widget/Spacer.zig @@ -12,6 +12,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type { } return struct { size: terminal.Size = undefined, + size_changed: bool = false, pub fn init() @This() { return .{}; @@ -25,6 +26,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type { switch (event) { .resize => |size| { this.size = size; + this.size_changed = true; }, else => {}, } @@ -32,7 +34,10 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type { } pub fn render(this: *@This(), renderer: *Renderer) !void { - try renderer.clear(this.size); + if (this.size_changed) { + try renderer.clear(this.size); + this.size_changed = false; + } } }; }