RAGS - v1.10.0
    Preparing search index...

    In order for widgets to have dynamic content we pass Bindings as properties or setup a hook. A Binding is just an object that holds information for widget constructors to setup a listener.

    Caution

    Binding is a regular JavaScript object, it cannot be used in template strings

    const label = Variable("hello");

    Label({
    // [Object object] world
    label: `${label.bind()} world`,

    // hello world
    label: label.bind().as((hello) => `${hello} world`),
    });

    We can make a Binding from a Variable

    const percent = Variable(0.5);
    const slider = Widget.Slider({
    value: percent.bind(),
    onChange: ({ value }) => percent.value = value,
    });

    From a Service

    const { speaker } = await Service.import("audio");
    const slider = Widget.Slider({
    value: speaker.bind("volume"),
    onChange: ({ value }) => speaker.volume = value,
    });

    Merge any number of Bindings into another Binding

    const a = Variable(0.3);
    const b = Variable(0.7);
    const merged = Utils.merge([a.bind(), b.bind()], (a, b) => {
    return a * b;
    });

    const level = Widget.LevelBar({
    value: merged,
    });

    Turn one or multiple Service signals into a Binding

    const mpris = await Service.import("mpris");

    const label = Widget.Label({
    label: Utils.watch("initial-label", mpris, "player-added", (busName) => {
    return `player ${busName} was added`;
    }),
    });

    const label = Widget.Label({
    label: Utils.watch("initial-label", [
    [mpris, "player-added"],
    [mpris, "player-removed"],
    ], (busName) => {
    return `player ${busName} was added or removed`;
    }),
    });

    A Binding can be transformed according to need

    const num = Variable(0);

    const label = Widget.Label({
    // will throw an error, because number is not assignable to string
    label: num.bind(),

    // will have to be transformed
    label: num.bind().as((n) => n.toString()),
    label: num.bind().as(String),
    });

    You can call these on any Widget that you have a reference on. They will return this reference, meaning you can chain them up in any order in any number.

    const widget = Widget();
    widget.hook();
    widget.on();
    widget.poll();
    widget.keybind();
    const widget = Widget()
    .hook()
    .on();
    const widget = Widget({
    setup: (self) => {
    self.hook();
    self.on();
    },
    });
    const widget = Widget({
    setup: (self) =>
    self
    .hook()
    .on(),
    });

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

    const battery = await Service.import("battery");

    // .hook(GObject, callback, signal?)
    const BatteryPercent = () =>
    Label()
    .hook(battery, (self) => {
    self.label = `${battery.percent}%`;
    self.visible = battery.available;
    }, "changed");
    Caution

    A hook callback will be executed on startup. If you are connecting to a signal that has an argument you will need to check if its defined first

    const mpris = await Service.import("mpris");
    const label = Widget.Label().hook(mpris, (self, busName) => {
    if (!busName) {
    return; // skip startup execution
    }

    self.label = busName;
    }, "player-added");

    on is the same as connect but instead of the signal handler id, it returns a reference to the widget. on will setup a callback on a widget signal.

    These two are equivalent

    function MyButton() {
    const self = Widget.Button();

    self.connect("clicked", () => {
    print(self, "is clicked");
    });

    return self;
    }
    const MyButton = () =>
    Widget.Button()
    .on("clicked", (self) => {
    print(self, "is clicked");
    });
    Note

    Most signals like clicked are available as a property on the widget. So its rare that .on or .connect will be needed.

    Widget.Button({
    on_clicked: (self) => print(self, "was clicked"),
    });

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

    These two are equivalent

    function MyLabel() {
    const self = Widget.Label();

    Utils.interval(1000, () => {
    self.label = Utils.exec("date");
    }, self);

    return self;
    }
    const MyLabel = () =>
    Widget.Label()
    .poll(1000, (self) => {
    self.label = Utils.exec("date");
    });

    It is possible to setup keybindings on focused widgets

    // usually this way
    Widget.Button().on("key-press-event", (self, event) => {
    // check event for keys
    });

    // with .keybind()
    Widget.Button().keybind(["MOD1", "CONTROL"], "a", (self, event) => {
    print("alt+control+a was pressed");
    });