10. Fn.new and callbacks #
Let’s say you have a GUI button widget and you want to have a specific action when a user clicks on it.
class GuiButton {
public:
GuiButton(std::function<bool(int)> func) : func(std::move(func)) {
}
virtual ~GuiButton() {
}
bool event(int type) {
return func(type);
}
private:
std::function<bool(int)> func;
};
And now you would like to create this class in Wren and add some custom Wren function as the callback. What you can do is to create a Wren specific wrapper and accept a class instance (in this case, Fn
class instance from Wren).
class WrenGuiButton: public GuiButton {
public:
WrenGuiButton(wren::Variable fn)
: GuiButton(std::bind(&WrenGuiButton::wrenEvent, this, std::placeholders::_1)) {
callback = fn.func("call(_)");
}
private:
bool wrenEvent(int type) {
return callback(type).as<bool>();
}
wren::Method callback;
};
Or using lambdas:
class WrenGuiButton: public GuiButton {
public:
WrenGuiButton(wren::Variable fn)
: GuiButton([this](int type) -> bool { return callback(type).as<bool>(); }) {
callback = fn.func("call(_)");
}
private:
wren::Method callback;
};
Bind the class in the following way:
wren::VM vm;
auto& m = vm.module("test");
auto& cls = m.klass<WrenGuiButton>("GuiButton");
cls.ctor<wren::Variable>();
And finally the usage in Wren:
import "test" for GuiButton
class Main {
static main() {
var btn = GuiButton.new(Fn.new { |arg|
// "this" is going to be "Main" class
return true
})
return btn
}
}
This works because Wren’s Fn.new{}
is actually an instance of a class, and executing the method is simple as calling call(...)
of that instance.