1
0
Fork 0

feat: implement relayouting

closes #18
This commit is contained in:
LordMZTE 2024-01-30 16:13:59 +01:00
parent f925e5736c
commit c4ae23938d
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
4 changed files with 60 additions and 1 deletions

View file

@ -6,9 +6,11 @@ const statspatch = @import("statspatch");
test {
_ = ButtonActivated;
_ = Relayout;
}
pub const ButtonActivated = @import("backevents/ButtonActivated.zig");
pub const Relayout = @import("backevents/Relayout.zig");
const zenolith = @import("main.zig");
@ -29,13 +31,28 @@ fn Prototype(comptime Self: type) type {
) orelse {});
}
/// A callback that is automatically invoked before the backevent is propageted up the tree.
/// Here, the backevent may make changes to itself before being passed to the parent widget.
/// It is not invoked if there is no parent widget, that causes `unhandled` to be called immediately.
pub fn prePropagate(self: *Self, next_widget: *Widget) !void {
try (statspatch.implcallOptional(
self,
.ptr,
"prePropagate",
anyerror!void,
.{ self, next_widget },
) orelse {});
}
/// Propagates this backevent up the widget tree. If the current (given) Widget has a parent,
/// the event is propagated to it. Otherwise, the backevent's unhandled handler is called.
/// Widgets should call this in their backevent handler if they do not wish to modify or
/// intercept the backevent.
pub fn dispatch(self: Self, widget: *Widget) anyerror!void {
if (widget.data.parent) |p| {
try p.backevent(self);
var selfv = self;
try selfv.prePropagate(p);
try p.backevent(selfv);
} else {
try self.unhandled(widget);
}

View file

@ -0,0 +1,29 @@
//! This backevent is fired on a widget to signal that this widget needs another layout pass done on it.
//! A widget should handle this if it can do another layout pass on its child while guaranteeing
//! that its own size won't change in the process.
//! If no widget is able to handle this backevent, the platform will be asked to do another layout pass.
const std = @import("std");
const Backevent = @import("../backevent.zig").Backevent;
const Widget = @import("../widget.zig").Widget;
/// Not necessarily the widget this backevent originated from, but an immediate child of the
/// widget it is currently being dispatched on. This is the child that should be laid out again.
child: *Widget,
const Relayout = @This();
pub fn prePropagate(self: *Relayout, selfb: *Backevent, next_widget: *Widget) !void {
_ = selfb;
self.child = next_widget;
}
pub fn unhandled(self: Relayout, selfb: Backevent, root: *Widget) !void {
_ = selfb;
std.debug.assert(self.child == root);
if (root.data.platform) |plat| {
try plat.relayoutRoot(root);
}
}

View file

@ -58,6 +58,7 @@ pub const default_platform_impls = [_]type{};
/// The default backevents in Zenolith. Remember that these may be required by widgets.
pub const default_backevents = [_]type{
backevent.ButtonActivated,
backevent.Relayout,
};
const root_options = if (@hasDecl(root, "zenolith_options")) root.zenolith_options else struct {};

View file

@ -29,6 +29,18 @@ fn Prototype(comptime Self: type) type {
}
}
}
/// Do a layout pass on a given widget. The passed widget is asserted to be a root widget of
/// this platform.
pub fn relayoutRoot(self: *Self, root: *Widget) !void {
try statspatch.implcall(
self,
.ptr,
"relayoutRoot",
anyerror!void,
.{ root },
);
}
};
}