From c11cfaa26a45990dd56e097ae10054c4e2482aa4 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Sun, 18 Oct 2020 12:48:21 +0200 Subject: [PATCH] Simplify PrimitiveValue, add comments for doc-gen --- src/app.rs | 25 +++++-- src/config/element.rs | 18 ++--- src/config/mod.rs | 7 +- src/script_var_handler.rs | 2 +- src/util.rs | 17 +++++ src/value.rs | 107 ++++++++++++--------------- src/widgets/widget_definitions.rs | 116 ++++++++++++++++++++---------- 7 files changed, 173 insertions(+), 119 deletions(-) diff --git a/src/app.rs b/src/app.rs index ec7b8a4..4196a39 100644 --- a/src/app.rs +++ b/src/app.rs @@ -33,11 +33,18 @@ pub enum EwwCommand { PrintState(crossbeam_channel::Sender), } +#[derive(Debug, Clone, PartialEq)] +pub struct EwwWindow { + pub name: config::WindowName, + pub definition: config::EwwWindowDefinition, + pub gtk_window: gtk::Window, +} + #[derive(DebugStub)] pub struct App { pub eww_state: eww_state::EwwState, pub eww_config: config::EwwConfig, - pub windows: HashMap, + pub windows: HashMap, pub css_provider: gtk::CssProvider, pub app_evt_send: glib::Sender, #[debug_stub = "ScriptVarHandler(...)"] @@ -80,7 +87,7 @@ impl App { .windows .remove(window_name) .context(format!("No window with name '{}' is running.", window_name))?; - window.close(); + window.gtk_window.close(); self.eww_state.clear_window_state(window_name); Ok(()) @@ -146,7 +153,13 @@ impl App { window.set_keep_below(true); } - self.windows.insert(window_name.clone(), window); + let eww_window = EwwWindow { + definition: window_def, + gtk_window: window, + name: window_name.clone(), + }; + + self.windows.insert(window_name.clone(), eww_window); Ok(()) } @@ -163,9 +176,9 @@ impl App { let windows = self.windows.clone(); for (window_name, window) in windows { - let old_pos = window.get_position(); - let old_size = window.get_size(); - window.close(); + let old_pos = window.definition.position; + let old_size = window.definition.size; + window.gtk_window.close(); self.open_window(&window_name, Some(old_pos.into()), Some(old_size.into()))?; } Ok(()) diff --git a/src/config/element.rs b/src/config/element.rs index 430d518..78a3dab 100644 --- a/src/config/element.rs +++ b/src/config/element.rs @@ -80,7 +80,7 @@ impl WidgetUse { XmlNode::Text(text) if PATTERN.is_match(&text.text()) => WidgetUse::from_text_with_var_refs(&text.text()), XmlNode::Text(text) => WidgetUse::simple_text(AttrValue::parse_string(text.text())), XmlNode::Element(elem) => WidgetUse { - name: elem.tag_name().to_string(), + name: elem.tag_name().to_owned(), children: with_text_pos_context! { elem => elem.children().map(WidgetUse::from_xml_node).collect::>()?}?, attrs: elem .attributes() @@ -98,7 +98,7 @@ impl WidgetUse { WidgetUse { name: "label".to_owned(), children: vec![], - attrs: hashmap! { "text".to_string() => text }, // TODO this hardcoded "text" is dumdum + attrs: hashmap! { "text".to_owned() => text }, // TODO this hardcoded "text" is dumdum ..WidgetUse::default() } } @@ -136,7 +136,7 @@ enum StringOrVarRef { impl StringOrVarRef { fn to_attr_value(self) -> AttrValue { match self { - StringOrVarRef::String(x) => AttrValue::Concrete(PrimitiveValue::parse_string(&x)), + StringOrVarRef::String(x) => AttrValue::Concrete(PrimitiveValue::from_string(x)), StringOrVarRef::VarRef(x) => AttrValue::VarRef(VarName(x)), } } @@ -190,12 +190,12 @@ mod test { use pretty_assertions::assert_eq; fn mk_attr_str(s: &str) -> AttrValue { - AttrValue::Concrete(PrimitiveValue::String(s.to_owned())) + AttrValue::Concrete(PrimitiveValue::from_string(s.to_owned())) } #[test] fn test_simple_text() { - let expected_attr_value = AttrValue::Concrete(PrimitiveValue::String("my text".to_owned())); + let expected_attr_value = AttrValue::Concrete(PrimitiveValue::from_string("my text".to_owned())); let widget = WidgetUse::simple_text(expected_attr_value.clone()); assert_eq!( widget, @@ -244,12 +244,12 @@ mod test { let expected = WidgetUse { name: "widget_name".to_owned(), attrs: hashmap! { - "attr1".to_owned() => AttrValue::Concrete(PrimitiveValue::String("hi".to_owned())), - "attr2".to_owned() => AttrValue::Concrete(PrimitiveValue::Number(12f64)), + "attr1".to_owned() => AttrValue::Concrete(PrimitiveValue::from_string("hi".to_owned())), + "attr2".to_owned() => AttrValue::Concrete(PrimitiveValue::from_string("12".to_owned())), }, children: vec![ WidgetUse::new("child_widget".to_owned(), Vec::new()), - WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::String("foo".to_owned()))), + WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::from_string("foo".to_owned()))), ], ..WidgetUse::default() }; @@ -271,7 +271,7 @@ mod test { size: Some((12, 20)), structure: WidgetUse { name: "layout".to_owned(), - children: vec![WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::String( + children: vec![WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::from_string( "test".to_owned(), )))], attrs: HashMap::new(), diff --git a/src/config/mod.rs b/src/config/mod.rs index 23ae2fb..e12bbf0 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -58,7 +58,7 @@ impl ScriptVar { pub fn initial_value(&self) -> Result { match self { ScriptVar::Poll(x) => Ok(crate::run_command(&x.command)?), - ScriptVar::Tail(_) => Ok(PrimitiveValue::String(String::new())), + ScriptVar::Tail(_) => Ok(PrimitiveValue::from_string(String::new())), } } @@ -126,9 +126,8 @@ impl EwwConfig { "var" => { initial_variables.insert( VarName(node.attr("name")?.to_owned()), - PrimitiveValue::parse_string( - &node - .only_child() + PrimitiveValue::from_string( + node.only_child() .map(|c| c.as_text_or_sourcecode()) .unwrap_or_else(|_| String::new()), ), diff --git a/src/script_var_handler.rs b/src/script_var_handler.rs index 8ea238e..0196cf1 100644 --- a/src/script_var_handler.rs +++ b/src/script_var_handler.rs @@ -115,7 +115,7 @@ impl ScriptVarHandler { handle.read_line(&mut buffer)?; evt_send.send(app::EwwCommand::UpdateVar( var_name.clone(), - PrimitiveValue::parse_string(&buffer), + PrimitiveValue::from_string(buffer), ))?; } else if event.hangup { command_out_readers.remove(var_name); diff --git a/src/util.rs b/src/util.rs index cb9ab57..386d142 100644 --- a/src/util.rs +++ b/src/util.rs @@ -5,6 +5,23 @@ use itertools::Itertools; use serde::{Deserialize, Serialize}; use std::{fmt, path::Path}; +#[macro_export] +macro_rules! impl_many { + ($trait:ident<$typ:ty> $fn_name:ident{ + $( + for $for:ty => |$var:ident| $code:expr + );*; + }) => { + $(impl $trait<$typ> for $for { + type Error = anyhow::Error; + + fn $fn_name($var: $typ) -> Result { + $code + } + })* + } +} + /// read an scss file, replace all environment variable references within it and /// then parse it into css. pub fn parse_scss_from_file>(path: P) -> Result { diff --git a/src/value.rs b/src/value.rs index 6fddff7..326b929 100644 --- a/src/value.rs +++ b/src/value.rs @@ -6,20 +6,14 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use std::{convert::TryFrom, fmt}; +use crate::impl_many; + #[derive(Clone, PartialEq, Deserialize, Serialize, derive_more::From)] -pub enum PrimitiveValue { - String(String), - Number(f64), - Boolean(bool), -} +pub struct PrimitiveValue(String); impl fmt::Display for PrimitiveValue { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - PrimitiveValue::String(s) => write!(f, "\"{}\"", s), - PrimitiveValue::Number(n) => write!(f, "{}", n), - PrimitiveValue::Boolean(b) => write!(f, "{}", b), - } + write!(f, "\"{}\"", self.0) } } impl fmt::Debug for PrimitiveValue { @@ -34,80 +28,60 @@ impl std::str::FromStr for PrimitiveValue { /// parses the value, trying to turn it into a number and a boolean first, /// before deciding that it is a string. fn from_str(s: &str) -> Result { - Ok(PrimitiveValue::parse_string(s)) + Ok(PrimitiveValue::from_string(s.to_string())) } } -fn remove_surrounding(s: &str, surround: char) -> &str { - s.strip_prefix(surround).unwrap_or(s).strip_suffix(surround).unwrap_or(s) -} +impl_many!(TryFrom try_from { + for String => |x| x.as_string(); + for f64 => |x| x.as_f64(); + for bool => |x| x.as_bool(); +}); -impl TryFrom for String { - type Error = anyhow::Error; - - fn try_from(x: PrimitiveValue) -> Result { - x.as_string() +impl From for PrimitiveValue { + fn from(x: i32) -> Self { + PrimitiveValue(format!("{}", x)) } } -impl TryFrom for f64 { - type Error = anyhow::Error; - - fn try_from(x: PrimitiveValue) -> Result { - x.as_f64() - } -} - -impl TryFrom for bool { - type Error = anyhow::Error; - - fn try_from(x: PrimitiveValue) -> Result { - x.as_bool() +impl From for PrimitiveValue { + fn from(x: bool) -> Self { + PrimitiveValue(format!("{}", x)) } } impl From<&str> for PrimitiveValue { fn from(s: &str) -> Self { - PrimitiveValue::String(s.to_string()) + PrimitiveValue(s.to_string()) } } impl PrimitiveValue { - /// parses the value, trying to turn it into a number and a boolean first, - /// before deciding that it is a string. - pub fn parse_string(s: &str) -> Self { - s.parse() - .map(PrimitiveValue::Number) - .or_else(|_| s.parse().map(PrimitiveValue::Boolean)) - .unwrap_or_else(|_| PrimitiveValue::String(remove_surrounding(s, '\'').to_string())) + pub fn from_string(s: String) -> Self { + PrimitiveValue(s.to_string()) } + /// This will never fail pub fn as_string(&self) -> Result { - match self { - PrimitiveValue::String(x) => Ok(x.clone()), - PrimitiveValue::Number(x) => Ok(format!("{}", x)), - PrimitiveValue::Boolean(x) => Ok(format!("{}", x)), - } + Ok(self.0.to_owned()) } pub fn as_f64(&self) -> Result { - match self { - PrimitiveValue::Number(x) => Ok(*x), - PrimitiveValue::String(x) => x - .parse() - .map_err(|e| anyhow!("couldn't convert string {:?} to f64: {}", &self, e)), - _ => Err(anyhow!("{:?} is not an f64", &self)), - } + self.0 + .parse() + .map_err(|e| anyhow!("couldn't convert {:?} to f64: {}", &self, e)) + } + + pub fn as_i32(&self) -> Result { + self.0 + .parse() + .map_err(|e| anyhow!("couldn't convert {:?} to i32: {}", &self, e)) } pub fn as_bool(&self) -> Result { - match self { - PrimitiveValue::Boolean(x) => Ok(*x), - PrimitiveValue::String(x) => x - .parse() - .map_err(|e| anyhow!("couldn't convert string {:?} to bool: {}", &self, e)), - _ => Err(anyhow!("{:?} is not a string", &self)), - } + self.0 + .parse() + .map_err(|e| anyhow!("couldn't convert {:?} to bool: {}", &self, e)) } } @@ -148,21 +122,28 @@ pub enum AttrValue { impl AttrValue { pub fn as_string(&self) -> Result { match self { - AttrValue::Concrete(x) => Ok(x.as_string()?), + AttrValue::Concrete(x) => x.as_string(), _ => Err(anyhow!("{:?} is not a string", self)), } } pub fn as_f64(&self) -> Result { match self { - AttrValue::Concrete(x) => Ok(x.as_f64()?), + AttrValue::Concrete(x) => x.as_f64(), _ => Err(anyhow!("{:?} is not an f64", self)), } } + pub fn as_i32(&self) -> Result { + match self { + AttrValue::Concrete(x) => x.as_i32(), + _ => Err(anyhow!("{:?} is not an i32", self)), + } + } + pub fn as_bool(&self) -> Result { match self { - AttrValue::Concrete(x) => Ok(x.as_bool()?), + AttrValue::Concrete(x) => x.as_bool(), _ => Err(anyhow!("{:?} is not a bool", self)), } } @@ -184,7 +165,7 @@ impl AttrValue { if let Some(ref_name) = PATTERN.captures(&s).and_then(|cap| cap.get(1)).map(|x| x.as_str()) { AttrValue::VarRef(VarName(ref_name.to_owned())) } else { - AttrValue::Concrete(PrimitiveValue::String(s)) + AttrValue::Concrete(PrimitiveValue::from_string(s)) } } } diff --git a/src/widgets/widget_definitions.rs b/src/widgets/widget_definitions.rs index cae302a..02e253b 100644 --- a/src/widgets/widget_definitions.rs +++ b/src/widgets/widget_definitions.rs @@ -5,7 +5,7 @@ use crate::{ }; use anyhow::*; use gtk::{prelude::*, ImageExt}; -use std::{cell::RefCell, path::Path, rc::Rc}; +use std::{cell::RefCell, rc::Rc}; use gdk_pixbuf; @@ -17,12 +17,11 @@ use gdk_pixbuf; pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result> { let gtk_widget = match bargs.widget.name.as_str() { "box" => build_gtk_box(bargs)?.upcast(), - "slider" => build_gtk_scale(bargs)?.upcast(), + "scale" => build_gtk_scale(bargs)?.upcast(), "image" => build_gtk_image(bargs)?.upcast(), "button" => build_gtk_button(bargs)?.upcast(), "label" => build_gtk_label(bargs)?.upcast(), "text" => build_gtk_text(bargs)?.upcast(), - "aspect" => build_gtk_aspect_frame(bargs)?.upcast(), "literal" => build_gtk_literal(bargs)?.upcast(), "input" => build_gtk_input(bargs)?.upcast(), "calendar" => build_gtk_calendar(bargs)?.upcast(), @@ -32,6 +31,7 @@ pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result>> = Rc::new(RefCell::new(None)); resolve_block!(bargs, gtk_widget, { - prop(class: as_string) { gtk_widget.get_style_context().add_class(&class) }, - prop(valign: as_string) { gtk_widget.set_valign(parse_align(&valign)?) }, - prop(halign: as_string) { gtk_widget.set_halign(parse_align(&halign)?) }, - prop(width: as_f64 ) { gtk_widget.set_size_request(width as i32, gtk_widget.get_allocated_height()) }, - prop(height: as_f64 ) { gtk_widget.set_size_request(gtk_widget.get_allocated_width(), height as i32) }, - prop(active: as_bool = true) { gtk_widget.set_sensitive(active) }, + // @prop class - css class name + prop(class: as_string) { gtk_widget.get_style_context().add_class(&class) }, + // @prop valign - how to align this vertically. possible values: $alignment + prop(valign: as_string) { gtk_widget.set_valign(parse_align(&valign)?) }, + // @prop halign - how to align this horizontally. possible values: $alignment + prop(halign: as_string) { gtk_widget.set_halign(parse_align(&halign)?) }, + // @prop width - width of this element. note that this can not restrict the size if the contents stretch it + prop(width: as_f64) { gtk_widget.set_size_request(width as i32, gtk_widget.get_allocated_height()) }, + // @prop height - height of this element. note that this can not restrict the size if the contents stretch it + prop(height: as_f64) { gtk_widget.set_size_request(gtk_widget.get_allocated_width(), height as i32) }, + // @prop active - If this widget can be interacted with + prop(active: as_bool = true) { gtk_widget.set_sensitive(active) }, + // @prop visible - visibility of the widget prop(visible: as_bool = true) { // TODO how do i call this only after the widget has been mapped? this is actually an issue,.... if visible { gtk_widget.show(); } else { gtk_widget.hide(); } }, + // @prop style - inline css style applied to the widget prop(style: as_string) { gtk_widget.reset_style(); css_provider.load_from_data(format!("* {{ {} }}", style).as_bytes())?; gtk_widget.get_style_context().add_provider(&css_provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION) }, + // @prop onscroll - event to execute when the user scrolls with the mouse over the widget prop(onscroll: as_string) { gtk_widget.add_events(gdk::EventMask::SCROLL_MASK); gtk_widget.add_events(gdk::EventMask::SMOOTH_SCROLL_MASK); @@ -79,6 +88,7 @@ pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Wi )); old_id.map(|id| gtk_widget.disconnect(id)); }, + // @prop onhover - event to execute when the user hovers over the widget prop(onhover: as_string) { gtk_widget.add_events(gdk::EventMask::ENTER_NOTIFY_MASK); let old_id = on_hover_handler_id.replace(Some( @@ -92,23 +102,29 @@ pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Wi }); } -/// attributes that apply to all container widgets +/// @widget !container pub(super) fn resolve_container_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Container) { resolve_block!(bargs, gtk_widget, { + // @prop vexpand - should this container expand vertically prop(vexpand: as_bool = false) { gtk_widget.set_vexpand(vexpand) }, + // @prop hexpand - should this container expand horizontally prop(hexpand: as_bool = false) { gtk_widget.set_hexpand(hexpand) }, }); } +/// @widget !range pub(super) fn resolve_range_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Range) { let on_change_handler_id: Rc>> = Rc::new(RefCell::new(None)); gtk_widget.set_sensitive(false); resolve_block!(bargs, gtk_widget, { - prop(value : as_f64) { gtk_widget.set_value(value)}, - prop(min : as_f64) { gtk_widget.get_adjustment().set_lower(min)}, - prop(max : as_f64) { gtk_widget.get_adjustment().set_upper(max)}, - prop(orientation : as_string) { gtk_widget.set_orientation(parse_orientation(&orientation)?) }, - prop(onchange : as_string) { + // @prop value - the value + prop(value: as_f64) { gtk_widget.set_value(value)}, + // @prop min - the minimum value + prop(min: as_f64) { gtk_widget.get_adjustment().set_lower(min)}, + // @prop max - the maximum value + prop(max: as_f64) { gtk_widget.get_adjustment().set_upper(max)}, + // @prop onchange - command executed once the value is changes. The placeholder `{}`, used in the command will be replaced by the new value. + prop(onchange: as_string) { gtk_widget.set_sensitive(true); gtk_widget.add_events(gdk::EventMask::ENTER_NOTIFY_MASK); let old_id = on_change_handler_id.replace(Some( @@ -122,26 +138,35 @@ pub(super) fn resolve_range_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Ran }); } +/// @widget !orientable pub(super) fn resolve_orientable_attrs(bargs: &mut BuilderArgs, gtk_widget: >k::Range) { resolve_block!(bargs, gtk_widget, { + // @prop orientation - orientation of the widget. Possible values: $orientation prop(orientation: as_string) { gtk_widget.set_orientation(parse_orientation(&orientation)?) }, }); } // concrete widgets +/// @widget scale extends range +/// @desc a slider. fn build_gtk_scale(bargs: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Scale::new( gtk::Orientation::Horizontal, Some(>k::Adjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 1.0)), ); resolve_block!(bargs, gtk_widget, { - prop(flipped: as_bool) { gtk_widget.set_inverted(flipped) }, + // @prop flipped - flip the direction + prop(flipped: as_bool) { gtk_widget.set_inverted(flipped) }, + + // @prop draw-value - draw the value of the property prop(draw_value: as_bool = false) { gtk_widget.set_draw_value(draw_value) }, }); Ok(gtk_widget) } +/// @widget input +/// @desc an input field that doesn't yet really work fn build_gtk_input(bargs: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Entry::new(); let on_change_handler_id: Rc>> = Rc::new(RefCell::new(None)); @@ -162,10 +187,12 @@ fn build_gtk_input(bargs: &mut BuilderArgs) -> Result { Ok(gtk_widget) } +/// @widget button extends container fn build_gtk_button(bargs: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Button::new(); let on_click_handler_id: Rc>> = Rc::new(RefCell::new(None)); resolve_block!(bargs, gtk_widget, { + // @prop onclick - a command that get's run when the button is clicked prop(onclick: as_string) { gtk_widget.add_events(gdk::EventMask::ENTER_NOTIFY_MASK); let old_id = on_click_handler_id.replace(Some( @@ -178,38 +205,47 @@ fn build_gtk_button(bargs: &mut BuilderArgs) -> Result { Ok(gtk_widget) } +/// @widget image fn build_gtk_image(bargs: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Image::new(); resolve_block!(bargs, gtk_widget, { - prop(path: as_string) { - gtk_widget.set_from_file(Path::new(&path)); - }, - prop(path: as_string, width: as_f64, height: as_f64) { - let pixbuf = gdk_pixbuf::Pixbuf::from_file_at_size(std::path::PathBuf::from(path), width as i32, height as i32)?; + // @prop path - path to the image file + // @prop width - width of the image + // @prop height - height of the image + prop(path: as_string, width: as_i32 = 10000, height: as_i32 = 10000) { + let pixbuf = gdk_pixbuf::Pixbuf::from_file_at_size(std::path::PathBuf::from(path), width, height)?; gtk_widget.set_from_pixbuf(Some(&pixbuf)); } }); Ok(gtk_widget) } +/// @widget box extends container +/// @desc the main layout container fn build_gtk_box(bargs: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Box::new(gtk::Orientation::Horizontal, 0); resolve_block!(bargs, gtk_widget, { - prop(spacing: as_f64 = 0.0) { gtk_widget.set_spacing(spacing as i32) }, - prop(orientation: as_string) { gtk_widget.set_orientation(parse_orientation(&orientation)?) }, + // @prop spacing - spacing between elements + prop(spacing: as_i32 = 0) { gtk_widget.set_spacing(spacing) }, + // @prop orientation - orientation of the box. possible values: $orientation + prop(orientation: as_string) { gtk_widget.set_orientation(parse_orientation(&orientation)?) }, + // @prop space-evenly - space the widgets evenly. prop(space_evenly: as_bool = true) { gtk_widget.set_homogeneous(space_evenly) }, }); Ok(gtk_widget) } +/// @widget label fn build_gtk_label(bargs: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Label::new(None); resolve_block!(bargs, gtk_widget, { + // @prop - the text to display prop(text: as_string) { gtk_widget.set_text(&text) }, }); Ok(gtk_widget) } +/// @widget text fn build_gtk_text(_bargs: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Box::new(gtk::Orientation::Horizontal, 0); gtk_widget.set_halign(gtk::Align::Center); @@ -217,12 +253,15 @@ fn build_gtk_text(_bargs: &mut BuilderArgs) -> Result { Ok(gtk_widget) } +/// @widget literal +/// @desc a tag that allows you to render arbitrary XML. fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Frame::new(None); // TODO these clones here are dumdum let window_name = bargs.window_name.clone(); let widget_definitions = bargs.widget_definitions.clone(); resolve_block!(bargs, gtk_widget, { + // @prop - inline Eww XML that will be rendered as a widget. prop(content: as_string) { gtk_widget.get_children().iter().for_each(|w| gtk_widget.remove(w)); if !content.is_empty() { @@ -243,18 +282,26 @@ fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result { Ok(gtk_widget) } +/// @widget calendar fn build_gtk_calendar(bargs: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Calendar::new(); let on_click_handler_id: Rc>> = Rc::new(RefCell::new(None)); resolve_block!(bargs, gtk_widget, { - prop(day: as_f64) { gtk_widget.set_property_day(day as i32) }, - prop(month: as_f64) { gtk_widget.set_property_day(month as i32) }, - prop(year: as_f64) { gtk_widget.set_property_day(year as i32) }, - prop(show_details: as_bool) { gtk_widget.set_property_show_details(show_details) }, - prop(show_heading: as_bool) { gtk_widget.set_property_show_details(show_heading) }, - prop(show_day_names: as_bool) { gtk_widget.set_property_show_day_names(show_day_names) }, - prop(show_week_numbers: as_bool) { gtk_widget.set_property_show_week_numbers(show_week_numbers) }, - prop(show_heading: as_bool) { gtk_widget.set_property_show_heading(show_heading) }, + // @prop day - the selected day + prop(day: as_f64) { gtk_widget.set_property_day(day as i32) }, + // @prop month - the selected month + prop(month: as_f64) { gtk_widget.set_property_day(month as i32) }, + // @prop year - the selected year + prop(year: as_f64) { gtk_widget.set_property_day(year as i32) }, + // @prop show-details - show details + prop(show_details: as_bool) { gtk_widget.set_property_show_details(show_details) }, + // @prop show-heading - show heading line + prop(show_heading: as_bool) { gtk_widget.set_property_show_heading(show_heading) }, + // @prop show-day-names - show names of days + prop(show_day_names: as_bool) { gtk_widget.set_property_show_day_names(show_day_names) }, + // @prop show-week-numbers - show week numbers + prop(show_week_numbers: as_bool) { gtk_widget.set_property_show_week_numbers(show_week_numbers) }, + // @prop onclick - command to run when the user selects a date. The `{}` placeholder will be replaced by the selected date. prop(onclick: as_string) { let old_id = on_click_handler_id.replace(Some( gtk_widget.connect_day_selected(move |w| { @@ -272,11 +319,7 @@ fn build_gtk_calendar(bargs: &mut BuilderArgs) -> Result { Ok(gtk_widget) } -fn build_gtk_aspect_frame(_bargs: &mut BuilderArgs) -> Result { - let gtk_widget = gtk::AspectFrame::new(None, 0.5, 0.5, 1.0, true); - Ok(gtk_widget) -} - +/// @var orientation - "vertical", "v", "horizontal", "h" fn parse_orientation(o: &str) -> Result { Ok(match o { "vertical" | "v" => gtk::Orientation::Vertical, @@ -285,6 +328,7 @@ fn parse_orientation(o: &str) -> Result { }) } +/// @var align - "fill", "baseline", "center", "start", "end" fn parse_align(o: &str) -> Result { Ok(match o { "fill" => gtk::Align::Fill,