diff --git a/examples/demo.zig b/examples/demo.zig index 5e82f57..6c78795 100644 --- a/examples/demo.zig +++ b/examples/demo.zig @@ -108,10 +108,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| { if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(); @@ -140,6 +138,16 @@ pub fn main() !void { .msg = "Container Event handling failed", }, }); + + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/examples/elements/button.zig b/examples/elements/button.zig index e78b37e..b40f5b2 100644 --- a/examples/elements/button.zig +++ b/examples/elements/button.zig @@ -118,10 +118,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(), .click => |button| { log.info("Clicked with mouse using Button: {s}", .{button}); @@ -137,6 +135,15 @@ pub fn main() !void { }, }); + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/examples/elements/input.zig b/examples/elements/input.zig index 7c19eaa..a5b0db0 100644 --- a/examples/elements/input.zig +++ b/examples/elements/input.zig @@ -131,10 +131,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(), .accept => |input| { defer allocator.free(input); @@ -151,6 +149,15 @@ pub fn main() !void { }, }); + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/examples/elements/scrollable.zig b/examples/elements/scrollable.zig index 76f0515..c5c2a44 100644 --- a/examples/elements/scrollable.zig +++ b/examples/elements/scrollable.zig @@ -157,10 +157,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(), .err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }), else => {}, @@ -172,6 +170,16 @@ pub fn main() !void { .msg = "Container Event handling failed", }, }); + + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/examples/errors.zig b/examples/errors.zig index b7e9345..15b2ec1 100644 --- a/examples/errors.zig +++ b/examples/errors.zig @@ -70,7 +70,6 @@ const ErrorNotification = struct { const this: *@This() = @ptrCast(@alignCast(ctx)); switch (event) { .key => |key| if (!key.isAscii()) return error.UnsupportedKey, - .size => |_| {}, .err => |err| this.msg = err.msg, else => {}, } @@ -134,10 +133,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(), .err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }), else => {}, @@ -149,6 +146,16 @@ pub fn main() !void { .msg = "Container Event handling failed", }, }); + + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/examples/layouts/grid.zig b/examples/layouts/grid.zig index bff53e4..583bf34f 100644 --- a/examples/layouts/grid.zig +++ b/examples/layouts/grid.zig @@ -85,10 +85,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(), // NOTE errors could be displayed in another container in case one was received, etc. to provide the user with feedback .err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }), @@ -102,6 +100,16 @@ pub fn main() !void { .msg = "Container Event handling failed", }, }); + + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/examples/layouts/horizontal.zig b/examples/layouts/horizontal.zig index 2c1bf88..e27f852 100644 --- a/examples/layouts/horizontal.zig +++ b/examples/layouts/horizontal.zig @@ -77,10 +77,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(), // NOTE errors could be displayed in another container in case one was received, etc. to provide the user with feedback .err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }), @@ -94,6 +92,16 @@ pub fn main() !void { .msg = "Container Event handling failed", }, }); + + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/examples/layouts/mixed.zig b/examples/layouts/mixed.zig index 3ead435..bc71ae1 100644 --- a/examples/layouts/mixed.zig +++ b/examples/layouts/mixed.zig @@ -89,10 +89,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(), // NOTE errors could be displayed in another container in case one was received, etc. to provide the user with feedback .err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }), @@ -106,6 +104,16 @@ pub fn main() !void { .msg = "Container Event handling failed", }, }); + + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/examples/layouts/vertical.zig b/examples/layouts/vertical.zig index feb2aff..9ceee31 100644 --- a/examples/layouts/vertical.zig +++ b/examples/layouts/vertical.zig @@ -76,10 +76,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(), // NOTE errors could be displayed in another container in case one was received, etc. to provide the user with feedback .err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }), @@ -93,6 +91,16 @@ pub fn main() !void { .msg = "Container Event handling failed", }, }); + + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/examples/styles/palette.zig b/examples/styles/palette.zig index 39b50ba..686ccb7 100644 --- a/examples/styles/palette.zig +++ b/examples/styles/palette.zig @@ -74,10 +74,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(), .err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }), else => {}, @@ -89,6 +87,16 @@ pub fn main() !void { .msg = "Container Event handling failed", }, }); + + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/examples/styles/text.zig b/examples/styles/text.zig index 2c516d1..02a0af3 100644 --- a/examples/styles/text.zig +++ b/examples/styles/text.zig @@ -127,10 +127,8 @@ pub fn main() !void { const event = app.nextEvent(); log.debug("received event: {s}", .{@tagName(event)}); + // pre event handling switch (event) { - .init => continue, - .quit => break, - .size => |size| try renderer.resize(size), .key => |key| if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(), .err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }), else => {}, @@ -142,6 +140,16 @@ pub fn main() !void { .msg = "Container Event handling failed", }, }); + + // post event handling + switch (event) { + .quit => break, + else => {}, + } + + try renderer.resize(); + container.reposition(.{}); + container.resize(renderer.size); try renderer.render(@TypeOf(container), &container); try renderer.flush(); } diff --git a/src/app.zig b/src/app.zig index 5776f82..ad7c648 100644 --- a/src/app.zig +++ b/src/app.zig @@ -97,9 +97,6 @@ pub fn App(comptime E: type) type { try terminal.enterAltScreen(); try terminal.hideCursor(); try terminal.enableMouseSupport(); - - // send initial size afterwards - this.postEvent(.{ .size = terminal.getTerminalSize() }); } pub fn interrupt(this: *@This()) !void { @@ -144,7 +141,8 @@ pub fn App(comptime E: type) type { fn winsizeCallback(ptr: *anyopaque) void { const this: *@This() = @ptrCast(@alignCast(ptr)); - this.postEvent(.{ .size = terminal.getTerminalSize() }); + _ = this; + // this.postEvent(.{ .size = terminal.getTerminalSize() }); } var winch_handler: ?SignalHandler = null; @@ -329,10 +327,12 @@ pub fn App(comptime E: type) type { const width_char = iter.next() orelse break; const height_char = iter.next() orelse break; - this.postEvent(.{ .size = .{ - .x = std.fmt.parseUnsigned(u16, width_char, 10) catch break, - .y = std.fmt.parseUnsigned(u16, height_char, 10) catch break, - } }); + _ = width_char; + _ = height_char; + // this.postEvent(.{ .size = .{ + // .x = std.fmt.parseUnsigned(u16, width_char, 10) catch break, + // .y = std.fmt.parseUnsigned(u16, height_char, 10) catch break, + // } }); } }, 'u' => { diff --git a/src/container.zig b/src/container.zig index ba6b81b..4695eaa 100644 --- a/src/container.zig +++ b/src/container.zig @@ -601,173 +601,174 @@ pub fn Container(comptime Event: type) type { try this.elements.append(element); } - pub fn position(this: *@This(), pos: Point) !void { - log.debug("pos: .{{ .x = {d}, .y = {d} }}", .{ pos.x, pos.y }); - this.origin = pos; + pub fn reposition(this: *@This(), origin: Point) void { + log.debug("origin: .{{ .x = {d}, .y = {d} }}", .{ origin.x, origin.y }); + this.origin = origin; + this.element.reposition(origin); + } + + pub fn resize(this: *@This(), size: Point) void { + log.debug("Event .size: {{ .x = {d}, .y = {d} }}", .{ size.x, size.y }); + this.size = size; + if (this.properties.fixed_size.x > 0 and size.x < this.properties.fixed_size.x) return; + if (this.properties.fixed_size.y > 0 and size.y < this.properties.fixed_size.y) return; + + this.element.resize(size); + + if (this.elements.items.len == 0) return; + + const layout = this.properties.layout; + var fixed_size_elements: u16 = 0; + var fixed_size: Point = .{}; + for (this.elements.items) |element| { + switch (layout.direction) { + .horizontal => if (element.properties.fixed_size.x > 0) { + fixed_size_elements += 1; + }, + .vertical => if (element.properties.fixed_size.y > 0) { + fixed_size_elements += 1; + }, + } + fixed_size = fixed_size.add(element.properties.fixed_size); + } + // check if the available screen is large enough + switch (layout.direction) { + .horizontal => if (fixed_size.x > size.x) return, + .vertical => if (fixed_size.y > size.y) return, + } + const sides = this.properties.border.sides; + const padding = layout.padding; + var gap = layout.gap; + if (layout.separator.enabled) gap += 1; + + const len: u16 = @truncate(this.elements.items.len); + const element_x = blk: { + var x = size.x - fixed_size.x - gap * (len - 1); + if (sides.left) x -= 1; + if (sides.right) x -= 1; + x -= padding.left + padding.right; + if (fixed_size_elements == len) break :blk 0; + if (fixed_size_elements == 0) { + break :blk @divTrunc(x, len); + } else { + break :blk @divTrunc(x, len - fixed_size_elements); + } + }; + const element_y = blk: { + var y = size.y - fixed_size.y - gap * (len - 1); + if (sides.top) y -= 1; + if (sides.bottom) y -= 1; + y -= padding.top + padding.bottom; + if (fixed_size_elements == len) break :blk 0; + if (fixed_size_elements == 0) { + break :blk @divTrunc(y, len); + } else { + break :blk @divTrunc(y, len - fixed_size_elements); + } + }; + var offset: u16 = switch (layout.direction) { + .horizontal => padding.left, + .vertical => padding.top, + }; + var overflow = switch (layout.direction) { + .horizontal => blk: { + var x = size.x - fixed_size.x - gap * (len - 1); + if (sides.left) x -= 1; + if (sides.right) x -= 1; + x -= padding.left + padding.right; + if (fixed_size_elements == len) break :blk 0; + if (fixed_size_elements == 0) { + break :blk x - element_x * len; + } else { + break :blk x - element_x * (len - fixed_size_elements); + } + }, + .vertical => blk: { + var y = size.y - fixed_size.y - gap * (len - 1); + if (sides.top) y -= 1; + if (sides.bottom) y -= 1; + y -= padding.top + padding.bottom; + if (fixed_size_elements == len) break :blk 0; + if (fixed_size_elements == 0) { + break :blk y - element_y * len; + } else { + break :blk y - element_y * (len - fixed_size_elements); + } + }, + }; + + for (this.elements.items) |*element| { + var element_size: Point = undefined; + var element_origin: Point = undefined; + switch (layout.direction) { + .horizontal => { + // TODO this should not always be the max size property! + var x = blk: { + if (element.properties.fixed_size.x > 0) break :blk element.properties.fixed_size.x; + break :blk element_x; + }; + if (overflow > 0) { + overflow -|= 1; + x += 1; + } + element_origin = .{ + .x = this.origin.x + offset, + .y = this.origin.y, + }; + element_size = .{ + .x = x, + .y = size.y, + }; + // border + if (sides.top) element_size.y -= 1; + if (sides.bottom) element_size.y -= 1; + // padding + element_origin.y += padding.top; + element_size.y -= padding.top + padding.bottom; + // gap + offset += gap; + offset += x; + }, + .vertical => { + var y = blk: { + if (element.properties.fixed_size.y > 0) break :blk element.properties.fixed_size.y; + break :blk element_y; + }; + if (overflow > 0) { + overflow -|= 1; + y += 1; + } + element_origin = .{ + .x = this.origin.x, + .y = this.origin.y + offset, + }; + element_size = .{ + .x = size.x, + .y = y, + }; + // border + if (sides.left) element_size.x -= 1; + if (sides.right) element_size.x -= 1; + // padding + element_origin.x += padding.left; + element_size.x -= padding.left + padding.right; + // gap + offset += gap; + offset += y; + }, + } + + // border resizing + if (sides.top) element_origin.y += 1; + if (sides.left) element_origin.x += 1; + + element.reposition(element_origin); + element.resize(element_size); + } } pub fn handle(this: *@This(), event: Event) !void { switch (event) { - .size => |size| resize: { - log.debug("Event .size: {{ .x = {d}, .y = {d} }}", .{ size.x, size.y }); - this.size = size; - if (this.properties.fixed_size.x > 0 and size.x < this.properties.fixed_size.x) return Error.TooSmall; - if (this.properties.fixed_size.y > 0 and size.y < this.properties.fixed_size.y) return Error.TooSmall; - - try this.element.handle(event); - - if (this.elements.items.len == 0) break :resize; - - const layout = this.properties.layout; - var fixed_size_elements: u16 = 0; - var fixed_size: Point = .{}; - for (this.elements.items) |element| { - switch (layout.direction) { - .horizontal => if (element.properties.fixed_size.x > 0) { - fixed_size_elements += 1; - }, - .vertical => if (element.properties.fixed_size.y > 0) { - fixed_size_elements += 1; - }, - } - fixed_size = fixed_size.add(element.properties.fixed_size); - } - // check if the available screen is large enough - switch (layout.direction) { - .horizontal => if (fixed_size.x > size.x) return Error.TooSmall, - .vertical => if (fixed_size.y > size.y) return Error.TooSmall, - } - const sides = this.properties.border.sides; - const padding = layout.padding; - var gap = layout.gap; - if (layout.separator.enabled) gap += 1; - - const len: u16 = @truncate(this.elements.items.len); - const element_x = blk: { - var x = size.x - fixed_size.x - gap * (len - 1); - if (sides.left) x -= 1; - if (sides.right) x -= 1; - x -= padding.left + padding.right; - if (fixed_size_elements == len) break :blk 0; - if (fixed_size_elements == 0) { - break :blk @divTrunc(x, len); - } else { - break :blk @divTrunc(x, len - fixed_size_elements); - } - }; - const element_y = blk: { - var y = size.y - fixed_size.y - gap * (len - 1); - if (sides.top) y -= 1; - if (sides.bottom) y -= 1; - y -= padding.top + padding.bottom; - if (fixed_size_elements == len) break :blk 0; - if (fixed_size_elements == 0) { - break :blk @divTrunc(y, len); - } else { - break :blk @divTrunc(y, len - fixed_size_elements); - } - }; - var offset: u16 = switch (layout.direction) { - .horizontal => padding.left, - .vertical => padding.top, - }; - var overflow = switch (layout.direction) { - .horizontal => blk: { - var x = size.x - fixed_size.x - gap * (len - 1); - if (sides.left) x -= 1; - if (sides.right) x -= 1; - x -= padding.left + padding.right; - if (fixed_size_elements == len) break :blk 0; - if (fixed_size_elements == 0) { - break :blk x - element_x * len; - } else { - break :blk x - element_x * (len - fixed_size_elements); - } - }, - .vertical => blk: { - var y = size.y - fixed_size.y - gap * (len - 1); - if (sides.top) y -= 1; - if (sides.bottom) y -= 1; - y -= padding.top + padding.bottom; - if (fixed_size_elements == len) break :blk 0; - if (fixed_size_elements == 0) { - break :blk y - element_y * len; - } else { - break :blk y - element_y * (len - fixed_size_elements); - } - }, - }; - - for (this.elements.items) |*element| { - var element_size: Point = undefined; - var element_origin: Point = undefined; - switch (layout.direction) { - .horizontal => { - // TODO this should not always be the max size property! - var x = blk: { - if (element.properties.fixed_size.x > 0) break :blk element.properties.fixed_size.x; - break :blk element_x; - }; - if (overflow > 0) { - overflow -|= 1; - x += 1; - } - element_origin = .{ - .x = this.origin.x + offset, - .y = this.origin.y, - }; - element_size = .{ - .x = x, - .y = size.y, - }; - // border - if (sides.top) element_size.y -= 1; - if (sides.bottom) element_size.y -= 1; - // padding - element_origin.y += padding.top; - element_size.y -= padding.top + padding.bottom; - // gap - offset += gap; - offset += x; - }, - .vertical => { - var y = blk: { - if (element.properties.fixed_size.y > 0) break :blk element.properties.fixed_size.y; - break :blk element_y; - }; - if (overflow > 0) { - overflow -|= 1; - y += 1; - } - element_origin = .{ - .x = this.origin.x, - .y = this.origin.y + offset, - }; - element_size = .{ - .x = size.x, - .y = y, - }; - // border - if (sides.left) element_size.x -= 1; - if (sides.right) element_size.x -= 1; - // padding - element_origin.x += padding.left; - element_size.x -= padding.left + padding.right; - // gap - offset += gap; - offset += y; - }, - } - - // border resizing - if (sides.top) element_origin.y += 1; - if (sides.left) element_origin.x += 1; - - // TODO tell the element its origin - try element.position(element_origin); - try element.handle(.{ .size = element_size }); - } - }, .mouse => |mouse| if (mouse.in(this.origin, this.size)) { try this.element.handle(event); for (this.elements.items) |*element| try element.handle(event); diff --git a/src/element.zig b/src/element.zig index 48b872e..6d7f435 100644 --- a/src/element.zig +++ b/src/element.zig @@ -13,10 +13,24 @@ pub fn Element(Event: type) type { vtable: *const VTable = &.{}, pub const VTable = struct { + resize: ?*const fn (ctx: *anyopaque, size: Point) void = null, + reposition: ?*const fn (ctx: *anyopaque, origin: Point) void = null, handle: ?*const fn (ctx: *anyopaque, event: Event) anyerror!void = null, content: ?*const fn (ctx: *anyopaque, cells: []Cell, origin: Point, size: Point) anyerror!void = null, }; + /// Resize the corresponding `Element` with the given *size*. + pub fn resize(this: @This(), size: Point) void { + if (this.vtable.resize) |resize_fn| + resize_fn(this.ptr, size); + } + + /// Reposition the corresponding `Element` with the given *origin*. + pub fn reposition(this: @This(), origin: Point) void { + if (this.vtable.reposition) |reposition_fn| + reposition_fn(this.ptr, origin); + } + /// Handle the received event. The event is one of the user provided /// events or a system event, with the exception of the `.size` /// `Event` as every `Container` already handles that event. @@ -73,6 +87,8 @@ pub fn Scrollable(Event: type) type { return .{ .ptr = this, .vtable = &.{ + .resize = resize, + .reposition = reposition, .handle = handle, .content = content, }, @@ -86,16 +102,23 @@ pub fn Scrollable(Event: type) type { }; } + fn resize(ctx: *anyopaque, size: Point) void { + const this: *@This() = @ptrCast(@alignCast(ctx)); + this.size = size; + // TODO scrollbar space - depending on configuration and only if necessary? + this.container_size = Point.max(size, this.min_size); + this.container_origin = size; // TODO the size should be a provided origin + this.container.resize(this.container_size); + } + + fn reposition(ctx: *anyopaque, origin: Point) void { + const this: *@This() = @ptrCast(@alignCast(ctx)); + this.container_origin = origin; // TODO the size should be a provided origin + } + fn handle(ctx: *anyopaque, event: Event) !void { const this: *@This() = @ptrCast(@alignCast(ctx)); switch (event) { - .size => |size| { - this.size = size; - // TODO scrollbar space - depending on configuration and only if necessary? - this.container_size = size.max(this.min_size); - this.container_origin = size; // TODO the size should be a provided origin - try this.container.handle(.{ .size = this.container_size }); - }, // TODO other means to scroll except with the mouse? (i.e. Ctrl-u/d, k/j, etc.?) .mouse => |mouse| switch (mouse.button) { Mouse.Button.wheel_up => if (this.container_size.y > this.size.y) { @@ -224,7 +247,7 @@ test "scrollable vertical" { var renderer: testing.Renderer = .init(allocator, size); defer renderer.deinit(); - try container.handle(.{ .size = size }); + container.resize(size); try renderer.render(Container(event.SystemEvent), &container); try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.vertical.top.zon"), renderer.screen); @@ -298,7 +321,7 @@ test "scrollable horizontal" { var renderer: testing.Renderer = .init(allocator, size); defer renderer.deinit(); - try container.handle(.{ .size = size }); + container.resize(size); try renderer.render(Container(event.SystemEvent), &container); try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.horizontal.left.zon"), renderer.screen); diff --git a/src/event.zig b/src/event.zig index 285ef7a..9ace94a 100644 --- a/src/event.zig +++ b/src/event.zig @@ -21,8 +21,6 @@ pub const SystemEvent = union(enum) { /// associated error message msg: []const u8, }, - /// Size event emitted by the terminal to derive the `Size` of the current terminal the application is rendered in - size: Point, /// Input key event received from the user key: Key, /// Mouse input event diff --git a/src/point.zig b/src/point.zig index add1369..5374192 100644 --- a/src/point.zig +++ b/src/point.zig @@ -2,17 +2,17 @@ pub const Point = packed struct { x: u16 = 0, y: u16 = 0, - pub fn add(this: @This(), other: @This()) @This() { + pub fn add(a: @This(), b: @This()) @This() { return .{ - .x = this.x + other.x, - .y = this.y + other.y, + .x = a.x + b.x, + .y = a.y + b.y, }; } - pub fn max(this: @This(), other: @This()) @This() { + pub fn max(a: @This(), b: @This()) @This() { return .{ - .x = @max(this.x, other.x), - .y = @max(this.y, other.y), + .x = @max(a.x, b.x), + .y = @max(a.y, b.y), }; } diff --git a/src/render.zig b/src/render.zig index 2524b44..6c60b34 100644 --- a/src/render.zig +++ b/src/render.zig @@ -29,9 +29,12 @@ pub const Buffered = struct { } } - pub fn resize(this: *@This(), size: Point) !void { + pub fn resize(this: *@This()) !void { + const size = terminal.getTerminalSize(); + if (std.meta.eql(this.size, size)) return; + this.size = size; - const n = @as(usize, size.x) * @as(usize, size.y); + const n = @as(usize, this.size.x) * @as(usize, this.size.y); if (!this.created) { this.screen = this.allocator.alloc(Cell, n) catch @panic("render.zig: Out of memory.");