apprt/gtk-ng: equalize splits
parent
a21b447c75
commit
9f037a7c23
|
|
@ -553,6 +553,8 @@ pub const Application = extern struct {
|
|||
|
||||
.desktop_notification => Action.desktopNotification(self, target, value),
|
||||
|
||||
.equalize_splits => return Action.equalizeSplits(target),
|
||||
|
||||
.goto_split => return Action.gotoSplit(target, value),
|
||||
|
||||
.goto_tab => return Action.gotoTab(target, value),
|
||||
|
|
@ -617,7 +619,6 @@ pub const Application = extern struct {
|
|||
.inspector,
|
||||
// TODO: splits
|
||||
.resize_split,
|
||||
.equalize_splits,
|
||||
.toggle_split_zoom,
|
||||
=> {
|
||||
log.warn("unimplemented action={}", .{action});
|
||||
|
|
@ -1652,6 +1653,20 @@ const Action = struct {
|
|||
gio_app.sendNotification(n.body, notification);
|
||||
}
|
||||
|
||||
pub fn equalizeSplits(target: apprt.Target) bool {
|
||||
switch (target) {
|
||||
.app => {
|
||||
log.warn("equalize splits to app is unexpected", .{});
|
||||
return false;
|
||||
},
|
||||
|
||||
.surface => |core| {
|
||||
const surface = core.rt_surface.surface;
|
||||
return surface.as(gtk.Widget).activateAction("split-tree.equalize", null) != 0;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gotoSplit(
|
||||
target: apprt.Target,
|
||||
to: apprt.action.GotoSplit,
|
||||
|
|
|
|||
|
|
@ -163,6 +163,8 @@ pub const SplitTree = extern struct {
|
|||
.{ "new-right", actionNewRight, null },
|
||||
.{ "new-up", actionNewUp, null },
|
||||
.{ "new-down", actionNewDown, null },
|
||||
|
||||
.{ "equalize", actionEqualize, null },
|
||||
};
|
||||
|
||||
// We need to collect our actions into a group since we're just
|
||||
|
|
@ -537,6 +539,22 @@ pub const SplitTree = extern struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn actionEqualize(
|
||||
_: *gio.SimpleAction,
|
||||
parameter_: ?*glib.Variant,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
_ = parameter_;
|
||||
|
||||
const old_tree = self.getTree() orelse return;
|
||||
var new_tree = old_tree.equalize(Application.default().allocator()) catch |err| {
|
||||
log.warn("unable to equalize tree: {}", .{err});
|
||||
return;
|
||||
};
|
||||
defer new_tree.deinit();
|
||||
self.setTree(&new_tree);
|
||||
}
|
||||
|
||||
fn surfaceCloseRequest(
|
||||
surface: *Surface,
|
||||
scope: *const Surface.CloseScope,
|
||||
|
|
|
|||
|
|
@ -642,6 +642,62 @@ pub fn SplitTree(comptime V: type) type {
|
|||
assert(reffed == nodes.len - 1);
|
||||
}
|
||||
|
||||
/// Equalize this node and all its children, returning a new node with splits
|
||||
/// adjusted so that each split's ratio is based on the relative weight
|
||||
/// (number of leaves) of its children.
|
||||
pub fn equalize(
|
||||
self: *const Self,
|
||||
gpa: Allocator,
|
||||
) Allocator.Error!Self {
|
||||
if (self.isEmpty()) return .empty;
|
||||
|
||||
// Create a new arena allocator for the clone.
|
||||
var arena = ArenaAllocator.init(gpa);
|
||||
errdefer arena.deinit();
|
||||
const alloc = arena.allocator();
|
||||
|
||||
// Allocate a new nodes array and copy the existing nodes into it.
|
||||
const nodes = try alloc.dupe(Node, self.nodes);
|
||||
|
||||
// Go through and equalize our ratios based on weights.
|
||||
for (nodes) |*node| switch (node.*) {
|
||||
.leaf => {},
|
||||
.split => |*s| {
|
||||
const weight_left = self.weight(s.left, s.layout, 0);
|
||||
const weight_right = self.weight(s.right, s.layout, 0);
|
||||
assert(weight_left > 0);
|
||||
assert(weight_right > 0);
|
||||
const total_f16: f16 = @floatFromInt(weight_left + weight_right);
|
||||
const weight_left_f16: f16 = @floatFromInt(weight_left);
|
||||
s.ratio = weight_left_f16 / total_f16;
|
||||
},
|
||||
};
|
||||
|
||||
// Increase the reference count of all the views in the nodes.
|
||||
try refNodes(gpa, nodes);
|
||||
|
||||
return .{
|
||||
.arena = arena,
|
||||
.nodes = nodes,
|
||||
};
|
||||
}
|
||||
|
||||
fn weight(
|
||||
self: *const Self,
|
||||
from: Node.Handle,
|
||||
layout: Split.Layout,
|
||||
acc: usize,
|
||||
) usize {
|
||||
return switch (self.nodes[from]) {
|
||||
.leaf => acc + 1,
|
||||
.split => |s| if (s.layout == layout)
|
||||
self.weight(s.left, layout, acc) +
|
||||
self.weight(s.right, layout, acc)
|
||||
else
|
||||
1,
|
||||
};
|
||||
}
|
||||
|
||||
/// Spatial representation of the split tree. See spatial.
|
||||
pub const Spatial = struct {
|
||||
/// The slots of the spatial representation in the same order
|
||||
|
|
@ -1563,6 +1619,24 @@ test "SplitTree: spatial goto" {
|
|||
const view = split.nodes[target].leaf;
|
||||
try testing.expectEqualStrings("A", view.label);
|
||||
}
|
||||
|
||||
// Equalize
|
||||
var equal = try split.equalize(alloc);
|
||||
defer equal.deinit();
|
||||
|
||||
{
|
||||
const str = try std.fmt.allocPrint(alloc, "{diagram}", .{equal});
|
||||
defer alloc.free(str);
|
||||
try testing.expectEqualStrings(str,
|
||||
\\+---++---+
|
||||
\\| A || B |
|
||||
\\+---++---+
|
||||
\\+---++---+
|
||||
\\| C || D |
|
||||
\\+---++---+
|
||||
\\
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
test "SplitTree: clone empty tree" {
|
||||
|
|
|
|||
Loading…
Reference in New Issue