use std::rc::Rc;
use crate::{Actionable, Store};
use gtk::prelude::GtkApplicationExt;
use gtk::{
gio::SimpleAction,
glib::MainContext,
prelude::{ActionExt, ActionMapExt},
};
impl<A, S> Store<A, S>
where
A: Actionable + Clone + std::fmt::Debug + Send + Sync + 'static,
S: Clone + std::fmt::Debug + Default + Send + Sync + 'static,
{
pub fn bind_gtk(
self: Rc<Self>,
app: &libadwaita::Application,
root_reducer: impl Fn(&A, &mut S) + 'static,
) {
let store = self;
{
let (s, r) = async_channel::unbounded();
let reduce = store.init(
move |a, s| {
root_reducer(a, s);
},
move |a| {
s.send_blocking(a).expect("Failed to send action.");
},
);
MainContext::default().spawn_local(async move {
loop {
match r.recv().await {
Ok(a) => reduce(a),
Err(e) => {
log::error!("gstore recv action lead to error: {e}")
}
}
}
});
}
for action in A::list() {
let name = action.name();
let ga = SimpleAction::new(name, None);
ga.set_enabled(true);
app.add_action(&ga);
if let Some(keybinding) = action.keybinding() {
app.set_accels_for_action(&format!("app.{}", name), &[&keybinding.to_gtk()]);
}
let s = store.clone();
ga.connect_activate(move |a, _| {
if let Some(action) = A::try_from_name(a.name().as_str()) {
s.dispatch(action);
} else {
log::error!("Action got lost in translation: {:?}", a);
}
});
}
}
}
impl crate::Keybinding {
fn to_gtk(&self) -> String {
match self {
crate::Keybinding::Shift(key) => {
format!("<shift>{}", key)
}
crate::Keybinding::Super(key) => {
format!("<super>{}", key)
}
crate::Keybinding::Alt(key) => {
format!("<alt>{}", key)
}
crate::Keybinding::Ctrl(key) => {
format!("<primary>{}", key)
}
crate::Keybinding::Just(key) => key.to_string(),
}
}
}