summaryrefslogtreecommitdiff
path: root/core/gjs/src/astalify.ts
diff options
context:
space:
mode:
authorAylur <[email protected]>2024-10-15 15:30:04 +0200
committerGitHub <[email protected]>2024-10-15 15:30:04 +0200
commitcbe650afb31c24faea6da45b4aeeffc6e964969d (patch)
treed5c3788835ca7e50d68cd023026e7738f39f6f71 /core/gjs/src/astalify.ts
parentbdb23e20f171da7c769cba9e393d7e406e563a78 (diff)
parentbafd48d3df9b43a1d49ec015eff30619d595468b (diff)
Merge pull request #46 from Aylur/small-refactor
Small refactor
Diffstat (limited to 'core/gjs/src/astalify.ts')
-rw-r--r--core/gjs/src/astalify.ts322
1 files changed, 0 insertions, 322 deletions
diff --git a/core/gjs/src/astalify.ts b/core/gjs/src/astalify.ts
deleted file mode 100644
index c4cbc5c..0000000
--- a/core/gjs/src/astalify.ts
+++ /dev/null
@@ -1,322 +0,0 @@
-import Binding, { kebabify, snakeify, type Connectable, type Subscribable } from "./binding.js"
-import { Astal, Gtk, Gdk, GObject } from "./imports.js"
-import { execAsync } from "./process.js"
-import Variable from "./variable.js"
-
-function mergeBindings(array: any[]) {
- function getValues(...args: any[]) {
- let i = 0
- return array.map(value => value instanceof Binding
- ? args[i++]
- : value,
- )
- }
-
- 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)()
-}
-
-function setProp(obj: any, prop: string, value: any) {
- try {
- // the setter method has to be used because
- // array like properties are not bound correctly as props
- const setter = `set_${snakeify(prop)}`
- if (typeof obj[setter] === "function")
- return obj[setter](value)
-
- return (obj[prop] = value)
- }
- catch (error) {
- console.error(`could not set property "${prop}" on ${obj}:`, error)
- }
-}
-
-export default function astalify<
- C extends { new(...args: any[]): Gtk.Widget },
->(cls: C) {
- class Widget extends cls {
- get css(): string { return Astal.widget_get_css(this) }
- set css(css: string) { Astal.widget_set_css(this, css) }
- get_css(): string { return this.css }
- set_css(css: string) { this.css = css }
-
- get className(): string { return Astal.widget_get_class_names(this).join(" ") }
- set className(className: string) { Astal.widget_set_class_names(this, className.split(/\s+/)) }
- get_class_name(): string { return this.className }
- set_class_name(className: string) { this.className = className }
-
- get cursor(): Cursor { return Astal.widget_get_cursor(this) as Cursor }
- set cursor(cursor: Cursor) { Astal.widget_set_cursor(this, cursor) }
- get_cursor(): Cursor { return this.cursor }
- set_cursor(cursor: Cursor) { this.cursor = cursor }
-
- get clickThrough(): boolean { return Astal.widget_get_click_through(this) }
- set clickThrough(clickThrough: boolean) { Astal.widget_set_click_through(this, clickThrough) }
- get_click_through(): boolean { return this.clickThrough }
- set_click_through(clickThrough: boolean) { this.clickThrough = clickThrough }
-
- declare __no_implicit_destroy: boolean
- get noImplicitDestroy(): boolean { return this.__no_implicit_destroy }
- set noImplicitDestroy(value: boolean) { this.__no_implicit_destroy = value }
-
- _setChildren(children: Gtk.Widget[]) {
- children = children.flat(Infinity).map(ch => ch instanceof Gtk.Widget
- ? ch
- : new Gtk.Label({ visible: true, label: String(ch) }))
-
- // remove
- if (this instanceof Gtk.Bin) {
- const ch = this.get_child()
- if (ch)
- this.remove(ch)
- if (ch && !children.includes(ch) && !this.noImplicitDestroy)
- ch?.destroy()
- }
- else if (this instanceof Gtk.Container) {
- for (const ch of this.get_children()) {
- this.remove(ch)
- if (!children.includes(ch) && !this.noImplicitDestroy)
- ch?.destroy()
- }
- }
-
- // TODO: add more container types
- if (this instanceof Astal.Box) {
- this.set_children(children)
- }
-
- else if (this instanceof Astal.Stack) {
- this.set_children(children)
- }
-
- else if (this instanceof Astal.CenterBox) {
- this.startWidget = children[0]
- this.centerWidget = children[1]
- this.endWidget = children[2]
- }
-
- else if (this instanceof Astal.Overlay) {
- const [child, ...overlays] = children
- this.set_child(child)
- this.set_overlays(overlays)
- }
-
- else if (this instanceof Gtk.Container) {
- for (const ch of children)
- this.add(ch)
- }
- }
-
- toggleClassName(cn: string, cond = true) {
- Astal.widget_toggle_class_name(this, cn, cond)
- }
-
- hook(
- object: Connectable,
- signal: string,
- callback: (self: this, ...args: any[]) => void,
- ): this
- hook(
- object: Subscribable,
- callback: (self: this, ...args: any[]) => void,
- ): this
- hook(
- object: Connectable | Subscribable,
- signalOrCallback: string | ((self: this, ...args: any[]) => void),
- callback?: (self: this, ...args: any[]) => void,
- ) {
- if (typeof object.connect === "function" && callback) {
- const id = object.connect(signalOrCallback, (_: any, ...args: unknown[]) => {
- callback(this, ...args)
- })
- this.connect("destroy", () => {
- (object.disconnect as Connectable["disconnect"])(id)
- })
- }
-
- else if (typeof object.subscribe === "function" && typeof signalOrCallback === "function") {
- const unsub = object.subscribe((...args: unknown[]) => {
- signalOrCallback(this, ...args)
- })
- this.connect("destroy", unsub)
- }
-
- return this
- }
-
- constructor(...params: any[]) {
- super()
- const [config] = params
-
- const { setup, child, children = [], ...props } = config
- props.visible ??= true
-
- if (child)
- children.unshift(child)
-
- // collect bindings
- const bindings = Object.keys(props).reduce((acc: any, prop) => {
- if (props[prop] instanceof Binding) {
- const binding = props[prop]
- delete props[prop]
- return [...acc, [prop, binding]]
- }
- return acc
- }, [])
-
- // collect signal handlers
- const onHandlers = Object.keys(props).reduce((acc: any, key) => {
- if (key.startsWith("on")) {
- const sig = kebabify(key).split("-").slice(1).join("-")
- const handler = props[key]
- delete props[key]
- return [...acc, [sig, handler]]
- }
- return acc
- }, [])
-
- // set children
- const mergedChildren = mergeBindings(children.flat(Infinity))
- if (mergedChildren instanceof Binding) {
- this._setChildren(mergedChildren.get())
- this.connect("destroy", mergedChildren.subscribe((v) => {
- this._setChildren(v)
- }))
- }
- else {
- if (mergedChildren.length > 0) {
- this._setChildren(mergedChildren)
- }
- }
-
- // setup signal handlers
- for (const [signal, callback] of onHandlers) {
- if (typeof callback === "function") {
- this.connect(signal, callback)
- }
- else {
- this.connect(signal, () => execAsync(callback)
- .then(print).catch(console.error))
- }
- }
-
- // setup bindings handlers
- for (const [prop, binding] of bindings) {
- if (prop === "child" || prop === "children") {
- this.connect("destroy", binding.subscribe((v: any) => {
- this._setChildren(v)
- }))
- }
- this.connect("destroy", binding.subscribe((v: any) => {
- setProp(this, prop, v)
- }))
- setProp(this, prop, binding.get())
- }
-
- Object.assign(this, props)
- setup?.(this)
- }
- }
-
- GObject.registerClass({
- GTypeName: `Astal_${cls.name}`,
- Properties: {
- "class-name": GObject.ParamSpec.string(
- "class-name", "", "", GObject.ParamFlags.READWRITE, "",
- ),
- "css": GObject.ParamSpec.string(
- "css", "", "", GObject.ParamFlags.READWRITE, "",
- ),
- "cursor": GObject.ParamSpec.string(
- "cursor", "", "", GObject.ParamFlags.READWRITE, "default",
- ),
- "click-through": GObject.ParamSpec.boolean(
- "click-through", "", "", GObject.ParamFlags.READWRITE, false,
- ),
- "no-implicit-destroy": GObject.ParamSpec.boolean(
- "no-implicit-destroy", "", "", GObject.ParamFlags.READWRITE, false,
- ),
- },
- }, Widget)
-
- return Widget
-}
-
-type BindableProps<T> = {
- [K in keyof T]: Binding<T[K]> | T[K];
-}
-
-type SigHandler<
- W extends InstanceType<typeof Gtk.Widget>,
- Args extends Array<unknown>,
-> = ((self: W, ...args: Args) => unknown) | string | string[]
-
-export type ConstructProps<
- Self extends InstanceType<typeof Gtk.Widget>,
- Props extends Gtk.Widget.ConstructorProps,
- Signals extends Record<`on${string}`, Array<unknown>> = Record<`on${string}`, any[]>,
-> = Partial<{
- // @ts-expect-error can't assign to unknown, but it works as expected though
- [S in keyof Signals]: SigHandler<Self, Signals[S]>
-}> & Partial<{
- [Key in `on${string}`]: SigHandler<Self, any[]>
-}> & BindableProps<Partial<Props> & {
- className?: string
- css?: string
- cursor?: string
- clickThrough?: boolean
-}> & {
- onDestroy?: (self: Self) => unknown
- onDraw?: (self: Self) => unknown
- onKeyPressEvent?: (self: Self, event: Gdk.Event) => unknown
- onKeyReleaseEvent?: (self: Self, event: Gdk.Event) => unknown
- onButtonPressEvent?: (self: Self, event: Gdk.Event) => unknown
- onButtonReleaseEvent?: (self: Self, event: Gdk.Event) => unknown
- onRealize?: (self: Self) => unknown
- setup?: (self: Self) => void
-}
-
-export type BindableChild = Gtk.Widget | Binding<Gtk.Widget>
-
-type Cursor =
- | "default"
- | "help"
- | "pointer"
- | "context-menu"
- | "progress"
- | "wait"
- | "cell"
- | "crosshair"
- | "text"
- | "vertical-text"
- | "alias"
- | "copy"
- | "no-drop"
- | "move"
- | "not-allowed"
- | "grab"
- | "grabbing"
- | "all-scroll"
- | "col-resize"
- | "row-resize"
- | "n-resize"
- | "e-resize"
- | "s-resize"
- | "w-resize"
- | "ne-resize"
- | "nw-resize"
- | "sw-resize"
- | "se-resize"
- | "ew-resize"
- | "ns-resize"
- | "nesw-resize"
- | "nwse-resize"
- | "zoom-in"
- | "zoom-out"