Permalink
Browse files

Add support for child events in relm widgets

  • Loading branch information...
antoyo committed May 20, 2017
1 parent ab55ca3 commit a70ccadc97f7d1d304c9623f8dddd10d45bd5015
Showing with 63 additions and 9 deletions.
  1. +36 −0 examples/child-event.rs
  2. +6 −2 relm-gen-widget/src/gen.rs
  3. +21 −7 relm-gen-widget/src/parser.rs
View
@@ -44,6 +44,39 @@ use relm_attributes::widget;
use self::Msg::*;
#[widget]
impl Widget for TreeView {
fn init_view(&mut self) {
let columns = vec![Type::String];
let model = ListStore::new(&columns);
let row = model.append();
model.set_value(&row, 0, &"String".to_value());
let row = model.append();
model.set_value(&row, 0, &"Text".to_value());
let view_column = TreeViewColumn::new();
let cell = CellRendererText::new();
view_column.pack_start(&cell, true);
view_column.add_attribute(&cell, "text", 0);
self.tree_view.append_column(&view_column);
self.tree_view.set_model(Some(&model));
}
fn model() -> () {
}
fn update(&mut self, event: Msg) {
}
view! {
#[name="tree_view"]
gtk::TreeView {
selection.changed(selection) => SelectionChanged(selection.clone()),
}
}
}
#[derive(Msg)]
pub enum Msg {
SelectionChanged(TreeSelection),
@@ -86,6 +119,9 @@ impl Widget for Win {
gtk::TreeView {
selection.changed(selection) => SelectionChanged(selection.clone()),
},
TreeView {
selection.changed(selection) => SelectionChanged(selection.clone()),
},
},
delete_event(_, _) => (Quit, Inhibit(false)),
}
@@ -251,7 +251,7 @@ impl<'a> Generator<'a> {
for (name, event) in &gtk_widget.events {
self.collect_event(widget_name, gtk_widget.save, name, event);
}
for (&(ref child_name, ref name), event) in &gtk_widget.child_events {
for (&(ref child_name, ref name), event) in &widget.child_events {
let widget_name = Ident::new(format!("{}.get_{}()", widget_name, child_name));
self.collect_event(&widget_name, false, &name, event);
}
@@ -293,10 +293,14 @@ impl<'a> Generator<'a> {
self.events.push(connect);
}
}
let ident = Ident::new(format!("{}.widget().root()", widget_name));
for (name, event) in &relm_widget.gtk_events {
let ident = Ident::new(format!("{}.widget().root()", widget_name));
self.collect_event(&ident, true, name, event);
}
for (&(ref child_name, ref name), event) in &widget.child_events {
let ident = Ident::new(format!("{}.get_{}()", ident, child_name));
self.collect_event(&ident, false, &name, event);
}
}
fn gtk_widget(&mut self, widget: &Widget, gtk_widget: &GtkWidget, parent: Option<&Ident>,
@@ -48,6 +48,8 @@ lazy_static! {
static ref NAMES_INDEX: Mutex<HashMap<String, u32>> = Mutex::new(HashMap::new());
}
type ChildEvents = HashMap<(String, String), Event>;
#[derive(Clone, Copy, PartialEq)]
enum DefaultParam {
DefaultNoParam,
@@ -91,6 +93,7 @@ enum IsEventOrNot {
}
pub struct Widget {
pub child_events: ChildEvents,
pub child_properties: HashMap<String, Expr>,
pub children: Vec<Widget>,
pub container_type: Option<Option<String>>,
@@ -104,10 +107,11 @@ pub struct Widget {
impl Widget {
fn new_gtk(widget: GtkWidget, typ: Path, init_parameters: Vec<Expr>, children: Vec<Widget>,
properties: HashMap<String, Expr>, child_properties: HashMap<String, Expr>) -> Self
properties: HashMap<String, Expr>, child_properties: HashMap<String, Expr>, child_events: ChildEvents) -> Self
{
let name = gen_widget_name(&typ);
Widget {
child_events,
child_properties,
children,
container_type: None,
@@ -121,14 +125,15 @@ impl Widget {
}
fn new_relm(widget: RelmWidget, typ: Path, init_parameters: Vec<Expr>, children: Vec<Widget>,
properties: HashMap<String, Expr>, child_properties: HashMap<String, Expr>) -> Self
properties: HashMap<String, Expr>, child_properties: HashMap<String, Expr>, child_events: ChildEvents) -> Self
{
let mut name = gen_widget_name(&typ);
// Relm widgets are not used in the update() method; they are only saved to avoid dropping
// their channel too soon.
// So prepend an underscore to hide a warning.
name.insert(0, '_');
Widget {
child_events,
child_properties,
children,
container_type: None,
@@ -150,7 +155,6 @@ pub enum EitherWidget {
#[derive(Debug)]
pub struct GtkWidget {
pub child_events: HashMap<(String, String), Event>,
pub construct_properties: HashMap<syn::Ident, Expr>,
pub events: HashMap<String, Event>,
pub relm_name: Option<Ty>,
@@ -160,7 +164,6 @@ pub struct GtkWidget {
impl GtkWidget {
fn new() -> Self {
GtkWidget {
child_events: HashMap::new(),
construct_properties: HashMap::new(),
events: HashMap::new(),
relm_name: None,
@@ -231,6 +234,7 @@ fn parse_widget(tokens: &[TokenTree], save: bool) -> (Widget, &[TokenTree]) {
let mut children = vec![];
let mut properties = HashMap::new();
let mut child_properties = HashMap::new();
let mut child_events = HashMap::new();
gtk_widget.save = save;
if let TokenTree::Delimited(Delimited { delim: Paren, ref tts }) = tokens[0] {
if let TokenTree::Delimited(Delimited { delim: Brace, ref tts }) = tts[0] {
@@ -261,7 +265,7 @@ fn parse_widget(tokens: &[TokenTree], save: bool) -> (Widget, &[TokenTree]) {
let child_name = ident;
let (ident, new_tts) = parse_ident(&tts[1..]);
let (event, new_tts) = parse_event(new_tts, DefaultOneParam);
gtk_widget.child_events.insert((child_name, ident), event);
child_events.insert((child_name, ident), event);
tts = new_tts;
},
TokenTree::Delimited(Delimited { delim: Paren, .. }) | Token(FatArrow) => {
@@ -281,7 +285,8 @@ fn parse_widget(tokens: &[TokenTree], save: bool) -> (Widget, &[TokenTree]) {
else {
panic!("Expected {{ but found `{:?}` in view! macro", tokens[0]);
}
let widget = Widget::new_gtk(gtk_widget, gtk_type, init_parameters, children, properties, child_properties);
let widget = Widget::new_gtk(gtk_widget, gtk_type, init_parameters, children, properties, child_properties,
child_events);
(widget, &tokens[1..])
}
@@ -609,6 +614,7 @@ fn parse_relm_widget(tokens: &[TokenTree]) -> (Widget, &[TokenTree]) {
let mut children = vec![];
let mut properties = HashMap::new();
let mut child_properties = HashMap::new();
let mut child_events = HashMap::new();
if let TokenTree::Delimited(Delimited { delim: Paren, ref tts }) = tokens[0] {
let parameters = parse_comma_list(tts);
init_parameters = parameters;
@@ -642,6 +648,13 @@ fn parse_relm_widget(tokens: &[TokenTree]) -> (Widget, &[TokenTree]) {
Token(Colon) => {
tts = parse_value_or_child_properties(tts, ident, &mut child_properties, &mut properties);
},
Token(Dot) => {
let child_name = ident;
let (ident, new_tts) = parse_ident(&tts[1..]);
let (event, new_tts) = parse_event(new_tts, DefaultOneParam);
child_events.insert((child_name, ident), event);
tts = new_tts;
},
TokenTree::Delimited(Delimited { delim: Paren, .. }) | Token(FatArrow) => {
if ident.chars().next().map(|char| char.is_lowercase()) == Some(false) {
// Uppercase is a msg.
@@ -666,7 +679,8 @@ fn parse_relm_widget(tokens: &[TokenTree]) -> (Widget, &[TokenTree]) {
}
}
}
let widget = Widget::new_relm(relm_widget, relm_type, init_parameters, children, properties, child_properties);
let widget = Widget::new_relm(relm_widget, relm_type, init_parameters, children, properties, child_properties,
child_events);
(widget, &tokens[1..])
}

0 comments on commit a70ccad

Please sign in to comment.