feat(container): introduce fixed_size property for fixed sizing of Containers
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 42s
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 42s
Moved min_size property from `Container` to the `Scrollable` element, where it is only used anyway.
This commit is contained in:
@@ -51,11 +51,14 @@ pub fn main() !void {
|
||||
// - some sort of chat? -> write messages and have them displayed in a scrollable array at the right hand side?
|
||||
// - on the left some buttons?
|
||||
var box = try App.Container.init(allocator, .{
|
||||
.border = .{
|
||||
.color = .blue,
|
||||
.sides = .all,
|
||||
},
|
||||
.layout = .{
|
||||
.gap = 1,
|
||||
.padding = .vertical(2),
|
||||
},
|
||||
.min_size = .{ .cols = 50 },
|
||||
}, .{});
|
||||
try box.append(try App.Container.init(allocator, .{
|
||||
.rectangle = .{ .fill = .light_green },
|
||||
@@ -70,6 +73,7 @@ pub fn main() !void {
|
||||
|
||||
var scrollable: App.Scrollable = .{
|
||||
.container = box,
|
||||
.min_size = .{ .cols = 60 },
|
||||
};
|
||||
|
||||
var container = try App.Container.init(allocator, .{
|
||||
@@ -87,9 +91,11 @@ pub fn main() !void {
|
||||
.color = .light_blue,
|
||||
.sides = .all,
|
||||
},
|
||||
.fixed_size = .{ .cols = 200 },
|
||||
}, .{}));
|
||||
try container.append(try App.Container.init(allocator, .{
|
||||
.rectangle = .{ .fill = .blue },
|
||||
.fixed_size = .{ .cols = 30 },
|
||||
}, .{}));
|
||||
defer container.deinit(); // also de-initializes the children
|
||||
|
||||
|
||||
@@ -562,7 +562,7 @@ pub fn Container(comptime Event: type) type {
|
||||
border: Border = .{},
|
||||
rectangle: Rectangle = .{},
|
||||
layout: Layout = .{},
|
||||
min_size: Size = .{},
|
||||
fixed_size: Size = .{},
|
||||
};
|
||||
|
||||
pub fn init(
|
||||
@@ -590,24 +590,6 @@ pub fn Container(comptime Event: type) type {
|
||||
try this.elements.append(element);
|
||||
}
|
||||
|
||||
pub fn minSize(this: @This()) Size {
|
||||
var size: Size = .{};
|
||||
const len: u16 = @truncate(this.elements.items.len);
|
||||
if (len > 0) {
|
||||
for (this.elements.items) |element| {
|
||||
size = size.add(element.minSize());
|
||||
}
|
||||
var gap = this.properties.layout.gap;
|
||||
if (this.properties.layout.separator.enabled) gap += 1;
|
||||
|
||||
switch (this.properties.layout.direction) {
|
||||
.horizontal => size.cols += gap * (len - 1),
|
||||
.vertical => size.rows += gap * (len - 1),
|
||||
}
|
||||
}
|
||||
return size.max(this.properties.min_size);
|
||||
}
|
||||
|
||||
pub fn handle(this: *@This(), event: Event) !void {
|
||||
switch (event) {
|
||||
.resize => |size| resize: {
|
||||
@@ -618,11 +600,32 @@ pub fn Container(comptime Event: type) type {
|
||||
size.rows,
|
||||
});
|
||||
this.size = size;
|
||||
if (this.properties.fixed_size.cols > 0 and size.cols < this.properties.fixed_size.cols) return error.TooSmall;
|
||||
if (this.properties.fixed_size.rows > 0 and size.rows < this.properties.fixed_size.rows) 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: Size = .{};
|
||||
for (this.elements.items) |element| {
|
||||
switch (layout.direction) {
|
||||
.horizontal => if (element.properties.fixed_size.cols > 0) {
|
||||
fixed_size_elements += 1;
|
||||
},
|
||||
.vertical => if (element.properties.fixed_size.rows > 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.cols > size.cols) return error.TooSmall,
|
||||
.vertical => if (fixed_size.rows > size.rows) return error.TooSmall,
|
||||
}
|
||||
const sides = this.properties.border.sides;
|
||||
const padding = layout.padding;
|
||||
var gap = layout.gap;
|
||||
@@ -630,18 +633,28 @@ pub fn Container(comptime Event: type) type {
|
||||
|
||||
const len: u16 = @truncate(this.elements.items.len);
|
||||
const element_cols = blk: {
|
||||
var cols = size.cols - gap * (len - 1);
|
||||
var cols = size.cols - fixed_size.cols - gap * (len - 1);
|
||||
if (sides.left) cols -= 1;
|
||||
if (sides.right) cols -= 1;
|
||||
cols -= padding.left + padding.right;
|
||||
break :blk @divTrunc(cols, len);
|
||||
if (fixed_size_elements == len) break :blk 0;
|
||||
if (fixed_size_elements == 0) {
|
||||
break :blk @divTrunc(cols, len);
|
||||
} else {
|
||||
break :blk @divTrunc(cols, len - fixed_size_elements);
|
||||
}
|
||||
};
|
||||
const element_rows = blk: {
|
||||
var rows = size.rows - gap * (len - 1);
|
||||
var rows = size.rows - fixed_size.rows - gap * (len - 1);
|
||||
if (sides.top) rows -= 1;
|
||||
if (sides.bottom) rows -= 1;
|
||||
rows -= padding.top + padding.bottom;
|
||||
break :blk @divTrunc(rows, len);
|
||||
if (fixed_size_elements == len) break :blk 0;
|
||||
if (fixed_size_elements == 0) {
|
||||
break :blk @divTrunc(rows, len);
|
||||
} else {
|
||||
break :blk @divTrunc(rows, len - fixed_size_elements);
|
||||
}
|
||||
};
|
||||
var offset: u16 = switch (layout.direction) {
|
||||
.horizontal => padding.left,
|
||||
@@ -649,18 +662,28 @@ pub fn Container(comptime Event: type) type {
|
||||
};
|
||||
var overflow = switch (layout.direction) {
|
||||
.horizontal => blk: {
|
||||
var cols = size.cols - gap * (len - 1);
|
||||
var cols = size.cols - fixed_size.cols - gap * (len - 1);
|
||||
if (sides.left) cols -= 1;
|
||||
if (sides.right) cols -= 1;
|
||||
cols -= padding.left + padding.right;
|
||||
break :blk cols - element_cols * len;
|
||||
if (fixed_size_elements == len) break :blk 0;
|
||||
if (fixed_size_elements == 0) {
|
||||
break :blk cols - element_cols * len;
|
||||
} else {
|
||||
break :blk cols - element_cols * (len - fixed_size_elements);
|
||||
}
|
||||
},
|
||||
.vertical => blk: {
|
||||
var rows = size.rows - gap * (len - 1);
|
||||
var rows = size.rows - fixed_size.rows - gap * (len - 1);
|
||||
if (sides.top) rows -= 1;
|
||||
if (sides.bottom) rows -= 1;
|
||||
rows -= padding.top + padding.bottom;
|
||||
break :blk rows - element_rows * len;
|
||||
if (fixed_size_elements == len) break :blk 0;
|
||||
if (fixed_size_elements == 0) {
|
||||
break :blk rows - element_rows * len;
|
||||
} else {
|
||||
break :blk rows - element_rows * (len - fixed_size_elements);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -668,7 +691,11 @@ pub fn Container(comptime Event: type) type {
|
||||
var element_size: Size = undefined;
|
||||
switch (layout.direction) {
|
||||
.horizontal => {
|
||||
var cols = element_cols;
|
||||
// TODO: this should not always be the max size property!
|
||||
var cols = blk: {
|
||||
if (element.properties.fixed_size.cols > 0) break :blk element.properties.fixed_size.cols;
|
||||
break :blk element_cols;
|
||||
};
|
||||
if (overflow > 0) {
|
||||
overflow -|= 1;
|
||||
cols += 1;
|
||||
@@ -692,7 +719,10 @@ pub fn Container(comptime Event: type) type {
|
||||
offset += cols;
|
||||
},
|
||||
.vertical => {
|
||||
var rows = element_rows;
|
||||
var rows = blk: {
|
||||
if (element.properties.fixed_size.rows > 0) break :blk element.properties.fixed_size.rows;
|
||||
break :blk element_rows;
|
||||
};
|
||||
if (overflow > 0) {
|
||||
overflow -|= 1;
|
||||
rows += 1;
|
||||
|
||||
@@ -58,12 +58,16 @@ 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 = .{},
|
||||
/// Minimal `Size` of the scrollable `Container` to be used. If the
|
||||
/// actual scrollable container's size is larger it will be used instead
|
||||
/// (no scrolling will be necessary for that screen size).
|
||||
min_size: Size = .{},
|
||||
/// `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),
|
||||
|
||||
pub fn element(this: *@This()) Element(Event) {
|
||||
@@ -76,8 +80,11 @@ pub fn Scrollable(Event: type) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init(container: Container(Event)) @This() {
|
||||
return .{ .container = container };
|
||||
pub fn init(container: Container(Event), min_size: Size) @This() {
|
||||
return .{
|
||||
.container = container,
|
||||
.min_size = min_size,
|
||||
};
|
||||
}
|
||||
|
||||
fn handle(ctx: *anyopaque, event: Event) !void {
|
||||
@@ -86,7 +93,7 @@ pub fn Scrollable(Event: type) type {
|
||||
.resize => |size| {
|
||||
this.size = size;
|
||||
// TODO: scrollbar space - depending on configuration and only if necessary?
|
||||
this.container_size = size.max(this.container.minSize());
|
||||
this.container_size = size.max(this.min_size);
|
||||
this.container_size.anchor = size.anchor;
|
||||
try this.container.handle(.{ .resize = this.container_size });
|
||||
},
|
||||
@@ -190,7 +197,6 @@ test "scrollable vertical" {
|
||||
.direction = .vertical,
|
||||
.padding = .all(1),
|
||||
},
|
||||
.min_size = .{ .rows = size.rows + 15 },
|
||||
}, .{});
|
||||
try box.append(try .init(std.testing.allocator, .{
|
||||
.rectangle = .{ .fill = .grey },
|
||||
@@ -200,7 +206,7 @@ test "scrollable vertical" {
|
||||
}, .{}));
|
||||
defer box.deinit();
|
||||
|
||||
var scrollable: Scrollable(event.SystemEvent) = .init(box);
|
||||
var scrollable: Scrollable(event.SystemEvent) = .init(box, .{ .rows = size.rows + 15 });
|
||||
|
||||
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
||||
.border = .{
|
||||
@@ -265,7 +271,6 @@ test "scrollable horizontal" {
|
||||
.direction = .horizontal,
|
||||
.padding = .all(1),
|
||||
},
|
||||
.min_size = .{ .cols = size.cols + 15 },
|
||||
}, .{});
|
||||
try box.append(try .init(std.testing.allocator, .{
|
||||
.rectangle = .{ .fill = .grey },
|
||||
@@ -275,7 +280,7 @@ test "scrollable horizontal" {
|
||||
}, .{}));
|
||||
defer box.deinit();
|
||||
|
||||
var scrollable: Scrollable(event.SystemEvent) = .init(box);
|
||||
var scrollable: Scrollable(event.SystemEvent) = .init(box, .{ .cols = size.cols + 15 });
|
||||
|
||||
var container: Container(event.SystemEvent) = try .init(std.testing.allocator, .{
|
||||
.border = .{
|
||||
|
||||
Reference in New Issue
Block a user