diff options
author | Aylur <[email protected]> | 2024-06-09 22:25:40 +0200 |
---|---|---|
committer | Aylur <[email protected]> | 2024-06-09 22:25:40 +0200 |
commit | 41cb376a02d12f85eb1e4893425af15614c2e187 (patch) | |
tree | e5d684784c4a3782adbbaad7e6597d3dafd8bb6f /gjs/src | |
parent | 15285a17bf447c5185dfbb92d9a4bd2670a4e44e (diff) |
support deeply nested layout structures
js, jsx, lua now allows deeply nested layouts that contains Bindings
Variable.derive will be automatically constructed where needed
and Bindings in layouts will be bound automatically
it breaks compatibility with ags even more, but jsx should be preferred
imo anyway
Diffstat (limited to 'gjs/src')
-rw-r--r-- | gjs/src/astalify.ts | 100 | ||||
-rw-r--r-- | gjs/src/jsx/jsx-runtime.ts | 51 |
2 files changed, 75 insertions, 76 deletions
diff --git a/gjs/src/astalify.ts b/gjs/src/astalify.ts index f986716..ecd52d4 100644 --- a/gjs/src/astalify.ts +++ b/gjs/src/astalify.ts @@ -1,12 +1,61 @@ import Binding, { kebabify, snakeify, type Connectable, type Subscribable } from "./binding.js" import { Astal, Gtk } from "./imports.js" import { execAsync } from "./process.js" +import Variable from "./variable.js" Object.defineProperty(Astal.Box.prototype, "children", { get() { return this.get_children() }, set(v) { this.set_children(v) }, }) +function setChildren(parent: Gtk.Widget, children: Gtk.Widget[]) { + children = children.flat(Infinity).map(ch => ch instanceof Gtk.Widget + ? ch + : new Gtk.Label({ visible: true, label: String(ch) })) + + // remove + if (parent instanceof Gtk.Bin) { + const ch = parent.get_child() + if (ch) + parent.remove(ch) + } + + // FIXME: add rest of the edge cases like Stack + if (parent instanceof Astal.Box) { + parent.set_children(children) + } + + else if (parent instanceof Astal.CenterBox) { + parent.startWidget = children[0] + parent.centerWidget = children[1] + parent.endWidget = children[2] + } + + else if (parent instanceof Astal.Overlay) { + const [child, ...overlays] = children + parent.set_child(child) + parent.set_overlays(overlays) + } + + else if (parent instanceof Gtk.Container) { + for (const ch of children) + parent.add(ch) + } +} + +function mergeBindings(array: any[]) { + const getValues = () => array.map(i => i instanceof Binding ? i.get() : i) + const bindings = array.filter(i => i instanceof Binding) + + if (bindings.length === 0) + return array + + if (bindings.length === 1) + return bindings[0].as(getValues) + + return Variable.derive(bindings, getValues)() +} + export type Widget<C extends { new(...args: any): Gtk.Widget }> = InstanceType<C> & { className: string css: string @@ -47,7 +96,7 @@ function hook( return self } -function ctor(self: any, config: any = {}, ...children: Gtk.Widget[]) { +function ctor(self: any, config: any = {}, children: any[] = []) { const { setup, ...props } = config props.visible ??= true @@ -71,9 +120,6 @@ function ctor(self: any, config: any = {}, ...children: Gtk.Widget[]) { return acc }, []) - const pchildren = props.children - delete props.children - Object.assign(self, props) Object.assign(self, { hook(obj: any, sig: any, callback: any) { @@ -91,23 +137,28 @@ function ctor(self: any, config: any = {}, ...children: Gtk.Widget[]) { } } - if (self instanceof Gtk.Container) { - if (children) { - for (const child of children) - self.add(child) - } - if (pchildren && Array.isArray(pchildren)) { - for (const child of pchildren) - self.add(child) - } - } - for (const [prop, bind] of bindings) { + if (prop === "child" || prop === "children") { + self.connect("destroy", bind.subscribe((v: any) => { + setChildren(self, v) + })) + } self.connect("destroy", bind.subscribe((v: any) => { self[`set_${snakeify(prop)}`](v) })) } + children = mergeBindings(children.flat(Infinity)) + if (children instanceof Binding) { + setChildren(self, children.get()) + self.connect("destroy", children.subscribe(v => { + setChildren(self, v) + })) + } + else { + setChildren(self, children) + } + setup?.(self) return self } @@ -130,29 +181,14 @@ function proxify< set(v) { Astal.widget_set_cursor(this, v) }, }) - klass.prototype.set_child = function(widget: Gtk.Widget) { - if (this instanceof Gtk.Bin) { - const rm = this.get_child() - if (rm) - this.remove(rm) - } - if (this instanceof Gtk.Container) - this.add(widget) - } - - Object.defineProperty(klass.prototype, "child", { - get() { return this.get_child?.() }, - set(v) { this.set_child(v) }, - }) - const proxy = new Proxy(klass, { construct(_, [conf, ...children]) { const self = new klass - return ctor(self, conf, ...children) + return ctor(self, conf, children) }, apply(_t, _a, [conf, ...children]) { const self = new klass - return ctor(self, conf, ...children) + return ctor(self, conf, children) }, }) diff --git a/gjs/src/jsx/jsx-runtime.ts b/gjs/src/jsx/jsx-runtime.ts index 5e7f23b..e96f7c2 100644 --- a/gjs/src/jsx/jsx-runtime.ts +++ b/gjs/src/jsx/jsx-runtime.ts @@ -1,12 +1,5 @@ import { Gtk } from "../imports.js" import * as Widget from "../widgets.js" -import Binding from "../binding.js" - -function w(e: any) { - return e instanceof Gtk.Widget || e instanceof Binding - ? e - : Widget.Label({ label: String(e) }) -} export function jsx( ctor: keyof typeof ctors | typeof Gtk.Widget, @@ -16,46 +9,16 @@ export function jsx( if (!Array.isArray(children)) children = [children] - else - children = children.flat() - - // <box children={Binding} /> and <box>{Binding}</box> - if (ctor === "box" && children.length === 1 && children[0] instanceof Binding) { - props.children = children[0] - } - - // TODO: handle array of Binding - // is there a usecase? - - else if (ctor === "centerbox") { - if (children[0]) - props.startWidget = w(children[0]) - if (children[1]) - props.centerWidget = w(children[1]) - if (children[2]) - props.endWidget = w(children[2]) - } - - else if (ctor === "overlay") { - const [child, ...overlays] = children - if (child) - props.child = child - - props.overlays = overlays - } - else if (children.length === 1) { - props.child = w(children[0]) - delete props.children - } + if (typeof ctor === "string") + return (ctors as any)[ctor](props, children) - else { - props.children = children.map(w) - } + if (children.length === 1) + props.child = children[0] + else if (children.length > 1) + props.children = children - return typeof ctor === "string" - ? (ctors as any)[ctor](props) - : new ctor(props) + return new ctor(props) } const ctors = { |