import { property, register } from 'astal'; import { Gtk, hook } from 'astal/gtk4'; import { type Connectable, type Subscribable } from 'astal/binding'; import construct from './construct'; import setupControllers from './controller'; import { type BindableProps, dummyBuilder, type MixinParams, noImplicitDestroy, setChildren, childType, } from './generics'; export default < C extends new (...props: MixinParams) => Gtk.Widget, ConstructorProps, >( cls: C, clsName = cls.name, ) => { @register({ GTypeName: `RealClass_${clsName}` }) class Widget extends cls { declare private _css: string | undefined; declare private _provider: Gtk.CssProvider | undefined; @property(String) get css(): string | undefined { return this._css; } set css(value: string) { if (!this._provider) { this._provider = new Gtk.CssProvider(); this.get_style_context().add_provider( this._provider, Gtk.STYLE_PROVIDER_PRIORITY_USER, ); } this._css = value; this._provider.load_from_string(value); } declare private [childType]: string; @property(String) get type(): string { return this[childType]; } set type(value: string) { this[childType] = value; } @property(Object) get children(): Gtk.Widget[] { return this.getChildren(this); } set children(value: Gtk.Widget[]) { this.setChildren(this, value); } declare private [noImplicitDestroy]: boolean; @property(String) get noImplicitDestroy(): boolean { return this[noImplicitDestroy]; } set noImplicitDestroy(value: boolean) { this[noImplicitDestroy] = value; } protected getChildren(widget: Gtk.Widget): Gtk.Widget[] { if ('get_child' in widget && typeof widget.get_child == 'function') { return widget.get_child() ? [widget.get_child()] : []; } const children: Gtk.Widget[] = []; let ch = widget.get_first_child(); while (ch !== null) { children.push(ch); ch = ch.get_next_sibling(); } return children; } protected setChildren(widget: Gtk.Widget, children: Gtk.Widget[]) { for (const child of children) { widget.vfunc_add_child( dummyBuilder, child, childType in widget ? widget[childType] as string : null, ); } } [setChildren](children: Gtk.Widget[]) { for (const child of (this.getChildren(this))) { child?.unparent(); if (!children.includes(child) && noImplicitDestroy in this) { child.run_dispose(); } } this.setChildren(this, children); } hook( object: Connectable, signal: string, callback: (self: this, ...args: unknown[]) => void, ): this; hook( object: Subscribable, callback: (self: this, ...args: unknown[]) => void, ): this; hook( object: Connectable | Subscribable, signalOrCallback: string | ((self: this, ...args: unknown[]) => void), callback?: (self: this, ...args: unknown[]) => void, ) { hook(this, object, signalOrCallback, callback); return this; } constructor(...params: MixinParams) { const props = params[0] || {}; super('cssName' in props ? { cssName: props.cssName } : {}); if ('cssName' in props) { delete props.cssName; } if (props.noImplicitDestroy) { this.noImplicitDestroy = true; delete props.noImplicitDestroy; } if (props.type) { this.type = props.type; delete props.type; } construct(this, setupControllers(this, props)); } } type Constructor = new (...args: Props[]) => Instance; type WidgetClass = Constructor< Widget & Gtk.Widget & InstanceType, Partial> >; // override the parameters of the `super` constructor return Widget as unknown as WidgetClass; };