From 5e789bf1522f90a24883e5ae2a3961f44c31916a Mon Sep 17 00:00:00 2001 From: Thorsten Ball Date: Tue, 24 Oct 2023 06:33:04 +0200 Subject: [PATCH] gtk: allow splitting when already split --- src/apprt/gtk/Paned.zig | 37 ++++++++++++++++++++++- src/apprt/gtk/Surface.zig | 63 ++++++++++++++++++++++++++++----------- 2 files changed, 81 insertions(+), 19 deletions(-) diff --git a/src/apprt/gtk/Paned.zig b/src/apprt/gtk/Paned.zig index af548b349..1c51f7cd8 100644 --- a/src/apprt/gtk/Paned.zig +++ b/src/apprt/gtk/Paned.zig @@ -56,8 +56,9 @@ pub fn init(self: *Paned, window: *Window, direction: input.SplitDirection, labe }; const paned = c.gtk_paned_new(orientation); - const gtk_paned: *c.GtkPaned = @ptrCast(paned); errdefer c.gtk_widget_destroy(paned); + + const gtk_paned: *c.GtkPaned = @ptrCast(paned); self.paned = gtk_paned; } @@ -80,6 +81,7 @@ pub fn newSurface(self: *Paned, tab: *Tab, parent_: ?*CoreSurface) !*Surface { const gl_area = c.gtk_gl_area_new(); c.gtk_widget_set_hexpand(gl_area, 1); c.gtk_widget_set_vexpand(gl_area, 1); + try surface.init(self.window.app, .{ .window = self.window, .tab = tab, @@ -91,9 +93,13 @@ pub fn newSurface(self: *Paned, tab: *Tab, parent_: ?*CoreSurface) !*Surface { .title_label = @ptrCast(self.label_text), .font_size = font_size, }); + return surface; } +pub fn setParent(self: *Paned, parent: Parent) void { + self.parent = parent; +} pub fn removeChildren(self: *Paned) void { assert(self.child1 != .none); assert(self.child2 != .none); @@ -103,6 +109,21 @@ pub fn removeChildren(self: *Paned) void { c.gtk_paned_set_end_child(@ptrCast(self.paned), null); } +pub fn removeChildInPosition(self: *Paned, position: Position) void { + switch (position) { + .start => { + assert(self.child1 != .none); + self.child1 = .none; + c.gtk_paned_set_start_child(@ptrCast(self.paned), null); + }, + .end => { + assert(self.child2 != .none); + self.child2 = .none; + c.gtk_paned_set_end_child(@ptrCast(self.paned), null); + }, + } +} + pub fn addChild1Surface(self: *Paned, surface: *Surface) void { assert(self.child1 == .none); self.child1 = Tab.Child{ .surface = surface }; @@ -117,6 +138,20 @@ pub fn addChild2Surface(self: *Paned, surface: *Surface) void { c.gtk_paned_set_end_child(@ptrCast(self.paned), @ptrCast(surface.gl_area)); } +pub fn addChild1Paned(self: *Paned, paned: *Paned) void { + assert(self.child1 == .none); + self.child1 = Tab.Child{ .paned = paned }; + paned.setParent(Parent{ .paned = .{ self, .start } }); + c.gtk_paned_set_start_child(@ptrCast(self.paned), @ptrCast(@alignCast(paned.paned))); +} + +pub fn addChild2Paned(self: *Paned, paned: *Paned) void { + assert(self.child2 == .none); + self.child2 = Tab.Child{ .paned = paned }; + paned.setParent(Parent{ .paned = .{ self, .end } }); + c.gtk_paned_set_end_child(@ptrCast(self.paned), @ptrCast(@alignCast(paned.paned))); +} + pub fn splitStartPosition(self: *Paned, orientation: c.GtkOrientation) !void { _ = orientation; _ = self; diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index 98f49f6c7..e63e6855f 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -349,11 +349,49 @@ pub fn toggleFullscreen(self: *Surface, mac_non_native: configpkg.NonNativeFulls pub fn newSplit(self: *Surface, direction: input.SplitDirection) !void { log.debug("new split, direction: {}", .{direction}); + // TODO: Refactor all of this! + switch (self.parent) { .none => return, - .paned => { - // TODO: Implement this - log.info("parent is paned", .{}); + .paned => |parent_paned_tuple| { + const label_text: *c.GtkWidget = switch (self.title) { + .none => return, + .label => |label| l: { + const widget = @as(*c.GtkWidget, @ptrCast(@alignCast(label))); + break :l widget; + }, + }; + + // Keep explicit reference to our gl_area before we remove ourselves. + const sibling_object: *c.GObject = @ptrCast(self.gl_area); + _ = c.g_object_ref(sibling_object); + defer c.g_object_unref(sibling_object); + + const parent_paned = parent_paned_tuple[0]; + const parent_position = parent_paned_tuple[1]; + + // Keep position of divider + const parent_paned_position_before = c.gtk_paned_get_position(parent_paned.paned); + // Now remove ourselves from parent + parent_paned.removeChildInPosition(parent_position); + + // Create new sibling + const paned = try Paned.create(self.app.core_app.alloc, self.window, direction, label_text); + const new_surface = try paned.newSurface(self.tab, &self.core_surface); + // This sets .parent on each surface + paned.addChild1Surface(self); + paned.addChild2Surface(new_surface); + + // Add new split-paned + switch (parent_position) { + .start => parent_paned.addChild1Paned(paned), + .end => parent_paned.addChild2Paned(paned), + } + // Restore position + c.gtk_paned_set_position(parent_paned.paned, parent_paned_position_before); + // Focus on new surface + const widget = @as(*c.GtkWidget, @ptrCast(new_surface.gl_area)); + _ = c.gtk_widget_grab_focus(widget); }, .tab => |tab| { const label_text: *c.GtkWidget = switch (self.title) { @@ -374,7 +412,7 @@ pub fn newSplit(self: *Surface, direction: input.SplitDirection) !void { tab.setChild(.{ .paned = paned }); - // FOCUS ON NEW SURFACE + // Focus on new surface const widget = @as(*c.GtkWidget, @ptrCast(new_surface.gl_area)); _ = c.gtk_widget_grab_focus(widget); }, @@ -793,20 +831,9 @@ fn gtkDestroy(v: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void { log.debug("gl destroy", .{}); const self = userdataSelf(ud.?); - switch (self.parent) { - .none, .tab => { - const alloc = self.app.core_app.alloc; - self.deinit(); - alloc.destroy(self); - }, - else => { - - // const alloc = self.app.core_app.alloc; - // self.deinit(); - // alloc.destroy(self); - log.debug("TODO: no destroy", .{}); - }, - } + const alloc = self.app.core_app.alloc; + self.deinit(); + alloc.destroy(self); } /// Scale x/y by the GDK device scale.