summaryrefslogtreecommitdiff
path: root/docs/guide/lua/binding.md
diff options
context:
space:
mode:
authorKevin <[email protected]>2024-10-25 13:50:00 -0300
committerGitHub <[email protected]>2024-10-25 18:50:00 +0200
commit8306ec0789854f9e04bc1708c4a7dc2afc1b4c90 (patch)
tree881784894310510e4c62e2fc850ea934ca5aee86 /docs/guide/lua/binding.md
parente8715aec5e05e0438192e611afea2fe6f10cb80f (diff)
docs: lua docs (#50)
Diffstat (limited to 'docs/guide/lua/binding.md')
-rw-r--r--docs/guide/lua/binding.md139
1 files changed, 139 insertions, 0 deletions
diff --git a/docs/guide/lua/binding.md b/docs/guide/lua/binding.md
new file mode 100644
index 0000000..f4d5f0b
--- /dev/null
+++ b/docs/guide/lua/binding.md
@@ -0,0 +1,139 @@
+# Binding
+
+As mentioned before binding an object's state to another -
+so in most cases a `Variable` or a `GObject.Object` property to a widget's property -
+is done through the `bind` function which returns a `Binding` object.
+
+`Binding` objects simply hold information about the source and how it should be transformed
+which Widget constructors can use to setup a connection between themselves and the source.
+
+```lua
+---@class Binding<T>
+---@field private transform_fn fun(value: T): any
+---@field private emitter Connectable | Subscribable<T>
+---@field private property? string
+---@field as fun(transform: fun(value: T): any): Binding
+---@field get fun(): T
+---@field subscribe fun(self, callback: fun(value: T)): function
+```
+
+A `Binding` can be constructed from an object implementing
+the `Subscribable` interface (usually a `Variable`)
+or an object implementing the `Connectable` interface and one of its properties
+(usually a `GObject.Object` instance).
+
+Lua type annotations are not expressive enough to explain this,
+so I'll use TypeScript to demonstrate it.
+
+<!--TODO: use Teal maybe?-->
+
+```ts
+function bind<T>(obj: Subscribable<T>): Binding<T>
+
+function bind<
+ Obj extends Connectable,
+ Prop extends keyof Obj,
+>(obj: Obj, prop: Prop): Binding<Obj[Prop]>
+```
+
+## Subscribable and Connectable interface
+
+Any object implementing one of these interfaces can be used with `bind`.
+
+```ts
+interface Subscribable<T> {
+ subscribe(callback: (value: T) => void): () => void
+ get(): T
+}
+
+interface Connectable {
+ connect(signal: string, callback: (...args: any[]) => unknown): number
+ disconnect(id: number): void
+}
+```
+
+`Connectable` is usually used for GObjects coming from [libraries](../libraries/references)
+You won't be implementing it in Lua code.
+
+## Example Custom Subscribable
+
+When binding the children of a box from an array, usually not all elements
+of the array changes each time, so it would make sense to not destroy
+the widget which represents the element.
+
+::: code-group
+
+```lua :line-numbers [varmap.lua]
+local Gtk = require("astal.gtk3").Gtk
+local Variable = require("astal.variable")
+
+---@param initial table
+return function(initial)
+ local map = initial
+ local var = Variable()
+
+ local function notify()
+ local arr
+ for _, value in pairs(map) do
+ table.insert(arr, value)
+ end
+ var:set(arr)
+ end
+
+ local function delete(key)
+ if Gtk.Widget:is_type_of(map[key]) then
+ map[key]:destroy()
+ end
+
+ map[key] = nil
+ end
+
+ notify() -- init
+
+ return {
+ set = function(key, value)
+ delete(key)
+ map[key] = value
+ notify()
+ end,
+ delete = function(key)
+ delete(key)
+ notify()
+ end,
+ get = function()
+ return var:get()
+ end,
+ subscribe = function(callback)
+ return var:subscribe(callback)
+ end,
+ }
+end
+```
+
+:::
+
+And this `VarMap<key, Widget>` can be used as an alternative to `Variable<Array<Widget>>`.
+
+```lua
+function MappedBox()
+ local map = varmap({
+ ["1"] = Widget.Label({ label = "1" }),
+ ["2"] = Widget.Label({ label = "2" }),
+ })
+
+ return Widget.Box({
+ setup = function (self)
+ self:hook(gobject, "added", function (_, id)
+ map.set(id, Widget.Label({ label = id }))
+ end)
+ self:hook(gobject, "removed", function (_, id)
+ map.delete(id)
+ end)
+ end,
+ bind(map):as(function (arr)
+ -- can be sorted here
+ return arr
+ end),
+ })
+end
+```