apprt/gtk-ng: defineVirtualMethod helper
parent
1693c9a2ac
commit
675ba0e9b8
|
|
@ -1,6 +1,7 @@
|
||||||
//! This files contains all the GObject classes for the GTK apprt
|
//! This files contains all the GObject classes for the GTK apprt
|
||||||
//! along with helpers to work with them.
|
//! along with helpers to work with them.
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
const glib = @import("glib");
|
const glib = @import("glib");
|
||||||
const gobject = @import("gobject");
|
const gobject = @import("gobject");
|
||||||
const gtk = @import("gtk");
|
const gtk = @import("gtk");
|
||||||
|
|
@ -87,6 +88,77 @@ pub fn Common(
|
||||||
return @ptrCast(type_instance.f_g_class orelse return null);
|
return @ptrCast(type_instance.f_g_class orelse return null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Define a virtual method. The `Self.Class` type must have a field
|
||||||
|
/// named `name` which is a function pointer in the following form:
|
||||||
|
///
|
||||||
|
/// ?*const fn (*Self) callconv(.c) void
|
||||||
|
///
|
||||||
|
/// The virtual method may take additional parameters and specify
|
||||||
|
/// a non-void return type. The parameters and return type must be
|
||||||
|
/// valid for the C calling convention.
|
||||||
|
pub fn defineVirtualMethod(
|
||||||
|
comptime name: [:0]const u8,
|
||||||
|
) type {
|
||||||
|
return struct {
|
||||||
|
pub fn call(
|
||||||
|
class: anytype,
|
||||||
|
object: *ClassInstance(@TypeOf(class)),
|
||||||
|
params: anytype,
|
||||||
|
) (fn_info.return_type orelse void) {
|
||||||
|
const func = @field(
|
||||||
|
gobject.ext.as(Self.Class, class),
|
||||||
|
name,
|
||||||
|
).?;
|
||||||
|
@call(.auto, func, .{
|
||||||
|
gobject.ext.as(Self, object),
|
||||||
|
} ++ params);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn implement(
|
||||||
|
class: anytype,
|
||||||
|
implementation: *const ImplementFunc(@TypeOf(class)),
|
||||||
|
) void {
|
||||||
|
@field(gobject.ext.as(
|
||||||
|
Self.Class,
|
||||||
|
class,
|
||||||
|
), name) = @ptrCast(implementation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The type info of the virtual method.
|
||||||
|
const fn_info = fn_info: {
|
||||||
|
// This is broken down like this so its slightly more
|
||||||
|
// readable. We expect a field named "name" on the Class
|
||||||
|
// with the rough type of `?*const fn` and we need the
|
||||||
|
// function info.
|
||||||
|
const Field = @FieldType(Self.Class, name);
|
||||||
|
const opt = @typeInfo(Field).optional;
|
||||||
|
const ptr = @typeInfo(opt.child).pointer;
|
||||||
|
break :fn_info @typeInfo(ptr.child).@"fn";
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The instance type for a class.
|
||||||
|
fn ClassInstance(comptime T: type) type {
|
||||||
|
return @typeInfo(T).pointer.child.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The function type for implementations. This is the same type
|
||||||
|
/// as the virtual method but the self parameter points to the
|
||||||
|
/// target instead of the original class.
|
||||||
|
fn ImplementFunc(comptime T: type) type {
|
||||||
|
var params: [fn_info.params.len]std.builtin.Type.Fn.Param = undefined;
|
||||||
|
@memcpy(¶ms, fn_info.params);
|
||||||
|
params[0].type = *ClassInstance(T);
|
||||||
|
return @Type(.{ .@"fn" = .{
|
||||||
|
.calling_convention = fn_info.calling_convention,
|
||||||
|
.is_generic = fn_info.is_generic,
|
||||||
|
.is_var_args = fn_info.is_var_args,
|
||||||
|
.return_type = fn_info.return_type,
|
||||||
|
.params = ¶ms,
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// A helper that creates a property that reads and writes a
|
/// A helper that creates a property that reads and writes a
|
||||||
/// private field with only shallow copies. This is good for primitives
|
/// private field with only shallow copies. This is good for primitives
|
||||||
/// such as bools, numbers, etc.
|
/// such as bools, numbers, etc.
|
||||||
|
|
|
||||||
|
|
@ -41,28 +41,12 @@ pub const ImguiWidget = extern struct {
|
||||||
/// This virtual method will be called to allow the Dear ImGui
|
/// This virtual method will be called to allow the Dear ImGui
|
||||||
/// application to do one-time setup of the context. The correct context
|
/// application to do one-time setup of the context. The correct context
|
||||||
/// will be current when the virtual method is called.
|
/// will be current when the virtual method is called.
|
||||||
pub const setup = struct {
|
pub const setup = C.defineVirtualMethod("setup");
|
||||||
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
|
/// This virtual method will be called at each frame to allow the Dear
|
||||||
/// ImGui application to draw the application. The correct context will
|
/// ImGui application to draw the application. The correct context will
|
||||||
/// be current when the virtual method is called.
|
/// be current when the virtual method is called.
|
||||||
pub const render = struct {
|
pub const render = C.defineVirtualMethod("render");
|
||||||
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 {
|
const Private = struct {
|
||||||
|
|
@ -119,7 +103,7 @@ pub const ImguiWidget = extern struct {
|
||||||
/// when the virtual method is called.
|
/// when the virtual method is called.
|
||||||
pub fn setup(self: *Self) callconv(.c) void {
|
pub fn setup(self: *Self) callconv(.c) void {
|
||||||
const class = self.getClass() orelse return;
|
const class = self.getClass() orelse return;
|
||||||
virtual_methods.setup.call(class, self);
|
virtual_methods.setup.call(class, self, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This virtual method will be called at each frame to allow the Dear ImGui
|
/// This virtual method will be called at each frame to allow the Dear ImGui
|
||||||
|
|
@ -127,7 +111,7 @@ pub const ImguiWidget = extern struct {
|
||||||
/// when the virtual method is called.
|
/// when the virtual method is called.
|
||||||
pub fn render(self: *Self) callconv(.c) void {
|
pub fn render(self: *Self) callconv(.c) void {
|
||||||
const class = self.getClass() orelse return;
|
const class = self.getClass() orelse return;
|
||||||
virtual_methods.render.call(class, self);
|
virtual_methods.render.call(class, self, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue