Skip to content

Commit

Permalink
Close #2 (again) - add BuilderSingalConnector::inhibit
Browse files Browse the repository at this point in the history
idanarye committed Feb 8, 2021
1 parent 2c8ce4b commit ce37c8c
Showing 5 changed files with 145 additions and 32 deletions.
72 changes: 57 additions & 15 deletions examples/example_events.glade
Original file line number Diff line number Diff line change
@@ -1,46 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.36.0 -->
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkTextBuffer" id="buf_count_pressed_time"/>
<object class="GtkApplicationWindow" id="win_app">
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<child>
<!-- n-columns=2 n-rows=3 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Conut Pressed Time</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="button-press-event" handler="Press" swapped="no"/>
<signal name="button-release-event" handler="Release" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkTextView">
<property name="width_request">100</property>
<property name="height_request">20</property>
<property name="width-request">100</property>
<property name="height-request">20</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can-focus">True</property>
<property name="editable">False</property>
<property name="buffer">buf_count_pressed_time</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">All Characters</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Only The Digits</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<signal name="key-press-event" handler="AllCharactersEntryKeyPressed" swapped="no"/>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="only_digits">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="editable">False</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</object>
</interface>
28 changes: 25 additions & 3 deletions examples/example_events.rs
Original file line number Diff line number Diff line change
@@ -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<Self>;

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],
@@ -49,6 +50,7 @@ enum WindowSignal {
Press(gtk::Button, #[signal(event)] gdk::EventButton),
#[signal(inhibit = false)]
Release(gtk::Button, #[signal(event)] gdk::EventButton),
AllCharactersEntryKeyPressed(gtk::Entry, #[signal(event)] gdk::EventKey),
}

impl actix::StreamHandler<WindowSignal> for WindowActor {
@@ -78,6 +80,15 @@ impl actix::StreamHandler<WindowSignal> 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);
}
}
}
}
}
}
@@ -89,7 +100,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
woab::run_actix_inside_gtk_event_loop("example")?;

factories.win_app.instantiate().actor()
.connect_signals(WindowSignal::connector())
.connect_signals(WindowSignal::connector()
.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,
}
})
)
.create(|ctx| WindowActor {
widgets: ctx.widgets().unwrap(),
press_times: Default::default(),
18 changes: 13 additions & 5 deletions macros/src/builder_signal_derive.rs
Original file line number Diff line number Diff line change
@@ -36,7 +36,13 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result<proc_macro2:
Some(glib::value::ToValue::to_value(&#inhibit))
}
} else {
quote!(None)
quote! {
if let Some(gtk::Inhibit(inhibit)) = inhibit_dlg(&signal) {
Some(glib::value::ToValue::to_value(&inhibit))
} else {
None
}
}
};

let variant_ident = &variant.ident;
@@ -96,8 +102,10 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result<proc_macro2:
/* Match arms */
quote! {
#ident_as_str => 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);
},
@@ -117,7 +125,7 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result<proc_macro2:
let (match_arms, signal_names) = vec_of_tuples.into_iter().unzip::<_, _, Vec<_>, Vec<_>>();
Ok(quote! {
impl woab::BuilderSignal for #enum_ident {
fn bridge_signal(signal: &str, tx: tokio::sync::mpsc::Sender<Self>) -> Option<woab::RawSignalCallback> {
fn bridge_signal(signal: &str, tx: tokio::sync::mpsc::Sender<Self>, inhibit_dlg: impl 'static + Fn(&Self) -> Option<gtk::Inhibit>) -> Option<woab::RawSignalCallback> {
use tokio::sync::mpsc::error::TrySendError;
match signal {
#(#match_arms)*
@@ -133,7 +141,7 @@ pub fn impl_builder_signal_derive(ast: &syn::DeriveInput) -> Result<proc_macro2:
}

impl #enum_ident {
fn connector() -> woab::BuilderSingalConnector<Self, ()> {
fn connector() -> woab::BuilderSingalConnector<Self, (), ()> {
<Self as woab::BuilderSignal>::connector()
}
}
2 changes: 1 addition & 1 deletion src/builder.rs
Original file line number Diff line number Diff line change
@@ -230,7 +230,7 @@ where
{
let (tx, rx) = mpsc::channel(16);
A::add_stream(rx, ctx);
S::bridge_signal(handler_name, tx)
S::bridge_signal(handler_name, tx, |_| None)
.ok_or_else(|| format!("Handler '{}' was requested, but only {:?} exist", handler_name, S::list_signals()))
.unwrap()
}
57 changes: 49 additions & 8 deletions src/builder_signal.rs
Original file line number Diff line number Diff line change
@@ -11,13 +11,14 @@ pub trait BuilderSignal: Sized + 'static {
///
/// The returned function should convert the signals it revceives to the signal type, and
/// transmit them over `tx`.
fn bridge_signal(signal: &str, tx: mpsc::Sender<Self>) -> Option<RawSignalCallback>;
fn bridge_signal(signal: &str, tx: mpsc::Sender<Self>, inhibit_dlg: impl 'static + Fn(&Self) -> Option<gtk::Inhibit>) -> Option<RawSignalCallback>;

fn list_signals() -> &'static [&'static str];

fn connector() -> BuilderSingalConnector<Self, ()> {
fn connector() -> BuilderSingalConnector<Self, (), ()> {
BuilderSingalConnector {
transformer: (),
inhibit_dlg: (),
_phantom_data: Default::default(),
}
}
@@ -54,36 +55,75 @@ impl<S: 'static, T: 'static + Clone> SignalTransformer<S> for (T,) {
}
}

pub struct BuilderSingalConnector<S, T>
pub trait SignalsInhibit<S>: Clone {
fn inhibit(&self, signal: &S) -> Option<gtk::Inhibit>;
}

impl<S: 'static> SignalsInhibit<S> for () {
fn inhibit(&self, _signal: &S) -> Option<gtk::Inhibit> {
None
}
}

impl<S: 'static, F> SignalsInhibit<S> for F
where
F: Clone,
F: Fn(&S) -> Option<gtk::Inhibit>,
{
fn inhibit(&self, signal: &S) -> Option<gtk::Inhibit> {
self(signal)
}
}

pub struct BuilderSingalConnector<S, T, I>
where
S: BuilderSignal,
T: Clone,
I: SignalsInhibit<S>,
{
transformer: T,
inhibit_dlg: I,
_phantom_data: core::marker::PhantomData<S>,
}

impl<S> BuilderSingalConnector<S, ()>
impl<S, I> BuilderSingalConnector<S, (), I>
where
S: BuilderSignal,
I: SignalsInhibit<S>,
{
pub fn tag<T: Clone>(self, tag: T) -> BuilderSingalConnector<S, (T,)> {
pub fn tag<T: Clone>(self, tag: T) -> BuilderSingalConnector<S, (T,), I> {
BuilderSingalConnector {
transformer: (tag,),
inhibit_dlg: self.inhibit_dlg,
_phantom_data: Default::default(),
}
}
}

impl<S, T> BuilderSingalConnector<S, T, ()>
where
S: BuilderSignal,
T: SignalTransformer<S>,
{
pub fn inhibit<F: Clone + Fn(&S) -> Option<gtk::Inhibit>>(self, dlg: F) -> BuilderSingalConnector<S, T, F> {
BuilderSingalConnector {
transformer: self.transformer,
inhibit_dlg: dlg,
_phantom_data: Default::default(),
}
}
}

impl<S, T> RegisterSignalHandlers for BuilderSingalConnector<S, T>
impl<S, T, I> RegisterSignalHandlers for BuilderSingalConnector<S, T, I>
where
S: 'static,
S: BuilderSignal,
T: 'static,
T: SignalTransformer<S>,
I: 'static,
I: SignalsInhibit<S>,
{
type MessageType = T::Output;
// type MessageType = S;

fn register_signal_handlers<A>(self, ctx: &mut A::Context, callbacks: &mut HashMap<&'static str, crate::RawSignalCallback>)
where
@@ -92,7 +132,8 @@ where
{
let (tx, rx) = mpsc::channel(16);
for signal in S::list_signals() {
callbacks.insert(signal, S::bridge_signal(signal, tx.clone()).unwrap());
let inhibit_dlg = self.inhibit_dlg.clone();
callbacks.insert(signal, S::bridge_signal(signal, tx.clone(), move |signal| inhibit_dlg.inhibit(signal)).unwrap());
}
use tokio::stream::StreamExt;
let rx = rx.map(move|s| self.transformer.transform(s));

0 comments on commit ce37c8c

Please sign in to comment.