Permalink
Browse files

Add support for construct properties

  • Loading branch information...
antoyo committed May 17, 2017
1 parent 06ec550 commit 39ea6da0bd3649e53344e777e9e6a9ee7c064424
Showing with 257 additions and 28 deletions.
  1. +43 −15 Cargo.toml
  2. +100 −0 examples/buttons-construct-prop-attribute.rs
  3. +39 −7 relm-gen-widget/src/gen.rs
  4. +2 −0 relm-gen-widget/src/lib.rs
  5. +60 −2 relm-gen-widget/src/parser.rs
  6. +1 −2 src/container.rs
  7. +12 −2 src/lib.rs
View
@@ -9,19 +9,32 @@ repository = "https://github.com/antoyo/relm"
version = "0.9.6"
[badges]
travis-ci = { repository = "antoyo/relm", branch = "master" }
appveyor = { repository = "antoyo/relm", branch = "master" }
[badges.appveyor]
branch = "master"
repository = "antoyo/relm"
[badges.travis-ci]
branch = "master"
repository = "antoyo/relm"
[dependencies]
futures = { git = "https://github.com/alexcrichton/futures-rs", branch = "spawn-trait" }
futures-glib = { git = "https://github.com/antoyo/futures-glib-rs" }
glib = "^0.1.2"
glib-itc = "^0.1.1"
glib-sys = "^0.3.4"
gobject-sys = "^0.3.3"
gtk = "^0.1.1"
gtk-sys = "^0.3.3"
libc = "^0.2.22"
log = "^0.3.7"
[dependencies.futures]
branch = "spawn-trait"
git = "https://github.com/alexcrichton/futures-rs"
[dependencies.futures-glib]
git = "https://github.com/antoyo/futures-glib-rs"
[dependencies.relm-core]
path = "relm-core"
version = "^0.1.1"
@@ -39,6 +52,10 @@ tokio-service = "^0.1.0"
twist = "^0.5.0"
url = "^1.4.0"
[dev-dependencies.relm-attributes]
path = "relm-attributes"
version = "^0.9.0"
[dev-dependencies.relm-derive]
path = "relm-derive"
version = "^0.9.0"
@@ -47,20 +64,31 @@ version = "^0.9.0"
path = "relm-test"
version = "^0.1.0"
[dev-dependencies.relm-attributes]
path = "relm-attributes"
version = "^0.9.0"
[features]
nightly = []
use_impl_trait = []
[package.metadata.release]
pre-release-replacements = [
{file="README.adoc", search="relm = \"[a-z0-9^\\.-]+\"", replace="relm = \"{{version}}\""},
{file="src/lib.rs", search="relm = \"[a-z0-9^\\.-]+\"", replace="relm = \"{{version}}\""},
{file="examples/buttons-derive/Cargo.toml", search="relm = \"[a-z0-9^\\.-]+\"", replace="relm = \"{{version}}\""},
]
[metadata]
[metadata.release]
[[metadata.release.pre-release-replacements]]
file = "README.adoc"
replace = "relm = \"{{version}}\""
search = "relm = \"[a-z0-9^\\.-]+\""
[[metadata.release.pre-release-replacements]]
file = "src/lib.rs"
replace = "relm = \"{{version}}\""
search = "relm = \"[a-z0-9^\\.-]+\""
[[metadata.release.pre-release-replacements]]
file = "examples/buttons-derive/Cargo.toml"
replace = "relm = \"{{version}}\""
search = "relm = \"[a-z0-9^\\.-]+\""
[replace]
"futures:0.1.13" = { git = "https://github.com/alexcrichton/futures-rs", branch = "spawn-trait" }
[replace."futures:0.1.13"]
branch = "spawn-trait"
git = "https://github.com/alexcrichton/futures-rs"
@@ -0,0 +1,100 @@
/*
* Copyright (c) 2017 Boucher, Antoni <bouanto@zoho.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#![feature(proc_macro)]
extern crate gtk;
#[macro_use]
extern crate relm;
extern crate relm_attributes;
#[macro_use]
extern crate relm_derive;
use gtk::{
ButtonExt,
Inhibit,
OrientableExt,
WidgetExt,
};
use gtk::Orientation::Vertical;
use relm::Widget;
use relm_attributes::widget;
use self::Msg::*;
// Define the structure of the model.
pub struct Model {
counter: i32,
}
// The messages that can be sent to the update function.
#[derive(Msg)]
pub enum Msg {
Decrement,
Increment,
Quit,
}
#[widget]
impl Widget for Win {
// The initial model.
fn model() -> Model {
Model {
counter: 0,
}
}
// Update the model according to the message received.
fn update(&mut self, event: Msg) {
match event {
Decrement => self.model.counter -= 1,
Increment => self.model.counter += 1,
Quit => gtk::main_quit(),
}
}
view! {
gtk::Window {
gtk::Box {
// Set the orientation property of the Box.
orientation: Vertical,
// Create a Button inside the Box.
gtk::Button({ label: "+" }) {
// Send the message Increment when the button is clicked.
clicked => Increment,
},
gtk::Label {
// Bind the text property of the label to the counter attribute of the model.
text: &self.model.counter.to_string(),
},
gtk::Button {
clicked => Decrement,
label: "-",
},
},
delete_event(_, _) => (Quit, Inhibit(false)),
}
}
}
fn main() {
Win::run(()).unwrap();
}
View
@@ -307,7 +307,7 @@ impl<'a> Generator<'a> {
self.relm_widgets.insert(widget_name.clone(), struct_name.clone());
}
let construct_widget = gen_construct_widget(widget);
let construct_widget = gen_construct_widget(widget, gtk_widget);
self.collect_events(widget, gtk_widget);
let children: Vec<_> = widget.children.iter()
@@ -369,23 +369,55 @@ impl<'a> Generator<'a> {
}
}
fn gen_construct_widget(widget: &Widget) -> Tokens {
fn gen_construct_widget(widget: &Widget, gtk_widget: &GtkWidget) -> Tokens {
let struct_name = &widget.typ;
let params = &widget.init_parameters;
let properties_count = gtk_widget.construct_properties.len() as u32;
let mut parameters = vec![];
for (key, value) in gtk_widget.construct_properties.iter() {
let key = key.to_string();
parameters.push(quote! {
::relm::GParameter {
name: ::relm::ToGlibPtr::to_glib_full(#key),
value: ::std::ptr::read(::relm::ToGlibPtr::to_glib_none(&::gtk::ToValue::to_value(&#value)).0),
}
});
}
// TODO: use this new code when g_object_new_with_properties() is released.
/*let mut names = vec![];
let mut values = vec![];
for (key, value) in gtk_widget.construct_properties.iter() {
let key = key.to_string();
names.push(quote! {
#key
});
values.push(quote! {
&#value
});
}*/
if widget.init_parameters.is_empty() {
quote! {
unsafe {
use gtk::StaticType;
use relm::{Downcast, FromGlibPtrNone, ToGlib};
::gtk::Widget::from_glib_none(::relm::g_object_new(#struct_name::static_type().to_glib(),
#(#params,)* ::std::ptr::null() as *const _) as *mut _)
.downcast_unchecked()
use relm::{Downcast, FromGlibPtrNone};
let mut parameters = [#(#parameters),*];
::gtk::Widget::from_glib_none(::relm::g_object_newv(
::relm::ToGlib::to_glib(&#struct_name::static_type()),
#properties_count, parameters.as_mut_ptr()) as *mut _)
.downcast_unchecked()
// TODO: use this new code when g_object_new_with_properties() is released.
/*let names: &[&str] = &[#(#names),*];
let values: &[&::gtk::ToValue] = &[#(#values),*];
::gtk::Widget::from_glib_none(::relm::g_object_new_with_properties(#struct_name::static_type().to_glib(),
#properties_count, ::relm::ToGlibPtr::to_glib_full(&names),
::relm::ToGlibPtr::to_glib_full(&values) as *mut _) as *mut _)
.downcast_unchecked()*/
}
}
}
else {
let params = &widget.init_parameters;
quote! {
#struct_name::new(#(#params),*)
}
@@ -25,6 +25,8 @@
* TODO: think about conditions and loops (widget-list).
*/
#![recursion_limit="128"]
#[macro_use]
extern crate lazy_static;
#[macro_use]
@@ -22,6 +22,7 @@
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
use std::mem;
use std::sync::Mutex;
use quote::{Tokens, ToTokens};
@@ -150,6 +151,7 @@ pub enum EitherWidget {
#[derive(Debug)]
pub struct GtkWidget {
pub child_events: HashMap<(String, String), Event>,
pub construct_properties: HashMap<syn::Ident, Tokens>,
pub events: HashMap<String, Event>,
pub relm_name: Option<Ty>,
pub save: bool,
@@ -159,6 +161,7 @@ impl GtkWidget {
fn new() -> Self {
GtkWidget {
child_events: HashMap::new(),
construct_properties: HashMap::new(),
events: HashMap::new(),
relm_name: None,
save: false,
@@ -228,8 +231,12 @@ fn parse_widget(tokens: &[TokenTree], save: bool) -> (Widget, &[TokenTree]) {
let mut child_properties = HashMap::new();
gtk_widget.save = save;
if let TokenTree::Delimited(Delimited { delim: Paren, ref tts }) = tokens[0] {
let parameters = parse_comma_list(tts);
init_parameters = parameters;
if let TokenTree::Delimited(Delimited { delim: Brace, ref tts }) = tts[0] {
gtk_widget.construct_properties = parse_hash(tts);
}
else {
init_parameters = parse_comma_list(tts);
}
tokens = &tokens[1..];
}
if let TokenTree::Delimited(Delimited { delim: Brace, ref tts }) = tokens[0] {
@@ -357,6 +364,56 @@ fn parse_comma_ident_list(tokens: &[TokenTree]) -> Vec<syn::Ident> {
params
}
enum HashState {
InName,
AfterName,
InValue,
}
use self::HashState::*;
fn parse_hash(tokens: &[TokenTree]) -> HashMap<syn::Ident, Tokens> {
let mut params = HashMap::new();
let mut current_param = Tokens::new();
let mut state = InName;
let mut name = syn::Ident::new("");
for token in tokens {
match state {
InName => {
// FIXME: support ident with dash (-).
if let Token(Ident(ref ident)) = *token {
name = ident.clone();
state = AfterName;
}
else {
panic!("Expected ident, but found `{:?}` in view! macro", token);
}
},
AfterName => {
if *token == Token(Colon) {
state = InValue;
}
else {
panic!("Expected colon, but found `{:?}` in view! macro", token);
}
},
InValue => {
if *token == Token(Comma) {
let ident = mem::replace(&mut name, syn::Ident::new(""));
params.insert(ident, current_param);
current_param = Tokens::new();
}
else {
token.to_tokens(&mut current_param);
}
},
}
}
// FIXME: could be an empty hash.
params.insert(name, current_param);
params
}
fn parse_comma_list(tokens: &[TokenTree]) -> Vec<Tokens> {
let mut params = vec![];
let mut current_param = Tokens::new();
@@ -369,6 +426,7 @@ fn parse_comma_list(tokens: &[TokenTree]) -> Vec<Tokens> {
token.to_tokens(&mut current_param);
}
}
// FIXME: could be an empty list.
params.push(current_param);
params
}
View
@@ -19,9 +19,8 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
use glib::Cast;
use gtk;
use gtk::{ContainerExt, IsA, Object, WidgetExt};
use gtk::{Cast, ContainerExt, IsA, Object, WidgetExt};
use component::Component;
use super::{DisplayVariant, Relm, create_widget, init_component};
Oops, something went wrong.

0 comments on commit 39ea6da

Please sign in to comment.