This commit is contained in:
elkowar 2020-10-07 21:02:06 +02:00
parent 7187b32ae5
commit 11139ad4dc
2 changed files with 63 additions and 116 deletions

View file

@ -109,58 +109,47 @@ pub fn build_gtk_widget(
}
#[macro_export]
macro_rules! resolve {
macro_rules! resolve_block {
($args:ident, $gtk_widget:ident, {
$(
$func:ident => $attr:literal $( = $default:literal)? $( = req $(@$required:tt)?)? => |$arg:ident| $body:expr
prop( $( $attr_name:ident : $typecast_func:ident $(= $default:expr)?),*) $code:block
),+ $(,)?
}) => {{
}) => {
$({
$(
resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body);
)+
}};
$args.unhandled_attrs.retain(|a| a != &::std::stringify!($attr_name).replace('_', "-"));
)*
($args:ident, $gtk_widget:ident, {
$($func:ident => {
$($attr:literal $(= $default:literal)? $(= req $(@$required:tt)?)? => |$arg:ident| $body:expr),+ $(,)?
}),+ $(,)?
}) => {{
$($(
resolve!($args, $gtk_widget, $func => $attr $( [ $default ] )* $($($required)*)* => |$arg| $body);
)+)+
}};
// optional
($args:ident, $gtk_widget:ident, $func:ident => $attr:literal => |$arg:ident| $body:expr) => {
$args.unhandled_attrs.retain(|a| a != &$attr);
if let Some(attr_value) = $args.widget.attrs.get($attr) {
$args.eww_state.$func($args.local_env, attr_value, {
let $gtk_widget = $gtk_widget.clone();
move |$arg| { $body; }
});
let attr_map: Result<_> = try {
::maplit::hashmap! {
$(
::std::stringify!($attr_name).to_owned() => resolve_block!(@get_value $args, &::std::stringify!($attr_name).replace('_', "-"), $(= $default)?)
),*
}
};
// required
($args:ident, $gtk_widget:ident, $func:ident => $attr:literal req => |$arg:ident| $body:expr) => {
$args.unhandled_attrs.retain(|a| a != &$attr);
$args.eww_state.$func($args.local_env, $args.widget.get_attr($attr)?, {
let $gtk_widget = $gtk_widget.clone();
move |$arg| { $body; }
});
};
// with default
($args:ident, $gtk_widget:ident, $func:ident => $attr:literal [$default:expr] => |$arg:ident| $body:expr) => {
$args.unhandled_attrs.retain(|a| a != &$attr);
$args.eww_state.$func(
$args.local_env, $args.widget.attrs.get($attr).unwrap_or(&AttrValue::Concrete(PrimitiveValue::from($default))),
{
let $gtk_widget = $gtk_widget.clone();
move |$arg| { $body; }
}
if let Ok(attr_map) = attr_map {
$args.eww_state.resolve(
$args.local_env,
attr_map,
::glib::clone!(@strong $gtk_widget => move |attrs| {
$(
let $attr_name = attrs.get( ::std::stringify!($attr_name) ).context("something went terribly wrong....")?.$typecast_func()?;
)*
$code
Ok(())
})
);
}
})+
};
(@get_value $args:ident, $name:expr, = $default:expr) => {
$args.widget.get_attr($name).cloned().unwrap_or(AttrValue::Concrete(PrimitiveValue::from($default)))
};
(@get_value $args:ident, $name:expr,) => {
$args.widget.get_attr($name)?.clone()
}
}
#[allow(unused)]

View file

@ -1,5 +1,5 @@
use super::{run_command, BuilderArgs};
use crate::resolve;
use crate::resolve_block;
use crate::value::{AttrValue, PrimitiveValue, VarName};
use anyhow::*;
use gtk::prelude::*;
@ -10,54 +10,28 @@ use std::path::Path;
// TODO figure out how to
// TODO https://developer.gnome.org/gtk3/stable/GtkFixed.html
#[macro_export]
macro_rules! resolve_block {
($args:ident, $gtk_widget:ident, {
$(
prop( $( $attr_name:ident : $typecast_func:ident $(= $default:expr)?),*) $code:block
),+ $(,)?
}) => {
$({
$(
$args.unhandled_attrs.retain(|a| a != &::std::stringify!($attr_name).replace('_', "-"));
)*
let attr_map: Result<_> = try {
::maplit::hashmap! {
$(
::std::stringify!($attr_name).to_owned() => resolve_block!(@get_value $args, &::std::stringify!($attr_name).replace('_', "-"), $(= $default)?)
),*
}
};
if let Ok(attr_map) = attr_map {
$args.eww_state.resolve(
$args.local_env,
attr_map,
::glib::clone!(@strong $gtk_widget => move |attrs| {
$(
let $attr_name = attrs.get( ::std::stringify!($attr_name) ).context("something went terribly wrong....")?.$typecast_func()?;
)*
$code
Ok(())
})
);
}
})+
};
//// widget definitions
(@get_value $args:ident, $name:expr, = $default:expr) => {
$args.widget.get_attr($name).cloned().unwrap_or(AttrValue::Concrete(PrimitiveValue::from($default)))
pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result<Option<gtk::Widget>> {
let gtk_widget = match bargs.widget.name.as_str() {
"layout" => build_gtk_layout(bargs)?.upcast(),
"slider" => 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(),
_ => return Ok(None),
};
Ok(Some(gtk_widget))
}
(@get_value $args:ident, $name:expr,) => {
$args.widget.get_attr($name)?.clone()
}
}
/// attributes that apply to all widgets
pub(super) fn resolve_widget_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Widget) {
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(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) },
@ -81,7 +55,7 @@ pub(super) fn resolve_range_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Ran
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(orientation : as_string) { gtk_widget.set_orientation(parse_orientation(&orientation)?) },
prop(onchange : as_string) {
gtk_widget.connect_value_changed(move |gtk_widget| {
run_command(&onchange, gtk_widget.get_value());
@ -92,26 +66,10 @@ pub(super) fn resolve_range_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Ran
pub(super) fn resolve_orientable_attrs(bargs: &mut BuilderArgs, gtk_widget: &gtk::Range) {
resolve_block!(bargs, gtk_widget, {
prop(orientation: as_string) { gtk_widget.set_orientation(parse_orientation(&orientation)) },
prop(orientation: as_string) { gtk_widget.set_orientation(parse_orientation(&orientation)?) },
});
}
//// widget definitions
pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result<Option<gtk::Widget>> {
let gtk_widget = match bargs.widget.name.as_str() {
"layout" => build_gtk_layout(bargs)?.upcast(),
"slider" => 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(),
_ => return Ok(None),
};
Ok(Some(gtk_widget))
}
// concrete widgets
fn build_gtk_scale(bargs: &mut BuilderArgs) -> Result<gtk::Scale> {
@ -145,9 +103,8 @@ fn build_gtk_image(bargs: &mut BuilderArgs) -> Result<gtk::Image> {
fn build_gtk_layout(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(orientation: as_string) { gtk_widget.set_orientation(parse_orientation(&orientation)) },
prop(orientation: as_string) { gtk_widget.set_orientation(parse_orientation(&orientation)?) },
prop(space_evenly: as_bool = true) { gtk_widget.set_homogeneous(space_evenly) },
});
Ok(gtk_widget)
@ -183,20 +140,21 @@ fn build_gtk_aspect_frame(bargs: &mut BuilderArgs) -> Result<gtk::AspectFrame> {
Ok(gtk_widget)
}
fn parse_orientation(o: &str) -> gtk::Orientation {
match o {
fn parse_orientation(o: &str) -> Result<gtk::Orientation> {
Ok(match o {
"vertical" | "v" => gtk::Orientation::Vertical,
_ => gtk::Orientation::Horizontal,
}
"horizontal" | "h" => gtk::Orientation::Horizontal,
_ => bail!("Couldn't parse orientation: '{}'", o),
})
}
fn parse_align(o: &str) -> gtk::Align {
match o {
fn parse_align(o: &str) -> Result<gtk::Align> {
Ok(match o {
"fill" => gtk::Align::Fill,
"baseline" => gtk::Align::Baseline,
"center" => gtk::Align::Center,
"start" => gtk::Align::Start,
"end" => gtk::Align::End,
_ => gtk::Align::Start,
}
_ => bail!("Couldn't parse alignment: '{}'", o),
})
}