Module beamui.core.signals

Signal and slot mechanism.

Signals and slots, Observer pattern

Mainly used for communication between widgets.

Signal is a holder of several slots. You can connect and disconnect slots to it. When you invoke signal, slots are called one by one. All actions are performed in the caller thread.

Slot is a delegate with any types of parameters and return value. It may be a struct or class method (overridden, maybe), some nested or global function, or a lambda.

Listener here stands for a signal with single slot, which 'listens' the signal, so don't be confused by a name. Listener has smaller memory footprint.

Caution

unlike std.signals, it does not disconnect signal from slots belonging to destroyed objects.

Example

import std.stdio;

struct S
{
    Listener!(bool delegate()) onFire;
    Signal!(bool delegate(string)) onMultiFire;

    void fire()
    {
        // call the signal, which calls a listener
        // may be called with explicit onFire.emit()
        bool done = onFire();
        assert(done);
    }

    void multiFire()
    {
        bool done = onMultiFire("world");
        assert(done);
    }
}

struct Z
{
    static int goodbyeCount = 0;

    bool hello(string what)
    {
        writeln("Hello, ", what);
        return true;
    }

    bool goodbye(string what)
    {
        writeln("Goodbye, ", what);
        goodbyeCount++;
        return false;
    }
}

S s;
Z z;
// assign a lambda to the signal
// there are 10 ways to declare a lambda, here we use short {} syntax
s.onFire = { return z.hello("world"); };
// check if any listener is connected
assert(s.onFire.assigned);
s.fire();

Z z1, z2;
// connect methods by reference
// may be connected with explicit .connect()
s.onMultiFire ~= &z.goodbye;
s.onMultiFire ~= &z1.hello;
s.onMultiFire ~= &z2.goodbye;
s.multiFire();
// signal invokes slots one by one in order they added
// by default, signal stops on first nonzero value, returned by a slot
// and returns this value
// so z2.goodbye will not be called
// this behaviour can be changed by passing ReturnPolicy.late as a second Signal parameter
assert(Z.goodbyeCount == 1);

// you can disconnect individual slots using disconnect()
s.onMultiFire.disconnect(&z1.hello);
// or -= operator
s.onMultiFire -= &z2.goodbye;

Import line

import beamui.core.signals;

Structs

NameDescription
Listener Single listener; parameter is some delegate
Signal Multiple listeners; parameter is some delegate

Enums

NameDescription
ReturnPolicy Determines when signal returns value