Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to build multiple actors from a BuilderUtilizer #4

Merged
merged 6 commits into from
Feb 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions examples/example_actor_per_row.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#[derive(woab::Factories)]
pub struct Factories {
#[factory(extra(buf_sum))]
win_app: woab::Factory<WindowActor, WindowWidgets, WindowSignal>,
win_app: woab::BuilderFactory,
#[factory(extra(buf_addend))]
row_addend: woab::Factory<AddendActor, AddendWidgets, AddendSignal>,
row_addend: woab::BuilderFactory,
}

#[derive(woab::WidgetsFromBuilder)]
Expand Down Expand Up @@ -46,14 +46,16 @@ impl actix::StreamHandler<WindowSignal> for WindowActor {
use gtk::prelude::*;;
match signal {
WindowSignal::ClickButton => {
let addend = self.factories.row_addend.build().actor(|_, widgets| {
self.widgets.lst_addition.add(&widgets.row_addend);
AddendActor {
widgets,
window: ctx.address(),
number: Some(0),
}
}).unwrap();
let addend = self.factories.row_addend.instantiate()
.new_actor(|builder_ctx| {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ctx.connect_signals::<AddendSignal>();

let widgets: AddendWidgets = builder_ctx.connect_widgets().unwrap();
self.widgets.lst_addition.add(&widgets.row_addend);
AddendActor {
widgets,
window: ctx.address(),
number: Some(0),
}
});
self.addends.push(addend);
ctx.address().do_send(Recalculate);
}
Expand Down Expand Up @@ -162,11 +164,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
gtk::init()?;
woab::run_actix_inside_gtk_event_loop("example")?;

factories.win_app.build().actor(|_, widgets| WindowActor {
widgets,
factories,
addends: Vec::new(),
})?;
factories.win_app.instantiate()
.new_actor(|ctx| {
ctx.connect_signals::<WindowSignal>();
WindowActor {
widgets: ctx.connect_widgets().unwrap(),
factories,
addends: Vec::new(),
}
});

gtk::main();
Ok(())
Expand Down
16 changes: 10 additions & 6 deletions examples/example_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::time::{Instant, Duration};
#[derive(woab::Factories)]
pub struct Factories {
#[factory(extra(buf_count_pressed_time))]
win_app: woab::Factory<WindowActor, WindowWidgets, WindowSignal>,
win_app: woab::BuilderFactory,
}

#[derive(woab::WidgetsFromBuilder)]
Expand Down Expand Up @@ -88,11 +88,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
gtk::init()?;
woab::run_actix_inside_gtk_event_loop("example")?;

factories.win_app.build().actor(|_, widgets| WindowActor {
widgets,
press_times: Default::default(),
total_durations: Default::default(),
})?;
factories.win_app.instantiate()
.new_actor(|ctx| {
ctx.connect_signals::<WindowSignal>();
WindowActor {
widgets: ctx.connect_widgets().unwrap(),
press_times: Default::default(),
total_durations: Default::default(),
}
});

gtk::main();
Ok(())
Expand Down
26 changes: 15 additions & 11 deletions examples/example_taggged_signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use gtk::prelude::*;
#[derive(woab::Factories)]
pub struct Factories {
#[factory(extra(buf_sum))]
win_app: woab::Factory<WindowActor, WindowWidgets, WindowSignal>,
win_app: woab::BuilderFactory,
#[factory(extra(buf_addend))]
row_addend: woab::Factory<(), AddendWidgets, AddendSignal>,
row_addend: woab::BuilderFactory,
}

#[derive(woab::WidgetsFromBuilder)]
Expand Down Expand Up @@ -46,9 +46,9 @@ impl actix::StreamHandler<WindowSignal> for WindowActor {
WindowSignal::ClickButton => {
let addend_id = self.next_addend_id;
self.next_addend_id += 1;
let widgets = self.factories.row_addend.build()
.connect_tagged_builder_signals(ctx, addend_id)
.widgets().unwrap();
let mut builder = self.factories.row_addend.instantiate();
builder.connect_signals_tagged(addend_id, ctx);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess Rust can deduce that this does not need ::<AddendSignal>, but it's probably a good idea to add it anyway...

let widgets = builder.connect_widgets::<AddendWidgets>().unwrap();
self.widgets.lst_addition.add(&widgets.row_addend);
self.addends.insert(addend_id, (widgets, Some(0)));
self.recalculate();
Expand Down Expand Up @@ -111,12 +111,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
gtk::init()?;
woab::run_actix_inside_gtk_event_loop("example")?;

factories.win_app.build().actor(|_, widgets| WindowActor {
widgets,
factories,
next_addend_id: 0,
addends: Default::default(),
})?;
factories.win_app.instantiate()
.new_actor(|ctx| {
ctx.connect_signals::<WindowSignal>();
WindowActor {
widgets: ctx.connect_widgets().unwrap(),
factories,
next_addend_id: 0,
addends: Default::default(),
}
});

gtk::main();
Ok(())
Expand Down
45 changes: 30 additions & 15 deletions macros/src/builder_signal_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result<proc_macro2:
return Err(Error::new_spanned(ast, "BuilderSignal only supports enums"));
};
let enum_ident = &ast.ident;
let match_arms = data_enum.variants.iter().map(|variant| {
let vec_of_tuples = data_enum.variants.iter().map(|variant| {
let mut ret = None;
iter_attrs_parameters(&variant.attrs, "signal", |name, value| {
match path_to_single_string(&name)?.as_str() {
Expand Down Expand Up @@ -92,29 +92,44 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result<proc_macro2:
syn::Fields::Unit => quote!(#enum_ident::#variant_ident),
syn::Fields::Named(_) => return Err(Error::new_spanned(variant, "BuilderSignal only supports unit or tuple variants (even if they are empty)")),
};
Ok(quote! {
#ident_as_str => Some(Box::new(move |args| {
match tx.clone().try_send(#msg_construction) {
Ok(_) => #signal_return_value,
Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => {
panic!("Unable to send {} signal - channel is closed", #ident_as_str);
},
Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => {
panic!("Unable to send {} signal - channel is full", #ident_as_str);
},
}
})),
})
Ok((
/* Match arms */
quote! {
#ident_as_str => Some(Box::new(move |args| {
match tx.clone().try_send(#msg_construction) {
Ok(_) => #signal_return_value,
Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => {
panic!("Unable to send {} signal - channel is closed", #ident_as_str);
},
Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => {
panic!("Unable to send {} signal - channel is full", #ident_as_str);
},
}
})),
},
/* Signal names */
quote! {
#ident_as_str,
},
))
}).collect::<Result<Vec<_>, Error>>()?;
/* We cannot use unzip with error handling, so here's a workaround */
let (match_arms, signal_names) = vec_of_tuples.into_iter().unzip::<_, _, Vec<_>, Vec<_>>();
Ok(quote! {
impl woab::BuilderSignal for #enum_ident {
fn transmit_signal_in_stream_function(signal: &str, tx: tokio::sync::mpsc::Sender<Self>) -> Option<Box<dyn Fn(&[glib::Value]) -> Option<glib::Value>>> {
fn bridge_signal(signal: &str, tx: tokio::sync::mpsc::Sender<Self>) -> Option<woab::RawSignalCallback> {
use tokio::sync::mpsc::error::TrySendError;
match signal {
#(#match_arms)*
_ => None,
}
}

fn list_signals() -> &'static [&'static str] {
&[
#(#signal_names)*
]
}
}
})
}
2 changes: 1 addition & 1 deletion macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ mod factories_derive;
mod removable_derive;
mod util;

#[proc_macro_derive(WidgetsFromBuilder)]
#[proc_macro_derive(WidgetsFromBuilder, attributes(widget))]
pub fn derive_widgets_from_builder(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
match widgets_from_builder_derive::impl_widgets_from_builder_derive(&input) {
Expand Down
33 changes: 32 additions & 1 deletion macros/src/widgets_from_builder_derive.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use syn::parse::Error;
use syn::spanned::Spanned;
use quote::quote;
use crate::util::{iter_attrs_parameters, path_to_single_string};

pub fn impl_widgets_from_builder_derive(ast: &syn::DeriveInput) -> Result<proc_macro2::TokenStream, Error> {
let fields = if let syn::Data::Struct(syn::DataStruct {
Expand All @@ -13,9 +14,31 @@ pub fn impl_widgets_from_builder_derive(ast: &syn::DeriveInput) -> Result<proc_m
};
let struct_ident = &ast.ident;
let ctor_arms = fields.named.iter().map(|field| {
/* Handle renaming */
let mut name = None;
iter_attrs_parameters(&field.attrs, "widget", |attr_name, value| {
match path_to_single_string(&attr_name)?.as_str() {
"name" => {
let value = value.ok_or_else(|| Error::new_spanned(attr_name, "attribute `name` must have a value"))?;
if name.is_some() {
return Err(Error::new_spanned(value, "attribute `name` can only be specified once"));
}
name = Some(value);
},
_ => {
return Err(Error::new_spanned(attr_name, "unknown attribute"));
},
}
Ok(())
})?;

let field_ident = field.ident.as_ref().ok_or_else(|| Error::new(field.span(), "Nameless field"))?;
let field_type = &field.ty;
let ident_as_str = syn::LitStr::new(&field_ident.to_string(), field_ident.span());
let ident_as_str = match name {
Some(syn::Expr::Lit(syn::ExprLit {lit: syn::Lit::Str(name), ..})) => name,
None => syn::LitStr::new(&field_ident.to_string(), field_ident.span()),
_ => return Err(Error::new_spanned(name, "`name` attribute must have a string literal value")),
};
Ok(quote!{
#field_ident: builder.get_object(#ident_as_str).ok_or_else(|| {
if let Some(object) = builder.get_object::<glib::Object>(#ident_as_str) {
Expand All @@ -42,5 +65,13 @@ pub fn impl_widgets_from_builder_derive(ast: &syn::DeriveInput) -> Result<proc_m
})
}
}

impl std::convert::TryFrom<gtk::Builder> for #struct_ident {
type Error = woab::Error;

fn try_from(builder: gtk::Builder) -> Result<Self, Self::Error> {
<Self as std::convert::TryFrom<&gtk::Builder>>::try_from(&builder)
}
}
})
}
Loading