apprt/gtk: gotoSplit gets proper previous/next direction

This commit is contained in:
Mitchell Hashimoto
2023-12-01 13:21:31 -08:00
parent f811ac6b18
commit d311fb93ed
2 changed files with 65 additions and 62 deletions

View File

@ -193,89 +193,68 @@ pub const Side = enum { top_left, bottom_right };
/// Returns the map that can be used to determine elements in various /// Returns the map that can be used to determine elements in various
/// directions (primarily for gotoSplit). /// directions (primarily for gotoSplit).
pub fn directionMap(self: *const Split, from: Side) DirectionMap { pub fn directionMap(self: *const Split, from: Side) DirectionMap {
return switch (from) {
.top_left => self.directionMapFromTopLeft(),
.bottom_right => self.directionMapFromBottomRight(),
};
}
fn directionMapFromTopLeft(self: *const Split) DirectionMap {
var result = DirectionMap.initFull(null); var result = DirectionMap.initFull(null);
if (self.container.split()) |parent_split| { if (self.directionPrevious(from)) |prev| {
const deepest_br = parent_split.deepestSurface(.bottom_right); result.put(.previous, prev);
result.put(.previous, deepest_br);
// This behavior matches the behavior of macOS at the time of writing // This behavior matches the behavior of macOS at the time of writing
// this. There is an open issue (#524) to make this depend on the // this. There is an open issue (#524) to make this depend on the
// actual physical location of the current split. // actual physical location of the current split.
result.put(.top, deepest_br); result.put(.top, prev);
result.put(.left, deepest_br); result.put(.left, prev);
} }
switch (self.bottom_right) { if (self.directionNext(from)) |next| {
.surface => |s| { result.put(.next, next);
result.put(.next, s); result.put(.bottom, next);
result.put(.bottom, s); result.put(.right, next);
result.put(.right, s);
},
.split => |s| {
const deepest_tl = s.deepestSurface(.top_left);
result.put(.next, deepest_tl);
result.put(.bottom, deepest_tl);
result.put(.right, deepest_tl);
},
} }
return result; return result;
} }
fn directionMapFromBottomRight(self: *const Split) DirectionMap { fn directionPrevious(self: *const Split, from: Side) ?*Surface {
var result = DirectionMap.initFull(null); switch (from) {
// From the bottom right, our previous is the deepest surface
// in the top-left of our own split.
.bottom_right => return self.top_left.deepestSurface(.bottom_right),
if (self.container.split()) |parent_split| { // From the top left its more complicated. It is the de
const deepest_tl = parent_split.deepestSurface(.top_left); .top_left => {
result.put(.next, deepest_tl); // If we have no parent split then there can be no previous.
const parent = self.container.split() orelse return null;
const side = self.container.splitSide() orelse return null;
// This behavior matches the behavior of macOS at the time of writing // The previous value is the previous of the side that we are.
// this. There is an open issue (#524) to make this depend on the return switch (side) {
// actual physical location of the current split. .top_left => parent.directionPrevious(.top_left),
result.put(.top, deepest_tl); .bottom_right => parent.directionPrevious(.bottom_right),
result.put(.left, deepest_tl); };
}
switch (self.top_left) {
.surface => |s| {
result.put(.previous, s);
result.put(.bottom, s);
result.put(.right, s);
},
.split => |s| {
const deepest_br = s.deepestSurface(.bottom_right);
result.put(.previous, deepest_br);
result.put(.bottom, deepest_br);
result.put(.right, deepest_br);
}, },
} }
return result;
} }
/// Get the most deeply nested surface for a given side. fn directionNext(self: *const Split, from: Side) ?*Surface {
fn deepestSurface(self: *const Split, side: Side) *Surface { switch (from) {
return switch (side) { // From the top left, our next is the earliest surface in the
.bottom_right => switch (self.bottom_right) { // top-left direction of the bottom-right side of our split. Fun!
.surface => |s| s, .top_left => return self.bottom_right.deepestSurface(.top_left),
.split => |s| s.deepestSurface(.bottom_right),
},
.top_left => switch (self.top_left) { // From the bottom right is more compliated. It is the deepest
.surface => |s| s, // (last) surface in the
.split => |s| s.deepestSurface(.top_left), .bottom_right => {
// If we have no parent split then there can be no next.
const parent = self.container.split() orelse return null;
const side = self.container.splitSide() orelse return null;
// The previous value is the previous of the side that we are.
return switch (side) {
.top_left => parent.directionNext(.bottom_right),
.bottom_right => parent.directionNext(.bottom_right),
};
}, },
}; }
} }
fn removeChildren(self: *const Split) void { fn removeChildren(self: *const Split) void {

View File

@ -48,6 +48,9 @@ pub const Container = union(enum) {
split_tl: *Elem, split_tl: *Elem,
split_br: *Elem, split_br: *Elem,
/// The side of the split.
pub const SplitSide = enum { top_left, bottom_right };
/// Elem is the possible element of any container. A container can /// Elem is the possible element of any container. A container can
/// hold both a surface and a split. Any valid container should /// hold both a surface and a split. Any valid container should
/// have an Elem value so that it can be properly used with /// have an Elem value so that it can be properly used with
@ -92,6 +95,18 @@ pub const Container = union(enum) {
.split => |s| s.grabFocus(), .split => |s| s.grabFocus(),
} }
} }
/// The last surface in this container in the direction specified.
/// Direction must be "top_left" or "bottom_right".
pub fn deepestSurface(self: Elem, side: SplitSide) ?*Surface {
return switch (self) {
.surface => |s| s,
.split => |s| (switch (side) {
.top_left => s.top_left,
.bottom_right => s.bottom_right,
}).deepestSurface(side),
};
}
}; };
/// Returns the window that this surface is attached to. /// Returns the window that this surface is attached to.
@ -127,6 +142,15 @@ pub const Container = union(enum) {
}; };
} }
/// The side that we are in the split.
pub fn splitSide(self: Container) ?SplitSide {
return switch (self) {
.none, .tab_ => null,
.split_tl => .top_left,
.split_br => .bottom_right,
};
}
/// Replace the container's element with this element. This is /// Replace the container's element with this element. This is
/// used by children to modify their parents to for example change /// used by children to modify their parents to for example change
/// from a surface to a split or a split back to a surface or /// from a surface to a split or a split back to a surface or