mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 00:06:09 +03:00
gtk: add support for resizing splits via keybinds
This adds support for resizing splits via keybinds to the GTK runtime. Code is straightforward. I couldn't see a way to do it without keeping track of the orientation of the splits, but I think that's fine.
This commit is contained in:
@ -15,12 +15,17 @@ const c = @import("c.zig");
|
|||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
|
pub const Orientation = enum { horizontal, vertical };
|
||||||
|
|
||||||
/// Our actual GtkPaned widget
|
/// Our actual GtkPaned widget
|
||||||
paned: *c.GtkPaned,
|
paned: *c.GtkPaned,
|
||||||
|
|
||||||
/// The container for this split panel.
|
/// The container for this split panel.
|
||||||
container: Surface.Container,
|
container: Surface.Container,
|
||||||
|
|
||||||
|
/// The orientation of this split panel.
|
||||||
|
orientation: Orientation,
|
||||||
|
|
||||||
/// The elements of this split panel.
|
/// The elements of this split panel.
|
||||||
top_left: Surface.Container.Elem,
|
top_left: Surface.Container.Elem,
|
||||||
bottom_right: Surface.Container.Elem,
|
bottom_right: Surface.Container.Elem,
|
||||||
@ -78,6 +83,10 @@ pub fn init(
|
|||||||
.container = container,
|
.container = container,
|
||||||
.top_left = .{ .surface = sibling },
|
.top_left = .{ .surface = sibling },
|
||||||
.bottom_right = .{ .surface = surface },
|
.bottom_right = .{ .surface = surface },
|
||||||
|
.orientation = (switch (direction) {
|
||||||
|
.right => .horizontal,
|
||||||
|
.down => .vertical,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Replace the previous containers element with our split.
|
// Replace the previous containers element with our split.
|
||||||
@ -137,6 +146,15 @@ fn removeChild(
|
|||||||
alloc.destroy(self);
|
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.
|
// 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 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
|
// The memory of the old element must be freed or otherwise handled by
|
||||||
|
@ -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
|
/// 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
|
||||||
@ -559,6 +572,14 @@ pub fn gotoSplit(self: *const Surface, direction: input.SplitFocusDirection) voi
|
|||||||
if (surface_) |surface| surface.grabFocus();
|
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 {
|
pub fn newTab(self: *Surface) !void {
|
||||||
const window = self.container.window() orelse {
|
const window = self.container.window() orelse {
|
||||||
log.info("surface cannot create new tab when not attached to a window", .{});
|
log.info("surface cannot create new tab when not attached to a window", .{});
|
||||||
|
@ -977,6 +977,28 @@ pub fn default(alloc_gpa: Allocator) Allocator.Error!Config {
|
|||||||
.{ .goto_split = .right },
|
.{ .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
|
// Viewport scrolling
|
||||||
try result.keybind.set.put(
|
try result.keybind.set.put(
|
||||||
alloc,
|
alloc,
|
||||||
|
Reference in New Issue
Block a user