Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions app/layout/State.zig
Original file line number Diff line number Diff line change
Expand Up @@ -841,7 +841,17 @@ pub fn deinitWarm(self: *State, gpa: std.mem.Allocator) void {
pub fn resetLayout(self: *State, gpa: std.mem.Allocator) void {
for (self.regions.items) |r| forgetWidgetSize(r.id);
for (self.regions_building.items) |r| forgetWidgetSize(r.id);
self.clearArrangement(gpa);
self.clearDock();
// The floats' places went with the assignments and splits; their windows go too.
self.floats.clear();
}

/// Forget what the user arranged — extents, assignments, orders, Single/Multiple and the splits —
/// and any drag or transition under way, keeping each place's widget state (how wide it is drawn,
/// shut or not), the seed tree and the floats. For putting an arrangement back on top of it
/// (`Editor.applySavedRegions`), as a demo's snapshot does; `resetLayout` forgets the rest too.
pub fn clearArrangement(self: *State, gpa: std.mem.Allocator) void {
var eit = self.extents.keyIterator();
while (eit.next()) |k| gpa.free(k.*);
self.extents.clearRetainingCapacity();
Expand All @@ -858,17 +868,15 @@ pub fn resetLayout(self: *State, gpa: std.mem.Allocator) void {

self.splits.deinit(gpa);
self.splits = .{};
self.clearDock();
// The floats' places went with the assignments and splits above; their windows go too.
self.floats.clear();
self.slide_open = "";
self.view_drag.discard();
self.discardSwaps();
self.center_transition.discard();
self.center_prev_id = null;
}

fn forgetWidgetSize(id: dvui.Id) void {
/// Forget how place `id` was drawn: its size, shut or not, and any ease or drag under way.
pub fn forgetWidgetSize(id: dvui.Id) void {
if (id == .zero) return;
dvui.dataRemove(null, id, "_size");
dvui.dataRemove(null, id, "_shown");
Expand Down
11 changes: 11 additions & 0 deletions plugins/workbench/src/Workbench.zig
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,17 @@ pub fn restorePanes(self: *Workbench) void {
workbench_layout.restorePanes(self);
}

/// The panes as they stand, for a demo's snapshot (`workbench_layout.arrangement`).
pub const Arrangement = struct { open: u64, groupings: []const u64, tree: [:0]const u8 };

pub fn arrangement(self: *Workbench, arena: std.mem.Allocator) !Arrangement {
return workbench_layout.arrangement(self, arena);
}

pub fn arrange(self: *Workbench, a: Arrangement) !void {
return workbench_layout.arrange(self, a);
}

pub fn forgetPanes(self: *Workbench) void {
workbench_layout.forgetPanes(self);
}
Expand Down
58 changes: 58 additions & 0 deletions plugins/workbench/src/workbench_layout.zig
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,64 @@ pub fn restorePanes(wb: *Workbench) void {
if (wb.workspaces.contains(wb.held_open)) wb.open_workspace_grouping = wb.held_open;
}

/// The panes as they stand, for a demo's snapshot to put back (`arrange`): which there are, in
/// row order, the one in front, and the tree they sit in as ZON (`Panes.Snapshot`). What each
/// holds is the app's assignment under its name, which the app's layout keeps. All in `arena`.
pub fn arrangement(wb: *Workbench, arena: std.mem.Allocator) !Workbench.Arrangement {
return .{
.open = wb.open_workspace_grouping,
.groupings = try arena.dupe(u64, wb.workspaces.keys()),
.tree = try panesZon(wb, arena),
};
}

fn panesZon(wb: *Workbench, gpa: std.mem.Allocator) ![:0]u8 {
const snap = try wb.panes.snapshot(wb.allocator);
defer snap.deinit(wb.allocator);
var aw: std.Io.Writer.Allocating = .init(gpa);
errdefer aw.deinit();
try std.zon.stringify.serializeMaxDepth(snap, .{}, &aw.writer, 64);
return aw.toOwnedSliceSentinel(0);
}

/// Put the panes back to `a` (`arrangement`): the panes it had, each a fresh workspace where it is
/// not one now, those it did not have gone, and its tree. Their tabs are the app's assignments,
/// for the caller to put back with the rest of the app's layout. Where the app arranges the panes
/// (`places`) there is no tree of the workbench's to put back: `error.AppArranged` unless the
/// panes are already the same.
pub fn arrange(wb: *Workbench, a: Workbench.Arrangement) !void {
const same_panes = std.mem.eql(u64, wb.workspaces.keys(), a.groupings);
if (wb.places != null and !same_panes) return error.AppArranged;
const same_tree = wb.places != null or (same_panes and blk: {
const now = try panesZon(wb, wb.allocator);
defer wb.allocator.free(now);
break :blk std.mem.eql(u8, now, a.tree);
});
if (!same_tree) try replacePanes(wb, a);
if (wb.workspaces.contains(a.open)) wb.open_workspace_grouping = a.open;
}

fn replacePanes(wb: *Workbench, a: Workbench.Arrangement) !void {
var arena: std.heap.ArenaAllocator = .init(wb.allocator);
defer arena.deinit();
var diag: std.zon.parse.Diagnostics = undefined;
const snap = try std.zon.parse.fromSlice(Panes.Snapshot, .{ .gpa = wb.allocator, .arena = arena.allocator(), .source = a.tree, .diagnostics = &diag });
var tree = try Panes.fromSnapshot(wb.allocator, snap);
errdefer tree.deinit();
tree.animated = true;

var panes: std.AutoArrayHashMapUnmanaged(u64, Workspace) = .empty;
errdefer panes.deinit(wb.allocator);
try panes.ensureTotalCapacity(wb.allocator, a.groupings.len);
for (a.groupings) |g| panes.putAssumeCapacity(g, wb.workspaces.get(g) orelse Workspace.init(g));
for (wb.workspaces.values()) |*ws| {
if (!panes.contains(ws.grouping)) ws.deinit();
}
wb.workspaces.deinit(wb.allocator);
wb.workspaces = panes;
adoptPanes(wb, tree);
}

/// Delete the saved arrangement: the app has taken it over (`Workbench.places`).
pub fn forgetPanes(wb: *Workbench) void {
if (comptime builtin.target.cpu.arch == .wasm32) return;
Expand Down
5 changes: 5 additions & 0 deletions sdk/src/Host.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2616,6 +2616,11 @@ pub fn selectionForKey(self: *Host, key: u64) ?[]const u8 {
return self.selections.get(key);
}

/// No surface chosen under `key` any more: its region's keywords decide again.
pub fn clearSelectionForKey(self: *Host, key: u64) void {
_ = self.selections.remove(key);
}

pub fn setSelectionForKey(self: *Host, key: u64, id: []const u8) void {
// Store the registry pointer, never a frame-arena copy. A view-drag
// used to hand an arena id to a new split; the next frame's `pick`
Expand Down
Loading
Loading