From 79abc12336ce363ab2367b707d25ef35d69b909f Mon Sep 17 00:00:00 2001 From: IdanArye Date: Wed, 3 Feb 2021 22:52:23 +0200 Subject: [PATCH] Close #2 - add `signals_inhibit` --- examples/example_events.glade | 72 +++++++++++++++++++++++------ examples/example_events.rs | 32 ++++++++++--- macros/src/builder_signal_derive.rs | 36 ++++++++++----- src/builder_signal.rs | 12 +++-- src/factories.rs | 12 ++++- 5 files changed, 124 insertions(+), 40 deletions(-) diff --git a/examples/example_events.glade b/examples/example_events.glade index eccd05048a..bce2c33dcf 100644 --- a/examples/example_events.glade +++ b/examples/example_events.glade @@ -1,46 +1,88 @@ - + - False + False + True - False + False Conut Pressed Time True - True - True + True + True - 0 - 0 + 0 + 0 - 100 - 20 + 100 + 20 True - True + True False buf_count_pressed_time - 1 - 0 + 1 + 0 + + + + + True + False + All Characters + + + 0 + 1 + + + + + True + False + Only The Digits + + + 0 + 2 + + + + + True + True + + + + 1 + 1 + + + + + True + True + False + + + 1 + 2 - - - diff --git a/examples/example_events.rs b/examples/example_events.rs index 9ef63f223e..3a3e87a2c7 100644 --- a/examples/example_events.rs +++ b/examples/example_events.rs @@ -1,5 +1,7 @@ use std::time::{Instant, Duration}; +use gtk::prelude::*; + #[derive(woab::Factories)] pub struct Factories { #[factory(extra(buf_count_pressed_time))] @@ -10,6 +12,7 @@ pub struct Factories { pub struct WindowWidgets { win_app: gtk::ApplicationWindow, buf_count_pressed_time: gtk::TextBuffer, + only_digits: gtk::Entry, } struct WindowActor { @@ -22,7 +25,6 @@ impl actix::Actor for WindowActor { type Context = actix::Context; fn started(&mut self, _ctx: &mut Self::Context) { - use gtk::WidgetExt; self.update_pressed_time_display(); self.widgets.win_app.show(); } @@ -34,7 +36,6 @@ impl actix::Actor for WindowActor { impl WindowActor { fn update_pressed_time_display(&self) { - use gtk::prelude::*; self.widgets.buf_count_pressed_time.set_text(&format!( "L: {:?}, R: {:?}", self.total_durations[0], @@ -43,12 +44,13 @@ impl WindowActor { } } -#[derive(woab::BuilderSignal)] +#[derive(Debug, woab::BuilderSignal)] enum WindowSignal { - #[signal(ret = false)] + #[signal(inhibit = false)] Press(gtk::Button, #[signal(event)] gdk::EventButton), - #[signal(ret = false)] + #[signal(inhibit = false)] Release(gtk::Button, #[signal(event)] gdk::EventButton), + AllCharactersEntryKeyPressed(gtk::Entry, #[signal(event)] gdk::EventKey), } impl actix::StreamHandler for WindowActor { @@ -78,6 +80,15 @@ impl actix::StreamHandler for WindowActor { self.update_pressed_time_display(); } } + WindowSignal::AllCharactersEntryKeyPressed(_, event) => { + if let Some(character) = event.get_keyval().to_unicode() { + if character.is_digit(10) { + let mut text = self.widgets.only_digits.get_text().as_str().to_owned(); + text.push(character); + self.widgets.only_digits.set_text(&text); + } + } + } } } } @@ -88,7 +99,16 @@ fn main() -> Result<(), Box> { gtk::init()?; woab::run_actix_inside_gtk_event_loop("example")?; - factories.win_app.build().actor(|_, widgets| WindowActor { + factories.win_app.build().signals_inhibit(|signal| { + match signal { + WindowSignal::AllCharactersEntryKeyPressed(_, event) => { + let character = event.get_keyval().to_unicode(); + let is_digit = character.map(|c| c.is_digit(10)).unwrap_or(false); + Some(gtk::Inhibit(is_digit)) + } + _ => None, + } + }).actor(|_, widgets| WindowActor { widgets, press_times: Default::default(), total_durations: Default::default(), diff --git a/macros/src/builder_signal_derive.rs b/macros/src/builder_signal_derive.rs index 5fba9aa397..4fc9367519 100644 --- a/macros/src/builder_signal_derive.rs +++ b/macros/src/builder_signal_derive.rs @@ -15,15 +15,15 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result { - let value = value.ok_or_else(|| Error::new_spanned(name, "`ret` must have a value"))?; - if ret.is_some() { - return Err(Error::new_spanned(value, "`ret` already set")); + "inhibit" => { + let value = value.ok_or_else(|| Error::new_spanned(name, "`inhibit` must have a value"))?; + if inhibit.is_some() { + return Err(Error::new_spanned(value, "`inhibit` already set")); } - ret = Some(value); + inhibit = Some(value); } _ => { return Err(Error::new_spanned(name, "unknown argument")); @@ -31,12 +31,22 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result Result Some(Box::new(move |args| { - match tx.clone().try_send(#msg_construction) { - Ok(_) => #signal_return_value, + let signal = #msg_construction; + let return_value = #signal_return_value; + match tx.clone().try_send(signal) { + Ok(_) => return_value, Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => { panic!("Unable to send {} signal - channel is closed", #ident_as_str); }, @@ -108,7 +120,7 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result, Error>>()?; Ok(quote! { impl woab::BuilderSignal for #enum_ident { - fn transmit_signal_in_stream_function(signal: &str, tx: tokio::sync::mpsc::Sender) -> Option Option>> { + fn transmit_signal_in_stream_function(signal: &str, tx: tokio::sync::mpsc::Sender, inhibit_dlg: Option Option>>) -> Option Option>> { use tokio::sync::mpsc::error::TrySendError; match signal { #(#match_arms)* diff --git a/src/builder_signal.rs b/src/builder_signal.rs index 01a9048cda..48798fcacb 100644 --- a/src/builder_signal.rs +++ b/src/builder_signal.rs @@ -1,3 +1,5 @@ +use std::rc::Rc; + use tokio::sync::mpsc; /// Represent a GTK signal that originates from a GTK builder. Refer to [the corresponding derive](derive.BuilderSignal.html). @@ -6,18 +8,18 @@ pub trait BuilderSignal: Sized + 'static { /// /// The returned function should convert the signals it revceives to the signal type, and /// transmit them over `tx`. - fn transmit_signal_in_stream_function(signal: &str, tx: mpsc::Sender) -> Option Option>>; + fn transmit_signal_in_stream_function(signal: &str, tx: mpsc::Sender, inhibit_dlg: Option Option>>) -> Option Option>>; /// Create a stream of all the signals. /// /// Will return `None` if there are no signals, to allow avoiding closed streams. - fn stream_builder_signals(builder: >k::Builder) -> Option> { + fn stream_builder_signals(builder: >k::Builder, inhibit_dlg: Option Option>>) -> Option> { use gtk::prelude::BuilderExtManual; let (tx, rx) = mpsc::channel(16); let mut connected_any = false; builder.connect_signals(|_, signal| { - if let Some(handler) = Self::transmit_signal_in_stream_function(signal, tx.clone()) { + if let Some(handler) = Self::transmit_signal_in_stream_function(signal, tx.clone(), inhibit_dlg.clone()) { connected_any = true; handler } else { @@ -32,10 +34,10 @@ pub trait BuilderSignal: Sized + 'static { } /// Connect the signals created from a GTK builder to an actor's context. - fn connect_builder_signals>(ctx: &mut H::Context, builder: >k::Builder) + fn connect_builder_signals>(ctx: &mut H::Context, builder: >k::Builder, inhibit_dlg: Option Option>>) where ::Context: actix::AsyncContext { - if let Some(rx) = Self::stream_builder_signals(builder) { + if let Some(rx) = Self::stream_builder_signals(builder, inhibit_dlg) { H::add_stream(rx, ctx); } } diff --git a/src/factories.rs b/src/factories.rs index cba7af6859..bd0b7c9477 100644 --- a/src/factories.rs +++ b/src/factories.rs @@ -1,4 +1,5 @@ use core::convert::TryInto; +use std::rc::Rc; use gtk::Builder; use tokio::sync::mpsc; @@ -156,6 +157,7 @@ impl Factory { /// See [`woab::Factory`](struct.Factory.html) for usage example. pub struct BuilderUtilizer { builder: gtk::Builder, + inhibit_dlg: Option Option>>, _phantom: std::marker::PhantomData<(A, W, S)>, } @@ -163,6 +165,7 @@ impl From for BuilderUtilizer { fn from(builder: gtk::Builder) -> Self { Self { builder, + inhibit_dlg: None, _phantom: Default::default(), } } @@ -195,7 +198,7 @@ where pub fn actor(&self, make_actor: impl FnOnce(&mut A::Context, W) -> A) -> Result, <>k::Builder as TryInto>::Error> { let widgets: W = self.widgets()?; Ok(::create(move |ctx| { - S::connect_builder_signals::(ctx, &self.builder); + S::connect_builder_signals::(ctx, &self.builder, self.inhibit_dlg.clone()); make_actor(ctx, widgets) })) } @@ -205,6 +208,11 @@ impl BuilderUtilizer where S: BuilderSignal, { + pub fn signals_inhibit(&mut self, inhibit_dlg: impl 'static + Fn(&S) -> Option) -> &mut Self { + self.inhibit_dlg = Some(Rc::new(inhibit_dlg)); + self + } + /// Create a stream (based on Tokio's MSPC) of signals that arrive from the builder. /// /// * The signals are all represented by the third generic parameter (`S`) of @@ -215,7 +223,7 @@ where /// returned a stream stream will be closed automatically for having no transmitters, which - /// by default - will make Actix close the actor. pub fn stream_builder_signals(&self) -> Option> { - S::stream_builder_signals(&self.builder) + S::stream_builder_signals(&self.builder, self.inhibit_dlg.clone()) } /// Stream the signals generated by the builder to an actor represented by `ctx`, together with