feat(scrollable): make Container scrollable through Element Scrollable
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 1m35s
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 1m35s
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
//! Interface for Element's which describe the contents of a `Container`.
|
||||
const std = @import("std");
|
||||
const s = @import("size.zig");
|
||||
const input = @import("input.zig");
|
||||
|
||||
const Container = @import("container.zig").Container;
|
||||
const Cell = @import("cell.zig");
|
||||
const Mouse = input.Mouse;
|
||||
const Position = s.Position;
|
||||
const Size = s.Size;
|
||||
|
||||
@@ -82,9 +84,12 @@ pub fn Scrollable(Event: type) type {
|
||||
/// `Size` of the actual contents where the anchor and the size is
|
||||
/// representing the size and location on screen.
|
||||
size: Size = .{},
|
||||
/// Anchor
|
||||
/// `Size` of the `Container` content that is scrollable and mapped to
|
||||
/// the *size* of the `Scrollable` `Element`.
|
||||
container_size: Size = .{},
|
||||
/// Anchor of the viewport of the scrollable `Container`.
|
||||
anchor: Position = .{},
|
||||
/// The actual container, that is *scrollable*
|
||||
/// The actual container, that is scrollable.
|
||||
container: Container(Event),
|
||||
/// Enable horizontal scrolling. This also renders a scrollbar (along the bottom of the viewport).
|
||||
horizontal: bool = false,
|
||||
@@ -104,24 +109,42 @@ pub fn Scrollable(Event: type) type {
|
||||
fn handle(ctx: *anyopaque, event: Event) !void {
|
||||
const this: *@This() = @ptrCast(@alignCast(ctx));
|
||||
switch (event) {
|
||||
.init => try this.container.handle(event),
|
||||
// TODO: emit `.resize` event for the container to set the size for the scrollable `Container`
|
||||
// - how would I determine the required or necessary `Size`?
|
||||
.resize => |size| {
|
||||
this.size = size;
|
||||
// TODO: not just pass through the given size, but rather the size that is necessary for scrollable content
|
||||
try this.container.handle(.{ .resize = size });
|
||||
const min_size = this.container.minSize();
|
||||
this.container_size = .{
|
||||
.anchor = size.anchor,
|
||||
.cols = @max(min_size.cols, size.cols),
|
||||
.rows = @max(min_size.rows, size.rows),
|
||||
};
|
||||
try this.container.handle(.{ .resize = this.container_size });
|
||||
},
|
||||
.mouse => |mouse| {
|
||||
std.log.debug("mouse event detected in scrollable element {any}", .{mouse.in(this.size)});
|
||||
try this.container.handle(.{
|
||||
.mouse => |mouse| switch (mouse.button) {
|
||||
Mouse.Button.wheel_up => if (this.vertical) {
|
||||
this.anchor.row -|= 1;
|
||||
},
|
||||
Mouse.Button.wheel_down => if (this.vertical) {
|
||||
const max_anchor_row = this.container_size.rows -| this.size.rows;
|
||||
this.anchor.row = @min(this.anchor.row + 1, max_anchor_row);
|
||||
},
|
||||
Mouse.Button.wheel_left => if (this.horizontal) {
|
||||
this.anchor.col -|= 1;
|
||||
},
|
||||
Mouse.Button.wheel_right => if (this.horizontal) {
|
||||
const max_anchor_col = this.container_size.cols -| this.size.cols;
|
||||
this.anchor.col = @min(this.anchor.col + 1, max_anchor_col);
|
||||
},
|
||||
else => try this.container.handle(.{
|
||||
.mouse = .{
|
||||
.col = mouse.col + this.anchor.col,
|
||||
.row = mouse.row + this.anchor.row,
|
||||
.button = mouse.button,
|
||||
.kind = mouse.kind,
|
||||
},
|
||||
});
|
||||
}),
|
||||
},
|
||||
else => try this.container.handle(event),
|
||||
}
|
||||
@@ -131,39 +154,41 @@ pub fn Scrollable(Event: type) type {
|
||||
const this: *@This() = @ptrCast(@alignCast(ctx));
|
||||
std.debug.assert(cells.len == @as(usize, this.size.cols) * @as(usize, this.size.rows));
|
||||
|
||||
const container_cells = try this.container.allocator.alloc(Cell, @as(usize, size.cols) * @as(usize, size.rows));
|
||||
@memset(cells, .{});
|
||||
const container_size = this.container.size;
|
||||
const container_cells = try this.container.allocator.alloc(Cell, @as(usize, container_size.cols) * @as(usize, container_size.rows));
|
||||
{
|
||||
const container_cells_const = try this.container.contents();
|
||||
defer this.container.allocator.free(container_cells_const);
|
||||
const container_size = this.container.size;
|
||||
std.debug.assert(container_cells_const.len == @as(usize, container_size.cols) * @as(usize, container_size.rows));
|
||||
@memcpy(container_cells, container_cells_const);
|
||||
}
|
||||
|
||||
// TODO: render correct view port into the container_cells
|
||||
for (this.container.elements.items) |*e| {
|
||||
const e_size = e.size;
|
||||
const element_cells = try e.contents();
|
||||
defer e.allocator.free(element_cells);
|
||||
|
||||
const anchor = (@as(usize, e_size.anchor.row -| size.anchor.row) * @as(usize, size.cols)) + @as(usize, e_size.anchor.col -| size.anchor.col);
|
||||
const anchor = (@as(usize, e_size.anchor.row -| container_size.anchor.row) * @as(usize, container_size.cols)) + @as(usize, e_size.anchor.col -| container_size.anchor.col);
|
||||
var idx: usize = 0;
|
||||
blk: for (0..e_size.rows) |row| {
|
||||
for (0..e_size.cols) |col| {
|
||||
blk: for (0..container_size.rows) |row| {
|
||||
for (0..container_size.cols) |col| {
|
||||
const cell = element_cells[idx];
|
||||
idx += 1;
|
||||
|
||||
container_cells[anchor + (row * size.cols) + col].style = cell.style;
|
||||
container_cells[anchor + (row * size.cols) + col].cp = cell.cp;
|
||||
container_cells[anchor + (row * container_size.cols) + col].style = cell.style;
|
||||
container_cells[anchor + (row * container_size.cols) + col].cp = cell.cp;
|
||||
|
||||
if (element_cells.len == idx) break :blk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const anchor = (@as(usize, this.anchor.row) * @as(usize, size.cols)) + @as(usize, this.anchor.col);
|
||||
for (container_cells, 0..) |cell, idx| {
|
||||
cells[anchor + idx] = cell;
|
||||
const anchor = (@as(usize, this.anchor.row) * @as(usize, container_size.cols)) + @as(usize, this.anchor.col);
|
||||
for (0..size.rows) |row| {
|
||||
for (0..size.cols) |col| {
|
||||
cells[(row * size.cols) + col] = container_cells[anchor + (row * container_size.cols) + col];
|
||||
}
|
||||
}
|
||||
this.container.allocator.free(container_cells);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user