Skip to content

Commit aa6b3c6

Browse files
committed
update to 1.8.0
TODO: list rest of subclassed widgets
1 parent bbacea6 commit aa6b3c6

11 files changed

+155
-104
lines changed

src/content/docs/config/cli.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ OPTIONS:
2020
-r, --run-js Execute string as an async function
2121
-f, --run-file Execute file as an async function
2222
-I, --init Initialize the configuration directory
23-
-C, --clear-cache Remove $HOME/.cache/ags
23+
--clear-cache Remove $HOME/.cache/ags
2424

2525
```
2626

src/content/docs/config/common-issues.md

+6-10
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,28 @@ revealer that starts off with `reveal_child: false`
1414

1515
```js
1616
Widget.Window({
17-
child: Widget.Box({
18-
css: 'padding: 1px;',
19-
child: Widget.Revealer(),
20-
}),
17+
child: Widget.Box({
18+
css: 'padding: 1px;',
19+
child: Widget.Revealer(),
20+
}),
2121
})
2222
```
2323

2424
## Custom svg symbolic icons
2525

2626
Put svgs in a directory, named `<icon-name>-symbolic.svg`
27-
and use `Gtk.IconTheme.append_search_path` or `icons` option in exported object
27+
and use `App.addIcons` or `icons` option in exported object
2828

2929
```js
3030
// config.js
3131
import Gtk from 'gi://Gtk?version=3.0';
3232

33-
Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets`);
33+
App.addIcons(`${App.configDir}/assets`)
3434

3535
Widget.Icon({
3636
icon: 'custom-symbolic', // custom-symbolic.svg
3737
css: 'color: green;', // can be colored, like other named icons
3838
});
39-
40-
export default {
41-
icons: `${App.configDir}/assets`,
42-
}
4339
```
4440

4541
## GtkWindow is not a layer surface

src/content/docs/config/config-object.md

+4-8
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ title: Config Object
33
description: Exported configuration object
44
---
55

6-
When you start `ags`, it will try to `import` the `default` `export`
7-
from a module which defaults to `~/.config/ags/config.js`.
8-
Even if you mutate this object after initialization,
9-
the config **will not be reloaded**.
6+
`App.config` can be called any number of times, the passed
7+
properties will be applied on top of previous calls
108

119
```js
1210
// config.js
13-
export default {
11+
App.config({
1412
style: "./style.css",
1513
icons: "./assests",
1614
windows: [
@@ -28,11 +26,9 @@ export default {
2826
onWindowToggled: function (windowName, visible) {
2927
print(`${windowName} is ${visible}`)
3028
},
31-
};
29+
});
3230
```
3331

34-
## The exported config object
35-
3632
| Field | Type | Description |
3733
|-------|------|-------------|
3834
| style | `string` | Path to a css file.

src/content/docs/config/first-widgets.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@ title: Your First Widget
33
description: Starting point to understanding how AGS works
44
---
55

6-
Start by creating `~/.config/ags/config.js` with the following contents:
6+
Start by creating `~/.config/ags/config.js`
77

88
```js
99
// ~/.config/ags/config.js
10-
export default {
10+
App.config({
1111
windows: [
1212
// this is where window definitions will go
1313
]
14-
}
14+
})
1515
```
1616

1717
then run `ags` in the terminal
@@ -45,11 +45,11 @@ const myBar = Widget.Window({
4545
child: myLabel,
4646
})
4747

48-
export default { windows: [myBar] }
48+
App.config({ windows: [myBar] })
4949
```
5050

5151
:::tip
52-
GObject properties can be accessed or set in multiple ways:
52+
GObject properties can be accessed or set in several ways:
5353
with `camelCase`, `snake_case`, and `kebab-case`
5454

5555
```js
@@ -89,12 +89,12 @@ function Bar(monitor = 0) {
8989
})
9090
}
9191

92-
export default {
92+
App.config({
9393
windows: [
9494
Bar(0), // can be instantiated for each monitor
9595
Bar(1),
9696
],
97-
}
97+
})
9898
```
9999

100100
:::note
@@ -103,7 +103,7 @@ if it is passed to `windows` in the exported object.
103103

104104
Calling `Widget.Window` will create and show the window by default.
105105
It is not necessary to pass a reference to `windows` in
106-
the exported object, but if it is not,
106+
the config object, but if it is not,
107107
it can't be toggled with `ags --toggle-window` or through `App.toggleWindow`
108108
:::
109109

src/content/docs/config/reactivity.md

+121-54
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,84 @@
22
title: Reactivity
33
---
44

5-
We have used `poll` and `bind` so far to make widgets
6-
have content dynamically. There is also `on`, `hook` and `keybind` methods.
5+
In order for widgets to have dynamic content we pass `Binding`s as properties
6+
or setup a `hook`.
7+
A `Binding` is just an object that holds information for widget constructors
8+
to setup a listener.
9+
10+
## Property Bindings
11+
12+
We can make a `Binding` from a Variable
13+
14+
```js
15+
const percent = Variable(0.5)
16+
const slider = Widget.Slider({
17+
value: percent.bind(),
18+
onChange: ({ value }) => percent.value = value,
19+
})
20+
```
21+
22+
From a `Service`
23+
24+
```js
25+
const { speaker } = await Service.import("audio")
26+
const slider = Widget.Slider({
27+
value: speaker.bind("volume"),
28+
onChange: ({ value }) => speaker.volume = value,
29+
})
30+
```
31+
32+
Merge any number of `Binding`s into another `Binding`
33+
34+
```js
35+
const a = Variable(0.3)
36+
const b = Variable(0.7)
37+
const merged = Utils.merge([a.bind(), b.bind()], (a, b) => {
38+
return a * b
39+
})
40+
41+
const level = Widget.LevelBar({
42+
value: merged
43+
})
44+
```
45+
46+
Turn one or multiple Service signals into a `Binding`
47+
48+
```js
49+
const mpris = await Service.import("mpris")
50+
51+
const label = Widget.Label({
52+
label: Utils.watch("initial-label", mpris, "player-added", (busName) => {
53+
return `player ${busName} was added`
54+
})
55+
})
56+
57+
const label = Widget.Label({
58+
label: Utils.watch("initial-label", [
59+
[mpris, "player-added"],
60+
[mpris, "player-removed"],
61+
], (busName) => {
62+
return `player ${busName} was added or removed`
63+
})
64+
})
65+
```
66+
67+
A `Binding` can be transformed according to need
68+
69+
```js
70+
const num = Variable(0)
71+
72+
const label = Widget.Label({
73+
// will throw an error, because number is not assignable to string
74+
label: num.bind(),
75+
76+
// will have to be transformed
77+
label: num.bind().as(n => n.toString()),
78+
label: num.bind().as(String)
79+
})
80+
```
81+
82+
## Hooks
783

884
You can call these on any Widget that you have a reference on.
985
They will return `this` reference, meaning you
@@ -12,90 +88,69 @@ can chain them up in any order in any number.
1288
```js
1389
const widget = Widget()
1490
widget.hook()
15-
widget.bind()
91+
widget.on()
92+
widget.poll()
93+
widget.keybind()
1694
```
1795

1896
```js
1997
const widget = Widget()
2098
.hook()
21-
.bind()
99+
.on()
22100
```
23101

24102
```js
25103
const widget = Widget({
26104
setup: self => {
27-
self.bind()
28105
self.hook()
106+
self.on()
29107
}
30108
})
31109
```
32110

33111
```js
34112
const widget = Widget({
35113
setup: self => self
36-
.bind()
37114
.hook()
115+
.on()
38116
})
39117
```
40118

41-
## Hook
119+
### Hook
42120

43121
`hook` will setup a listener to a `GObject` and will handle disconnection
44122
when the widget is destroyed. It will connect
45123
to the `changed` signal by default when not specified otherwise.
46124

47125
```js
126+
const battery = await Service.import("battery")
127+
48128
// .hook(GObject, callback, signal?)
49129
const BatteryPercent = () => Label()
50-
.hook(Battery, label => {
51-
label.label = `${Battery.percent}%`
52-
label.visible = Battery.available
53-
}, 'changed')
130+
.hook(battery, self => {
131+
self.label = `${battery.percent}%`
132+
self.visible = battery.available
133+
}, "changed")
54134
```
55135

56-
## Bind
57-
58-
`bind` can be directly translated to `hook`.
59-
It will setup a listener based on property changes
136+
:::caution
137+
A `hook` callback will be executed on startup.
138+
If you are connecting to a signal that has an argument
139+
you will need to check if its defined first
60140

61141
```js
62-
const label = Label()
142+
const mpris = await Service.import("mpris")
143+
const label = Widget.Label().hook(mpris, (self, busName) => {
144+
if (!busName)
145+
return // skip startup execution
63146

64-
label.bind(
65-
'label', // self property to bind
66-
Battery, // GObject to listen to
67-
'percent', // target property
68-
p => `${p}%`) // optional transform method
69-
70-
// translates to
71-
label.hook(
72-
Battery,
73-
self => self['label'] = `${Battery['percent']}%`,
74-
'notify::percent')
147+
self.label = busName
148+
}, "player-added")
75149
```
76150

77-
It is also possible to call `bind` on [Services](./services)
78-
and [Variables](./variables) that can be used inside constructors.
151+
:::
79152

80-
```js
81-
Label({
82-
label: Battery
83-
.bind('percent')
84-
.as(p => `${p}%`)
85-
})
86-
```
87-
88-
```js
89-
const text = Variable('hello')
90-
91-
Label({
92-
label: text
93-
.bind()
94-
.as(v => `transformed ${v}`)
95-
})
96-
```
97-
98-
## On
153+
### On
99154

100155
`on` is the same as `connect` but instead of the signal handler id,
101156
it returns a reference to the widget. `on` will setup a callback on a widget signal.
@@ -106,8 +161,8 @@ These two are equivalent
106161
function MyButton() {
107162
const self = Widget.Button()
108163

109-
self.connect('clicked', () => {
110-
print(self, 'is clicked')
164+
self.connect("clicked", () => {
165+
print(self, "is clicked")
111166
})
112167

113168
return self
@@ -116,12 +171,24 @@ function MyButton() {
116171

117172
```js
118173
const MyButton = () => Widget.Button()
119-
.on('clicked', self => {
120-
print(self, 'is clicked')
174+
.on("clicked", self => {
175+
print(self, "is clicked")
121176
})
122177
```
123178

124-
## Poll
179+
:::note
180+
Most signals like `clicked` are available as a propety on the widget.
181+
So its rare that `.on` or `.connect` will be needed.
182+
183+
```js
184+
Widget.Button({
185+
on_clicked: self => print(self, "was clicked")
186+
})
187+
```
188+
189+
:::
190+
191+
### Poll
125192

126193
Avoid using this as much as possible, using this is considered bad practice.
127194

@@ -146,7 +213,7 @@ const MyLabel = () => Widget.Label()
146213
})
147214
```
148215

149-
## Keybind
216+
### Keybind
150217

151218
It is possible to setup keybindings on focused widgets
152219

0 commit comments

Comments
 (0)