gtk-ng: use virtual methods to draw the inspector
Insead of signals between the ImGui widget and the Inspector widget, make the Inspector widget a subclass of the ImGui widget and use virtual methods to handle setup and rendering of the Inspector.pull/8237/head
parent
936577c581
commit
38e69b2e96
|
|
@ -53,6 +53,18 @@ pub fn Common(
|
|||
}
|
||||
}).private else {};
|
||||
|
||||
/// Get the class structure for the object.
|
||||
///
|
||||
/// This seems ugly and unsafe to me but this is what GObject is doing
|
||||
/// under the hood.
|
||||
///
|
||||
/// https://gitlab.gnome.org/GNOME/glib/-/blob/main/gobject/gtype.h?ref_type=heads#L555-571
|
||||
/// https://gitlab.gnome.org/GNOME/glib/-/blob/main/gobject/gtype.h?ref_type=heads#L2673
|
||||
pub fn getClass(self: *Self) ?*Self.Class {
|
||||
const type_instance: *gobject.TypeInstance = @ptrCast(self);
|
||||
return @ptrCast(type_instance.f_g_class orelse return null);
|
||||
}
|
||||
|
||||
/// A helper that creates a property that reads and writes a
|
||||
/// private field with only shallow copies. This is good for primitives
|
||||
/// such as bools, numbers, etc.
|
||||
|
|
|
|||
|
|
@ -67,6 +67,34 @@ pub const ImguiWidget = extern struct {
|
|||
};
|
||||
};
|
||||
|
||||
pub const virtual_methods = struct {
|
||||
/// This virtual method will be called to allow the Dear ImGui
|
||||
/// application to do one-time setup of the context. The correct context
|
||||
/// will be current when the virtual method is called.
|
||||
pub const setup = struct {
|
||||
pub fn call(class: anytype, object: *@typeInfo(@TypeOf(class)).pointer.child.Instance) void {
|
||||
return gobject.ext.as(Self.Class, class).setup.?(gobject.ext.as(Self, object));
|
||||
}
|
||||
|
||||
pub fn implement(class: anytype, implementation: *const fn (p_object: *@typeInfo(@TypeOf(class)).pointer.child.Instance) callconv(.c) void) void {
|
||||
gobject.ext.as(Self.Class, class).setup = @ptrCast(implementation);
|
||||
}
|
||||
};
|
||||
|
||||
/// This virtual method will be called at each frame to allow the Dear
|
||||
/// ImGui application to draw the application. The correct context will
|
||||
/// be current when the virtual method is called.
|
||||
pub const render = struct {
|
||||
pub fn call(class: anytype, object: *@typeInfo(@TypeOf(class)).pointer.child.Instance) void {
|
||||
return gobject.ext.as(Self.Class, class).render.?(gobject.ext.as(Self, object));
|
||||
}
|
||||
|
||||
pub fn implement(class: anytype, implementation: *const fn (p_object: *@typeInfo(@TypeOf(class)).pointer.child.Instance) callconv(.c) void) void {
|
||||
gobject.ext.as(Self.Class, class).render = @ptrCast(implementation);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const Private = struct {
|
||||
/// GL area where we display the Dear ImGui application.
|
||||
gl_area: *gtk.GLArea,
|
||||
|
|
@ -113,6 +141,25 @@ pub const ImguiWidget = extern struct {
|
|||
priv.gl_area.queueRender();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Public wrappers for virtual methods
|
||||
|
||||
/// This virtual method will be called to allow the Dear ImGui application
|
||||
/// to do one-time setup of the context. The correct context will be current
|
||||
/// when the virtual method is called.
|
||||
pub fn setup(self: *Self) callconv(.c) void {
|
||||
const class = self.getClass() orelse return;
|
||||
virtual_methods.setup.call(class, self);
|
||||
}
|
||||
|
||||
/// This virtual method will be called at each frame to allow the Dear ImGui
|
||||
/// application to draw the application. The correct context will be current
|
||||
/// when the virtual method is called.
|
||||
pub fn render(self: *Self) callconv(.c) void {
|
||||
const class = self.getClass() orelse return;
|
||||
virtual_methods.render.call(class, self);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Private Methods
|
||||
|
||||
|
|
@ -232,13 +279,8 @@ pub const ImguiWidget = extern struct {
|
|||
// initialize the ImgUI OpenGL backend for our context.
|
||||
_ = cimgui.ImGui_ImplOpenGL3_Init(null);
|
||||
|
||||
// Setup our app
|
||||
signals.setup.impl.emit(
|
||||
self,
|
||||
null,
|
||||
.{},
|
||||
null,
|
||||
);
|
||||
// Call the virtual method to setup the UI.
|
||||
self.setup();
|
||||
}
|
||||
|
||||
/// Handle a request to unrealize the GLArea
|
||||
|
|
@ -279,13 +321,8 @@ pub const ImguiWidget = extern struct {
|
|||
self.newFrame();
|
||||
cimgui.c.igNewFrame();
|
||||
|
||||
// Use the callback to draw the UI.
|
||||
signals.render.impl.emit(
|
||||
self,
|
||||
null,
|
||||
.{},
|
||||
null,
|
||||
);
|
||||
// Call the virtual method to draw the UI.
|
||||
self.render();
|
||||
|
||||
// Render
|
||||
cimgui.c.igRender();
|
||||
|
|
@ -422,15 +459,34 @@ pub const ImguiWidget = extern struct {
|
|||
cimgui.c.ImGuiIO_AddInputCharactersUTF8(io, bytes);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Default virtual method handlers
|
||||
|
||||
/// Default setup function. Does nothing but log a warning.
|
||||
fn defaultSetup(_: *Self) callconv(.c) void {
|
||||
log.warn("default Dear ImGui setup called, this is a bug.", .{});
|
||||
}
|
||||
|
||||
/// Default render function. Does nothing but log a warning.
|
||||
fn defaultRender(_: *Self) callconv(.c) void {
|
||||
log.warn("default Dear ImGui render called, this is a bug.", .{});
|
||||
}
|
||||
|
||||
const C = Common(Self, Private);
|
||||
pub const as = C.as;
|
||||
pub const ref = C.ref;
|
||||
pub const refSink = C.refSink;
|
||||
pub const unref = C.unref;
|
||||
pub const getClass = C.getClass;
|
||||
const private = C.private;
|
||||
|
||||
pub const Class = extern struct {
|
||||
parent_class: Parent.Class,
|
||||
|
||||
/// Function pointers for virtual methods.
|
||||
setup: ?*const fn (*Self) callconv(.c) void = null,
|
||||
render: ?*const fn (*Self) callconv(.c) void = null,
|
||||
|
||||
var parent: *Parent.Class = undefined;
|
||||
pub const Instance = Self;
|
||||
|
||||
|
|
@ -444,6 +500,10 @@ pub const ImguiWidget = extern struct {
|
|||
}),
|
||||
);
|
||||
|
||||
// Initialize our virtual methods with default functions.
|
||||
class.setup = defaultSetup;
|
||||
class.render = defaultRender;
|
||||
|
||||
// Bindings
|
||||
class.bindTemplateChildPrivate("gl_area", .{});
|
||||
class.bindTemplateChildPrivate("im_context", .{});
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const log = std.log.scoped(.gtk_ghostty_inspector_widget);
|
|||
pub const InspectorWidget = extern struct {
|
||||
const Self = @This();
|
||||
parent_instance: Parent,
|
||||
pub const Parent = adw.Bin;
|
||||
pub const Parent = ImguiWidget;
|
||||
pub const getGObjectType = gobject.ext.defineClass(Self, .{
|
||||
.name = "GhosttyInspectorWidget",
|
||||
.instanceInit = &init,
|
||||
|
|
@ -50,9 +50,6 @@ pub const InspectorWidget = extern struct {
|
|||
/// We attach a weak notify to the object.
|
||||
surface: ?*Surface = null,
|
||||
|
||||
/// The embedded Dear ImGui widget.
|
||||
imgui_widget: *ImguiWidget,
|
||||
|
||||
pub var offset: c_int = 0;
|
||||
};
|
||||
|
||||
|
|
@ -78,13 +75,30 @@ pub const InspectorWidget = extern struct {
|
|||
);
|
||||
}
|
||||
|
||||
/// Called to do initial setup of the UI.
|
||||
fn imguiSetup(
|
||||
_: *Self,
|
||||
) callconv(.c) void {
|
||||
Inspector.setup();
|
||||
}
|
||||
|
||||
/// Called for every frame to draw the UI.
|
||||
fn imguiRender(
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
const priv = self.private();
|
||||
const surface = priv.surface orelse return;
|
||||
const core_surface = surface.core() orelse return;
|
||||
const inspector = core_surface.inspector orelse return;
|
||||
inspector.render();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/// Queue a render of the Dear ImGui widget.
|
||||
pub fn queueRender(self: *Self) void {
|
||||
const priv = self.private();
|
||||
priv.imgui_widget.queueRender();
|
||||
self.as(ImguiWidget).queueRender();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
|
|
@ -189,24 +203,6 @@ pub const InspectorWidget = extern struct {
|
|||
// for completeness sake we should clean this up.
|
||||
}
|
||||
|
||||
fn imguiRender(
|
||||
_: *ImguiWidget,
|
||||
self: *Self,
|
||||
) callconv(.c) void {
|
||||
const priv = self.private();
|
||||
const surface = priv.surface orelse return;
|
||||
const core_surface = surface.core() orelse return;
|
||||
const inspector = core_surface.inspector orelse return;
|
||||
inspector.render();
|
||||
}
|
||||
|
||||
fn imguiSetup(
|
||||
_: *ImguiWidget,
|
||||
_: *Self,
|
||||
) callconv(.c) void {
|
||||
Inspector.setup();
|
||||
}
|
||||
|
||||
const C = Common(Self, Private);
|
||||
pub const as = C.as;
|
||||
pub const ref = C.ref;
|
||||
|
|
@ -230,13 +226,6 @@ pub const InspectorWidget = extern struct {
|
|||
}),
|
||||
);
|
||||
|
||||
// Bindings
|
||||
class.bindTemplateChildPrivate("imgui_widget", .{});
|
||||
|
||||
// Template callbacks
|
||||
class.bindTemplateCallback("imgui_render", &imguiRender);
|
||||
class.bindTemplateCallback("imgui_setup", &imguiSetup);
|
||||
|
||||
// Properties
|
||||
gobject.ext.registerProperties(class, &.{
|
||||
properties.surface.impl,
|
||||
|
|
@ -245,6 +234,8 @@ pub const InspectorWidget = extern struct {
|
|||
// Signals
|
||||
|
||||
// Virtual methods
|
||||
ImguiWidget.virtual_methods.setup.implement(class, imguiSetup);
|
||||
ImguiWidget.virtual_methods.render.implement(class, imguiRender);
|
||||
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,10 @@
|
|||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $GhosttyInspectorWidget: Adw.Bin {
|
||||
template $GhosttyInspectorWidget: $GhosttyImguiWidget {
|
||||
styles [
|
||||
"inspector",
|
||||
]
|
||||
|
||||
hexpand: true;
|
||||
vexpand: true;
|
||||
|
||||
Adw.Bin {
|
||||
$GhosttyImguiWidget imgui_widget {
|
||||
render => $imgui_render();
|
||||
setup => $imgui_setup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue