Skip to content

Commit

Permalink
Add the ability to use self in events
Browse files Browse the repository at this point in the history
  • Loading branch information
antoyo committed Apr 30, 2017
1 parent da92f6c commit 8e6105e
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 16 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -6,7 +6,7 @@ documentation = "https://docs.rs/relm/"
license = "MIT"
name = "relm"
repository = "https://github.com/antoyo/relm"
version = "0.9.3"
version = "0.9.4"

[badges]
travis-ci = { repository = "antoyo/relm" }
Expand Down
4 changes: 2 additions & 2 deletions examples/key-events-attribute.rs
Expand Up @@ -74,13 +74,13 @@ impl Widget for Win {
gtk::Window {
key_press_event(_, key) => (Press, Inhibit(false)),
key_release_event(_, key) => (Release, Inhibit(false)),
delete_event(_, _) with model => return Self::quit(model),
delete_event(_, _) with model => return self.quit(model),
}
}
}

impl Win {
fn quit(model: &mut Model) -> (Option<Msg>, Inhibit) {
fn quit(&self, model: &mut Model) -> (Option<Msg>, Inhibit) {
if model.press_count > 3 {
(None, Inhibit(true))
}
Expand Down
8 changes: 6 additions & 2 deletions examples/key-events.rs
Expand Up @@ -86,10 +86,14 @@ impl Widget for Win {

window.show_all();

let win = Win {
window: window.clone(),
};

connect!(relm, window, connect_key_press_event(_, _) (Press, Inhibit(false)));
connect!(relm, window, connect_key_release_event(_, _) (Release, Inhibit(false)));
connect!(relm, window, connect_delete_event(_, _) with model
Self::quit(model));
win.quit(model));

Win {
window: window,
Expand All @@ -98,7 +102,7 @@ impl Widget for Win {
}

impl Win {
fn quit(model: &mut Model) -> (Option<Msg>, Inhibit) {
fn quit(&self, model: &mut Model) -> (Option<Msg>, Inhibit) {
if model.press_count > 3 {
(None, Inhibit(true))
}
Expand Down
2 changes: 1 addition & 1 deletion relm-gen-widget/Cargo.toml
Expand Up @@ -5,7 +5,7 @@ documentation = "https://docs.rs/relm-gen-widget/"
license = "MIT"
name = "relm-gen-widget"
repository = "https://github.com/antoyo/relm"
version = "0.9.9"
version = "0.9.10"

[dependencies]
lazy_static = "^0.2.4"
Expand Down
36 changes: 31 additions & 5 deletions relm-gen-widget/src/gen.rs
Expand Up @@ -24,7 +24,7 @@ use std::collections::HashMap;
use quote::Tokens;
use syn::{Generics, Ident, Path, Ty, parse_path};

use parser::{GtkWidget, RelmWidget, Widget};
use parser::{GtkWidget, RelmWidget, Widget, RELM_WIDGET_CLONE_IDENT, RELM_WIDGET_SELF_IDENT};
use parser::EventValue::{CurrentWidget, ForeignWidget};
use parser::EventValueReturn::{CallReturn, Return, WithoutReturn};
use parser::EitherWidget::{Gtk, Relm};
Expand Down Expand Up @@ -93,9 +93,16 @@ pub fn gen(name: &Ident, typ: &Ty, widget: &Widget, driver: &mut Driver) -> (Tok
let widget_names2 = widget_names1;
let events = &generator.events;
let phantom_field = gen_phantom_field(typ);
let self_ident = Ident::new(RELM_WIDGET_SELF_IDENT);
let code = quote! {
#widget_tokens

let #self_ident: ::relm::ManuallyDrop<Self> = ::relm::ManuallyDrop::new(#name {
#root_widget_name: #root_widget_name.clone(),
#(#widget_names1: #widget_names2.clone(),)*
#phantom_field
});

#(#events)*

#name {
Expand Down Expand Up @@ -212,20 +219,39 @@ impl<'a> Generator<'a> {
quote! {
}
};
let clone_ident = Ident::new(RELM_WIDGET_CLONE_IDENT);
let self_ident = Ident::new(RELM_WIDGET_SELF_IDENT);
let (self_ident, clone) =
if gtk_widget.save {
(quote! {
#self_ident .
}, quote! {
let #clone_ident = ::relm::ManuallyDrop::new(#self_ident.clone());
})
}
else {
(quote! {
}, quote! {
})
};
let connect =
match event.value {
CurrentWidget(WithoutReturn(ref event_value)) => quote! {
connect!(relm, #widget_name, #event_ident(#(#event_params),*), #event_value);
#clone
connect!(relm, #self_ident #widget_name, #event_ident(#(#event_params),*), #event_value);
},
ForeignWidget(ref foreign_widget_name, WithoutReturn(ref event_value)) => quote! {
connect!(#widget_name, #event_ident(#(#event_params),*), #foreign_widget_name, #event_value);
#clone
connect!(#self_ident #widget_name, #event_ident(#(#event_params),*), #foreign_widget_name, #event_value);
},
CurrentWidget(Return(ref event_value, ref return_value)) => quote! {
connect!(relm, #widget_name, #event_ident(#(#event_params),*) (#event_value, #return_value));
#clone
connect!(relm, #self_ident #widget_name, #event_ident(#(#event_params),*) (#event_value, #return_value));
},
ForeignWidget(_, Return(_, _)) | ForeignWidget(_, CallReturn(_)) => unreachable!(),
CurrentWidget(CallReturn(ref func)) => quote! {
connect!(relm, #widget_name, #event_ident(#(#event_params),*) #event_model_ident #func);
#clone
connect!(relm, #self_ident #widget_name, #event_ident(#(#event_params),*) #event_model_ident #func);
},

};
Expand Down
15 changes: 10 additions & 5 deletions relm-gen-widget/src/parser.rs
Expand Up @@ -39,6 +39,9 @@ use self::EventValue::*;
use self::EventValueReturn::*;
use self::EitherWidget::*;

pub const RELM_WIDGET_CLONE_IDENT: &str = "__relm_widget_self_clone";
pub const RELM_WIDGET_SELF_IDENT: &str = "__relm_widget_self";

lazy_static! {
static ref NAMES_INDEX: Mutex<HashMap<String, u32>> = Mutex::new(HashMap::new());
}
Expand Down Expand Up @@ -202,7 +205,7 @@ pub fn parse(tokens: &[TokenTree]) -> Widget {
else {
tokens.to_vec()
};
let (mut widget, _, parent_id) = parse_child(&tokens);
let (mut widget, _, parent_id) = parse_child(&tokens, true);
widget.parent_id = parent_id;
widget
}
Expand All @@ -224,7 +227,7 @@ fn parse_widget(tokens: &[TokenTree], save: bool) -> (Widget, &[TokenTree]) {
let mut tts = &tts[..];
while !tts.is_empty() {
if tts[0] == Token(Pound) || try_parse_name(tts).is_some() {
let (child, new_tts, _) = parse_child(tts);
let (child, new_tts, _) = parse_child(tts, false);
tts = new_tts;
children.push(child);
}
Expand Down Expand Up @@ -257,15 +260,15 @@ fn parse_widget(tokens: &[TokenTree], save: bool) -> (Widget, &[TokenTree]) {
(widget, &tokens[1..])
}

fn parse_child(mut tokens: &[TokenTree]) -> (Widget, &[TokenTree], Option<String>) {
fn parse_child(mut tokens: &[TokenTree], root: bool) -> (Widget, &[TokenTree], Option<String>) {
let (mut attributes, new_tokens) = parse_attributes(tokens);
let container_type = attributes.remove("container")
.map(|typ| typ.map(str::to_string));
tokens = new_tokens;
let name = attributes.get("name").and_then(|name| *name);
let (mut widget, new_tokens) =
if tokens.get(1) == Some(&Token(ModSep)) {
parse_widget(tokens, name.is_some())
parse_widget(tokens, name.is_some() || root)
}
else {
parse_relm_widget(tokens)
Expand Down Expand Up @@ -442,6 +445,8 @@ fn parse_value(tokens: &[TokenTree]) -> (Tokens, &[TokenTree]) {
let mut i = 0;
while i < tokens.len() {
match tokens[i] {
Token(Ident(ref ident)) if *ident == syn::Ident::new("self") =>
Token(Ident(syn::Ident::new(RELM_WIDGET_CLONE_IDENT))).to_tokens(&mut current_param),
Token(Comma) => break,
ref token => token.to_tokens(&mut current_param),
}
Expand Down Expand Up @@ -549,7 +554,7 @@ fn parse_relm_widget(tokens: &[TokenTree]) -> (Widget, &[TokenTree]) {
false
};
if tts[0] == Token(Pound) || is_child {
let (child, new_tts, _) = parse_child(tts);
let (child, new_tts, _) = parse_child(tts, false);
tts = new_tts;
children.push(child);
}
Expand Down
25 changes: 25 additions & 0 deletions src/lib.rs
Expand Up @@ -97,6 +97,7 @@ mod macros;
mod stream;
mod widget;

use std::ops::Deref;
use std::sync::{Arc, Mutex};
use std::time::SystemTime;

Expand Down Expand Up @@ -188,6 +189,30 @@ macro_rules! use_impl_self_type {
};
}

// TODO: remove this hack.
/// A small type to avoid running the destructor of `T`
pub struct ManuallyDrop<T> { inner: Option<T> }

impl<T> ManuallyDrop<T> {
pub fn new(t: T) -> ManuallyDrop<T> {
ManuallyDrop { inner: Some(t) }
}
}

impl<T> Deref for ManuallyDrop<T> {
type Target = T;

fn deref(&self) -> &T {
self.inner.as_ref().unwrap()
}
}

impl<T> Drop for ManuallyDrop<T> {
fn drop(&mut self) {
std::mem::forget(self.inner.take())
}
}

/// Handle connection of futures to send messages to the [`update()`](trait.Widget.html#tymethod.update) and
/// [`update_command()`](trait.Widget.html#method.update_command) methods.
pub struct Relm<MSG: Clone + DisplayVariant> {
Expand Down

0 comments on commit 8e6105e

Please sign in to comment.