Simplify PrimitiveValue, add comments for doc-gen

This commit is contained in:
elkowar 2020-10-18 12:48:21 +02:00
parent de83f1fb69
commit c11cfaa26a
7 changed files with 173 additions and 119 deletions

View file

@ -33,11 +33,18 @@ pub enum EwwCommand {
PrintState(crossbeam_channel::Sender<String>),
}
#[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<config::WindowName, gtk::Window>,
pub windows: HashMap<config::WindowName, EwwWindow>,
pub css_provider: gtk::CssProvider,
pub app_evt_send: glib::Sender<EwwCommand>,
#[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(())

View file

@ -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::<Result<_>>()?}?,
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(),

View file

@ -58,7 +58,7 @@ impl ScriptVar {
pub fn initial_value(&self) -> Result<PrimitiveValue> {
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()),
),

View file

@ -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);

View file

@ -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<Self> {
$code
}
})*
}
}
/// read an scss file, replace all environment variable references within it and
/// then parse it into css.
pub fn parse_scss_from_file<P: AsRef<Path>>(path: P) -> Result<String> {

View file

@ -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<Self> {
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<PrimitiveValue> try_from {
for String => |x| x.as_string();
for f64 => |x| x.as_f64();
for bool => |x| x.as_bool();
});
impl TryFrom<PrimitiveValue> for String {
type Error = anyhow::Error;
fn try_from(x: PrimitiveValue) -> Result<Self> {
x.as_string()
impl From<i32> for PrimitiveValue {
fn from(x: i32) -> Self {
PrimitiveValue(format!("{}", x))
}
}
impl TryFrom<PrimitiveValue> for f64 {
type Error = anyhow::Error;
fn try_from(x: PrimitiveValue) -> Result<Self> {
x.as_f64()
}
}
impl TryFrom<PrimitiveValue> for bool {
type Error = anyhow::Error;
fn try_from(x: PrimitiveValue) -> Result<Self> {
x.as_bool()
impl From<bool> 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<String> {
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<f64> {
match self {
PrimitiveValue::Number(x) => Ok(*x),
PrimitiveValue::String(x) => x
self.0
.parse()
.map_err(|e| anyhow!("couldn't convert string {:?} to f64: {}", &self, e)),
_ => Err(anyhow!("{:?} is not an f64", &self)),
.map_err(|e| anyhow!("couldn't convert {:?} to f64: {}", &self, e))
}
pub fn as_i32(&self) -> Result<i32> {
self.0
.parse()
.map_err(|e| anyhow!("couldn't convert {:?} to i32: {}", &self, e))
}
pub fn as_bool(&self) -> Result<bool> {
match self {
PrimitiveValue::Boolean(x) => Ok(*x),
PrimitiveValue::String(x) => x
self.0
.parse()
.map_err(|e| anyhow!("couldn't convert string {:?} to bool: {}", &self, e)),
_ => Err(anyhow!("{:?} is not a string", &self)),
}
.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<String> {
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<f64> {
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<i32> {
match self {
AttrValue::Concrete(x) => x.as_i32(),
_ => Err(anyhow!("{:?} is not an i32", self)),
}
}
pub fn as_bool(&self) -> Result<bool> {
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))
}
}
}

View file

@ -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<Option<gtk::Widget>> {
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<Option<gtk
}
/// attributes that apply to all widgets
/// @widget !widget
pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Widget) {
let css_provider = gtk::CssProvider::new();
@ -53,21 +53,30 @@ pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Wi
let on_hover_handler_id: Rc<RefCell<Option<glib::SignalHandlerId>>> = Rc::new(RefCell::new(None));
resolve_block!(bargs, gtk_widget, {
// @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: 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 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: &gtk::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: &gtk::Wi
});
}
/// attributes that apply to all container widgets
/// @widget !container
pub(super) fn resolve_container_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::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: &gtk::Range) {
let on_change_handler_id: Rc<RefCell<Option<glib::SignalHandlerId>>> = 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: &gtk::Ran
});
}
/// @widget !orientable
pub(super) fn resolve_orientable_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::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<gtk::Scale> {
let gtk_widget = gtk::Scale::new(
gtk::Orientation::Horizontal,
Some(&gtk::Adjustment::new(0.0, 0.0, 100.0, 1.0, 1.0, 1.0)),
);
resolve_block!(bargs, gtk_widget, {
// @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<gtk::Entry> {
let gtk_widget = gtk::Entry::new();
let on_change_handler_id: Rc<RefCell<Option<glib::SignalHandlerId>>> = Rc::new(RefCell::new(None));
@ -162,10 +187,12 @@ fn build_gtk_input(bargs: &mut BuilderArgs) -> Result<gtk::Entry> {
Ok(gtk_widget)
}
/// @widget button extends container
fn build_gtk_button(bargs: &mut BuilderArgs) -> Result<gtk::Button> {
let gtk_widget = gtk::Button::new();
let on_click_handler_id: Rc<RefCell<Option<glib::SignalHandlerId>>> = 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<gtk::Button> {
Ok(gtk_widget)
}
/// @widget image
fn build_gtk_image(bargs: &mut BuilderArgs) -> Result<gtk::Image> {
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<gtk::Box> {
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 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<gtk::Label> {
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<gtk::Box> {
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<gtk::Box> {
Ok(gtk_widget)
}
/// @widget literal
/// @desc a tag that allows you to render arbitrary XML.
fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result<gtk::Frame> {
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<gtk::Frame> {
Ok(gtk_widget)
}
/// @widget calendar
fn build_gtk_calendar(bargs: &mut BuilderArgs) -> Result<gtk::Calendar> {
let gtk_widget = gtk::Calendar::new();
let on_click_handler_id: Rc<RefCell<Option<glib::SignalHandlerId>>> = Rc::new(RefCell::new(None));
resolve_block!(bargs, gtk_widget, {
// @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: 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 - 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<gtk::Calendar> {
Ok(gtk_widget)
}
fn build_gtk_aspect_frame(_bargs: &mut BuilderArgs) -> Result<gtk::AspectFrame> {
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<gtk::Orientation> {
Ok(match o {
"vertical" | "v" => gtk::Orientation::Vertical,
@ -285,6 +328,7 @@ fn parse_orientation(o: &str) -> Result<gtk::Orientation> {
})
}
/// @var align - "fill", "baseline", "center", "start", "end"
fn parse_align(o: &str) -> Result<gtk::Align> {
Ok(match o {
"fill" => gtk::Align::Fill,