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),
|
.desktop_notification => Action.desktopNotification(self, target, value),
|
||||||
|
|
||||||
|
.equalize_splits => return Action.equalizeSplits(target),
|
||||||
|
|
||||||
.goto_split => return Action.gotoSplit(target, value),
|
.goto_split => return Action.gotoSplit(target, value),
|
||||||
|
|
||||||
.goto_tab => return Action.gotoTab(target, value),
|
.goto_tab => return Action.gotoTab(target, value),
|
||||||
|
|
@ -617,7 +619,6 @@ pub const Application = extern struct {
|
||||||
.inspector,
|
.inspector,
|
||||||
// TODO: splits
|
// TODO: splits
|
||||||
.resize_split,
|
.resize_split,
|
||||||
.equalize_splits,
|
|
||||||
.toggle_split_zoom,
|
.toggle_split_zoom,
|
||||||
=> {
|
=> {
|
||||||
log.warn("unimplemented action={}", .{action});
|
log.warn("unimplemented action={}", .{action});
|
||||||
|
|
@ -1652,6 +1653,20 @@ const Action = struct {
|
||||||
gio_app.sendNotification(n.body, notification);
|
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(
|
pub fn gotoSplit(
|
||||||
target: apprt.Target,
|
target: apprt.Target,
|
||||||
to: apprt.action.GotoSplit,
|
to: apprt.action.GotoSplit,
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,8 @@ pub const SplitTree = extern struct {
|
||||||
.{ "new-right", actionNewRight, null },
|
.{ "new-right", actionNewRight, null },
|
||||||
.{ "new-up", actionNewUp, null },
|
.{ "new-up", actionNewUp, null },
|
||||||
.{ "new-down", actionNewDown, null },
|
.{ "new-down", actionNewDown, null },
|
||||||
|
|
||||||
|
.{ "equalize", actionEqualize, null },
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need to collect our actions into a group since we're just
|
// 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(
|
fn surfaceCloseRequest(
|
||||||
surface: *Surface,
|
surface: *Surface,
|
||||||
scope: *const Surface.CloseScope,
|
scope: *const Surface.CloseScope,
|
||||||
|
|
|
||||||
|
|
@ -642,6 +642,62 @@ pub fn SplitTree(comptime V: type) type {
|
||||||
assert(reffed == nodes.len - 1);
|
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.
|
/// Spatial representation of the split tree. See spatial.
|
||||||
pub const Spatial = struct {
|
pub const Spatial = struct {
|
||||||
/// The slots of the spatial representation in the same order
|
/// The slots of the spatial representation in the same order
|
||||||
|
|
@ -1563,6 +1619,24 @@ test "SplitTree: spatial goto" {
|
||||||
const view = split.nodes[target].leaf;
|
const view = split.nodes[target].leaf;
|
||||||
try testing.expectEqualStrings("A", view.label);
|
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" {
|
test "SplitTree: clone empty tree" {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue