diff --git a/src/apprt/gtk/Split.zig b/src/apprt/gtk/Split.zig index 7d6030c9b..1971f865c 100644 --- a/src/apprt/gtk/Split.zig +++ b/src/apprt/gtk/Split.zig @@ -15,12 +15,17 @@ const c = @import("c.zig"); const log = std.log.scoped(.gtk); +pub const Orientation = enum { horizontal, vertical }; + /// Our actual GtkPaned widget paned: *c.GtkPaned, /// The container for this split panel. container: Surface.Container, +/// The orientation of this split panel. +orientation: Orientation, + /// The elements of this split panel. top_left: Surface.Container.Elem, bottom_right: Surface.Container.Elem, @@ -78,6 +83,10 @@ pub fn init( .container = container, .top_left = .{ .surface = sibling }, .bottom_right = .{ .surface = surface }, + .orientation = (switch (direction) { + .right => .horizontal, + .down => .vertical, + }), }; // Replace the previous containers element with our split. @@ -137,6 +146,15 @@ fn removeChild( alloc.destroy(self); } +pub fn moveDivider(self: *Split, direction: input.SplitResizeDirection, amount: u16) void { + const pos = c.gtk_paned_get_position(self.paned); + const new = switch (direction) { + .up, .left => pos - amount, + .down, .right => pos + amount, + }; + c.gtk_paned_set_position(self.paned, new); +} + // This replaces the element at the given pointer with a new element. // The ptr must be either top_left or bottom_right (asserted in debug). // The memory of the old element must be freed or otherwise handled by diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index 266c67215..51e6a5146 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -151,6 +151,19 @@ pub const Container = union(enum) { }; } + /// Returns the first split with the given orientation, walking upwards in + /// the tree. + pub fn firstSplitWithOrientation(self: Container, orientation: Split.Orientation) ?*Split { + return switch (self) { + .none, .tab_ => null, + .split_tl, .split_br => split: { + const s = self.split() orelse break :split null; + if (s.orientation == orientation) break :split s; + break :split s.container.firstSplitWithOrientation(orientation); + }, + }; + } + /// Replace the container's element with this element. This is /// 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 @@ -559,6 +572,14 @@ pub fn gotoSplit(self: *const Surface, direction: input.SplitFocusDirection) voi if (surface_) |surface| surface.grabFocus(); } +pub fn resizeSplit(self: *const Surface, direction: input.SplitResizeDirection, amount: u16) void { + const s = self.container.firstSplitWithOrientation(switch (direction) { + .up, .down => .vertical, + .left, .right => .horizontal, + }) orelse return; + s.moveDivider(direction, amount); +} + pub fn newTab(self: *Surface) !void { const window = self.container.window() orelse { log.info("surface cannot create new tab when not attached to a window", .{}); diff --git a/src/config/Config.zig b/src/config/Config.zig index e59fb2843..b6d763bea 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -977,6 +977,28 @@ pub fn default(alloc_gpa: Allocator) Allocator.Error!Config { .{ .goto_split = .right }, ); + // Resizing splits + try result.keybind.set.put( + alloc, + .{ .key = .up, .mods = .{ .super = true, .ctrl = true, .shift = true } }, + .{ .resize_split = .{ .up, 10 } }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .down, .mods = .{ .super = true, .ctrl = true, .shift = true } }, + .{ .resize_split = .{ .down, 10 } }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .left, .mods = .{ .super = true, .ctrl = true, .shift = true } }, + .{ .resize_split = .{ .left, 10 } }, + ); + try result.keybind.set.put( + alloc, + .{ .key = .right, .mods = .{ .super = true, .ctrl = true, .shift = true } }, + .{ .resize_split = .{ .right, 10 } }, + ); + // Viewport scrolling try result.keybind.set.put( alloc,