apprt/gtk-ng: render a single artificial split
parent
70b050ebb4
commit
a7865d79ea
|
|
@ -66,16 +66,39 @@ pub const SplitTree = extern struct {
|
||||||
.{
|
.{
|
||||||
.nick = "Tree Model",
|
.nick = "Tree Model",
|
||||||
.blurb = "Underlying data model for the tree.",
|
.blurb = "Underlying data model for the tree.",
|
||||||
.accessor = C.privateBoxedFieldAccessor("tree"),
|
.accessor = .{
|
||||||
|
.getter = getTreeValue,
|
||||||
|
.setter = setTreeValue,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const signals = struct {
|
||||||
|
/// Emitted whenever the tree property is about to change.
|
||||||
|
///
|
||||||
|
/// The new value is given as the signal parameter. The old value
|
||||||
|
/// can still be retrieved from the tree property.
|
||||||
|
pub const @"tree-will-change" = struct {
|
||||||
|
pub const name = "tree-change";
|
||||||
|
pub const connect = impl.connect;
|
||||||
|
const impl = gobject.ext.defineSignal(
|
||||||
|
name,
|
||||||
|
Self,
|
||||||
|
&.{?*const Surface.Tree},
|
||||||
|
void,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const Private = struct {
|
const Private = struct {
|
||||||
/// The tree datastructure containing all of our surface views.
|
/// The tree datastructure containing all of our surface views.
|
||||||
tree: ?*Surface.Tree,
|
tree: ?*Surface.Tree,
|
||||||
|
|
||||||
|
// Template bindings
|
||||||
|
tree_bin: *adw.Bin,
|
||||||
|
|
||||||
pub var offset: c_int = 0;
|
pub var offset: c_int = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -91,6 +114,52 @@ pub const SplitTree = extern struct {
|
||||||
return tree.isEmpty();
|
return tree.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the tree data model that we're showing in this widget. This
|
||||||
|
/// does not clone the tree.
|
||||||
|
pub fn getTree(self: *Self) ?*Surface.Tree {
|
||||||
|
return self.private().tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the tree data model that we're showing in this widget. This
|
||||||
|
/// will clone the given tree.
|
||||||
|
pub fn setTree(self: *Self, tree: ?*const Surface.Tree) void {
|
||||||
|
const priv = self.private();
|
||||||
|
|
||||||
|
// Emit the signal so that handlers can witness both the before and
|
||||||
|
// after values of the tree.
|
||||||
|
signals.@"tree-will-change".impl.emit(
|
||||||
|
self,
|
||||||
|
null,
|
||||||
|
.{tree},
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (priv.tree) |old_tree| {
|
||||||
|
ext.boxedFree(Surface.Tree, old_tree);
|
||||||
|
priv.tree = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree) |new_tree| {
|
||||||
|
priv.tree = ext.boxedCopy(Surface.Tree, new_tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.as(gobject.Object).notifyByPspec(properties.tree.impl.param_spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getTreeValue(self: *Self, value: *gobject.Value) void {
|
||||||
|
gobject.ext.Value.set(
|
||||||
|
value,
|
||||||
|
self.private().tree,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setTreeValue(self: *Self, value: *const gobject.Value) void {
|
||||||
|
self.setTree(gobject.ext.Value.get(
|
||||||
|
value,
|
||||||
|
?*Surface.Tree,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Virtual methods
|
// Virtual methods
|
||||||
|
|
||||||
|
|
@ -127,9 +196,48 @@ pub const SplitTree = extern struct {
|
||||||
_: *gobject.ParamSpec,
|
_: *gobject.ParamSpec,
|
||||||
_: ?*anyopaque,
|
_: ?*anyopaque,
|
||||||
) callconv(.c) void {
|
) callconv(.c) void {
|
||||||
|
const priv = self.private();
|
||||||
|
const tree: *const Surface.Tree = self.private().tree orelse &.empty;
|
||||||
|
|
||||||
|
// Reset our widget tree.
|
||||||
|
priv.tree_bin.setChild(null);
|
||||||
|
if (!tree.isEmpty()) {
|
||||||
|
priv.tree_bin.setChild(buildTree(tree, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dependent properties
|
||||||
self.as(gobject.Object).notifyByPspec(properties.@"is-empty".impl.param_spec);
|
self.as(gobject.Object).notifyByPspec(properties.@"is-empty".impl.param_spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds the widget tree associated with a surface split tree.
|
||||||
|
///
|
||||||
|
/// The final returned widget is expected to be a floating reference,
|
||||||
|
/// ready to be attached to a parent widget.
|
||||||
|
fn buildTree(
|
||||||
|
tree: *const Surface.Tree,
|
||||||
|
current: Surface.Tree.Node.Handle,
|
||||||
|
) *gtk.Widget {
|
||||||
|
switch (tree.nodes[current]) {
|
||||||
|
.leaf => |v| {
|
||||||
|
// We have to setup our signal handlers.
|
||||||
|
return v.as(gtk.Widget);
|
||||||
|
},
|
||||||
|
|
||||||
|
.split => |s| return gobject.ext.newInstance(
|
||||||
|
gtk.Paned,
|
||||||
|
.{
|
||||||
|
.orientation = @as(gtk.Orientation, switch (s.layout) {
|
||||||
|
.horizontal => .horizontal,
|
||||||
|
.vertical => .vertical,
|
||||||
|
}),
|
||||||
|
.@"start-child" = buildTree(tree, s.left),
|
||||||
|
.@"end-child" = buildTree(tree, s.right),
|
||||||
|
// TODO: position/ratio
|
||||||
|
},
|
||||||
|
).as(gtk.Widget),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Class
|
// Class
|
||||||
|
|
||||||
|
|
@ -162,11 +270,13 @@ pub const SplitTree = extern struct {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Bindings
|
// Bindings
|
||||||
|
class.bindTemplateChildPrivate("tree_bin", .{});
|
||||||
|
|
||||||
// Template Callbacks
|
// Template Callbacks
|
||||||
class.bindTemplateCallback("notify_tree", &propTree);
|
class.bindTemplateCallback("notify_tree", &propTree);
|
||||||
|
|
||||||
// Signals
|
// Signals
|
||||||
|
signals.@"tree-will-change".impl.register(.{});
|
||||||
|
|
||||||
// Virtual methods
|
// Virtual methods
|
||||||
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
|
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
|
||||||
|
|
|
||||||
|
|
@ -2302,6 +2302,7 @@ pub const Surface = extern struct {
|
||||||
const C = Common(Self, Private);
|
const C = Common(Self, Private);
|
||||||
pub const as = C.as;
|
pub const as = C.as;
|
||||||
pub const ref = C.ref;
|
pub const ref = C.ref;
|
||||||
|
pub const refSink = C.refSink;
|
||||||
pub const unref = C.unref;
|
pub const unref = C.unref;
|
||||||
const private = C.private;
|
const private = C.private;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,7 @@ pub const Tab = extern struct {
|
||||||
surface_bindings: *gobject.BindingGroup,
|
surface_bindings: *gobject.BindingGroup,
|
||||||
|
|
||||||
// Template bindings
|
// Template bindings
|
||||||
|
split_tree: *SplitTree,
|
||||||
surface: *Surface,
|
surface: *Surface,
|
||||||
|
|
||||||
pub var offset: c_int = 0;
|
pub var offset: c_int = 0;
|
||||||
|
|
@ -161,6 +162,16 @@ pub const Tab = extern struct {
|
||||||
// We need to do this so that the title initializes properly,
|
// We need to do this so that the title initializes properly,
|
||||||
// I think because its a dynamic getter.
|
// I think because its a dynamic getter.
|
||||||
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
|
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
|
||||||
|
|
||||||
|
// Setup our initial split tree.
|
||||||
|
// TODO: Probably make this a property
|
||||||
|
const surface: *Surface = .new();
|
||||||
|
defer surface.unref();
|
||||||
|
_ = surface.refSink();
|
||||||
|
const alloc = Application.default().allocator();
|
||||||
|
var tree = Surface.Tree.init(alloc, surface) catch unreachable;
|
||||||
|
defer tree.deinit();
|
||||||
|
priv.split_tree.setTree(&tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
|
@ -271,6 +282,7 @@ pub const Tab = extern struct {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Bindings
|
// Bindings
|
||||||
|
class.bindTemplateChildPrivate("split_tree", .{});
|
||||||
class.bindTemplateChildPrivate("surface", .{});
|
class.bindTemplateChildPrivate("surface", .{});
|
||||||
|
|
||||||
// Template Callbacks
|
// Template Callbacks
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,8 @@ template $GhosttySplitTree: Adw.Bin {
|
||||||
Box {
|
Box {
|
||||||
orientation: vertical;
|
orientation: vertical;
|
||||||
|
|
||||||
Box surface_box {
|
Adw.Bin tree_bin {
|
||||||
visible: bind template.is-empty inverted;
|
visible: bind template.is-empty inverted;
|
||||||
orientation: vertical;
|
|
||||||
hexpand: true;
|
hexpand: true;
|
||||||
vexpand: true;
|
vexpand: true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,5 @@ template $GhosttyTab: Box {
|
||||||
close-request => $surface_close_request();
|
close-request => $surface_close_request();
|
||||||
}
|
}
|
||||||
|
|
||||||
$GhosttySplitTree {}
|
$GhosttySplitTree split_tree {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue