idanarye / woab

Widgets on Actors Bridge - a GUI microframework for combining GTK with Actix
https://crates.io/crates/woab
MIT License
14 stars 1 forks source link

Connect to signals programatically without a Builder #6

Closed piegamesde closed 3 years ago

piegamesde commented 3 years ago

I have the following code snippet at the moment:

let enter_fullscreen = gio::SimpleAction::new("enter_fullscreen", None);
application.add_action(&enter_fullscreen);
application.set_accels_for_action("app.enter_fullscreen", &["F11"]);

enter_fullscreen.connect_activate(
    clone!(@weak window => @default-panic, move |_action, _value| {
        println!("Enter fullscreen");
        window.fullscreen();
    }),
);

I'd like to move that code into a stream handler, because I would then access to the window through self.widgets (and also to the internal state, but that's luckily not required in this case) without explicitly reference counting. Bonus points if I could reuse my existing signal enum for those and the builder signals.

idanarye commented 3 years ago

Inside actor() you have the context, so you can just do what WoAB does internally:

let (tx, rx) = tokio::sync::mpsc::channel(16);
enter_fullscreen.connect_activate(move |_action, _value| {
    tx.try_send(MySignal::EnterFullscreen).unwrap(); // you actually need MySignal to be Debug for unwrap to work. Otherwise it's manual error handling...
}),
);
MyActor::add_stream(rx, ctx);

I'm not sure how much more WoAB can add to that (other than nicer tokio::sync::mpsc::error::TrySendError handling - because you usually don't make the signal type Debug...) Maybe something for connecting multiple actions? And translating the values?

woab::connect_actions(ctx)
    .connect(&enter_fullscreen, || MySignal::EnterFullscreen)
    .connect(&minimize, || MySignal::Minimize)
    .connect_value(&launch_nukes, |country: String| MySignal::LaunchNukes(country));

OK - this does start to look like a worthy addition...

piegamesde commented 3 years ago

The connect_xxx in gtk-rs callbacks are just automatically generated typed versions of connect. How about this:

enter_fullscreen.connect("activate", woab::make_signal_handler::<MySignal>::("EnterFullscreen"));

Basically we take advantage of the fact that our enum already implements BuilderSignal which already does the heavy conversion lifting. The only downside I see is that we loose a bit of static type checking that gtk-rs provides.

piegamesde commented 3 years ago

I've hacked something together in #4. It can be used like this:

woab::connect_signal_handler::<Self, _, _>(&enter_fullscreen, "activate", "Fullscreen", ctx);

If one needs the signal handler or wants to do error handling, I also expose the inner method:

leave_fullscreen.connect_local("activate", false, woab::make_signal_handler::<Self, _>("Unfullscreen", ctx)).unwrap()

It works and I rather like it, except for the fact that it almost always requires explicit type annotations. One could ease this by always passing the actor (&self) as argument, but I don't know if there may be situations where no reference to self is available. One may also experiment with providing these methods as a trait method on the actors. The call would then be Self::connect_signal_handler.