diff --git a/Cargo.toml b/Cargo.toml index a5fa258..663d1a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,9 @@ anyhow = "1.0" #thiserror = "1.0" -pretty_assertions = "0.6.1" - derive_more = "0.99" maplit = "1" + +[dev-dependencies] +pretty_assertions = "0.6.1" + diff --git a/src/main.rs b/src/main.rs index a461fa4..5f66708 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ use config::element; use eww_state::*; use value::{AttrValue, PrimitiveValue}; +#[macro_export] macro_rules! build { ($var_name:ident = $value:expr ; $code:block) => {{ let mut $var_name = $value; @@ -30,7 +31,7 @@ const EXAMPLE_CONFIG: &str = r#"{ widgets: { some_widget: { structure: { - layout_horizontal: { + layout: { class: "container", children: [ "hi", @@ -116,7 +117,7 @@ fn try_main() -> Result<()> { let empty_local_state = HashMap::new(); app_window.add( - &element_to_gtk_thing( + &widgets::element_to_gtk_thing( &eww_config.get_widgets(), &mut eww_state, &empty_local_state, @@ -163,97 +164,3 @@ fn event_loop(sender: glib::Sender) { .unwrap(); } } - -fn element_to_gtk_thing( - widget_definitions: &HashMap, - eww_state: &mut EwwState, - local_environment: &HashMap, - element: &element::ElementUse, -) -> Result { - match element { - element::ElementUse::Text(text) => Ok(gtk::Label::new(Some(&text)).upcast()), - element::ElementUse::Widget(widget) => { - widget_use_to_gtk_thing(widget_definitions, eww_state, local_environment, widget) - } - } -} - -fn widget_use_to_gtk_thing( - widget_definitions: &HashMap, - eww_state: &mut EwwState, - local_environment: &HashMap, - widget: &element::WidgetUse, -) -> Result { - let gtk_widget = - widget_use_to_gtk_container(widget_definitions, eww_state, &local_environment, &widget) - .or(widget_use_to_gtk_widget( - widget_definitions, - eww_state, - &local_environment, - &widget, - ))?; - if let Some(css_class) = widget - .attrs - .get("class") - .and_then(|x| AttrValue::as_string(x).ok()) - { - gtk_widget.get_style_context().add_class(css_class); - } - - Ok(gtk_widget) -} - -fn widget_use_to_gtk_container( - widget_definitions: &HashMap, - eww_state: &mut EwwState, - local_environment: &HashMap, - widget: &element::WidgetUse, -) -> Result { - let container_widget: gtk::Container = match widget.name.as_str() { - "layout_horizontal" => gtk::Box::new(gtk::Orientation::Horizontal, 0).upcast(), - "button" => gtk::Button::new().upcast(), - _ => return Err(anyhow!("{} is not a known container widget", widget.name)), - }; - - for child in &widget.children { - container_widget.add(&element_to_gtk_thing( - widget_definitions, - eww_state, - local_environment, - child, - )?); - } - Ok(container_widget.upcast()) -} - -fn widget_use_to_gtk_widget( - widget_definitions: &HashMap, - eww_state: &mut EwwState, - local_env: &HashMap, - widget: &element::WidgetUse, -) -> Result { - let builder_args = widgets::BuilderArgs { - eww_state, - local_env: &local_env, - widget: &widget, - }; - let new_widget: gtk::Widget = match widget.name.as_str() { - "slider" => widgets::build_gtk_scale(builder_args)?.upcast(), - - name if widget_definitions.contains_key(name) => { - let def = &widget_definitions[name]; - let local_environment = build!(env = local_env.clone(); { - env.extend(widget.attrs.clone()); - }); - - element_to_gtk_thing( - widget_definitions, - eww_state, - &local_environment, - &def.structure, - )? - } - _ => return Err(anyhow!("unknown widget {}", &widget.name)), - }; - Ok(new_widget) -} diff --git a/src/value.rs b/src/value.rs index f941be1..b0420a2 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,8 +1,11 @@ use anyhow::*; use derive_more::From; +use derive_more::*; use hocon::Hocon; use try_match::try_match; +// TODO implement TryFrom for the types properly + #[derive(Clone, Debug, PartialEq, From)] pub enum PrimitiveValue { String(String), diff --git a/src/widgets.rs b/src/widgets.rs index 88c896c..814386f 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -1,3 +1,4 @@ +use crate::build; use crate::config::element; use crate::eww_state::*; use crate::value::AttrValue; @@ -26,13 +27,106 @@ macro_rules! resolve { } } -pub struct BuilderArgs<'a, 'b, 'c> { - pub eww_state: &'a mut EwwState, - pub local_env: &'b HashMap, - pub widget: &'c element::WidgetUse, +fn run_command(cmd: &str, arg: T) { + let cmd = cmd.replace(CMD_STRING_PLACEHODLER, &format!("{}", arg)); + if let Err(e) = Command::new("bash").arg("-c").arg(cmd).output() { + eprintln!("{}", e); + } } -pub fn build_gtk_scale(builder_args: BuilderArgs) -> Result { +pub fn element_to_gtk_thing( + widget_definitions: &HashMap, + eww_state: &mut EwwState, + local_env: &HashMap, + element: &element::ElementUse, +) -> Result { + match element { + element::ElementUse::Text(text) => Ok(gtk::Label::new(Some(&text)).upcast()), + element::ElementUse::Widget(widget) => { + let gtk_container = + build_gtk_widget_or_container(widget_definitions, eww_state, local_env, widget); + let gtk_widget = gtk_container.or_else(|_| { + if let Some(def) = widget_definitions.get(widget.name.as_str()) { + let local_environment = build!(env = local_env.clone(); { + env.extend(widget.attrs.clone()); + }); + + element_to_gtk_thing( + widget_definitions, + eww_state, + &local_environment, + &def.structure, + ) + } else { + Err(anyhow!("unknown widget {}", &widget.name)) + } + })?; + + if let Ok(css_class) = widget + .get_attr("class") + .and_then(|x| AttrValue::as_string(x)) + { + gtk_widget.get_style_context().add_class(css_class); + } + + Ok(gtk_widget) + } + } +} + +struct BuilderArgs<'a, 'b, 'c> { + eww_state: &'a mut EwwState, + local_env: &'b HashMap, + widget: &'c element::WidgetUse, +} + +pub fn build_gtk_widget_or_container( + widget_definitions: &HashMap, + eww_state: &mut EwwState, + local_env: &HashMap, + widget: &element::WidgetUse, +) -> Result { + let mut builder_args = BuilderArgs { + eww_state, + local_env: &local_env, + widget: &widget, + }; + let gtk_widget: Option = + if let Some(gtk_widget) = build_gtk_container(&mut builder_args)? { + for child in &widget.children { + let child_widget = + &element_to_gtk_thing(widget_definitions, eww_state, local_env, child)?; + gtk_widget.add(child_widget); + } + Some(gtk_widget.upcast()) + } else { + build_gtk_widget(&mut builder_args)? + }; + gtk_widget.context(format!("unknown widget {:?}", widget)) +} + +// widget definitions + +fn build_gtk_widget(builder_args: &mut BuilderArgs) -> Result> { + let gtk_widget = match builder_args.widget.name.as_str() { + "slider" => build_gtk_scale(builder_args)?.upcast(), + _ => return Ok(None), + }; + Ok(Some(gtk_widget)) +} + +fn build_gtk_container(builder_args: &mut BuilderArgs) -> Result> { + let gtk_widget = match builder_args.widget.name.as_str() { + "layout" => build_gtk_layout(builder_args)?.upcast(), + "button" => build_gtk_button(builder_args)?.upcast(), + _ => return Ok(None), + }; + Ok(Some(gtk_widget)) +} + +// concrete widgets + +fn build_gtk_scale(builder_args: &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)), @@ -55,7 +149,7 @@ pub fn build_gtk_scale(builder_args: BuilderArgs) -> Result { Ok(gtk_widget) } -pub fn build_gtk_button(builder_args: BuilderArgs) -> Result { +fn build_gtk_button(builder_args: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Button::new(); resolve!(builder_args, gtk_widget, { resolve_bool => { @@ -68,7 +162,7 @@ pub fn build_gtk_button(builder_args: BuilderArgs) -> Result { Ok(gtk_widget) } -pub fn build_gtk_layout(builder_args: BuilderArgs) -> Result { +fn build_gtk_layout(builder_args: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Box::new(gtk::Orientation::Horizontal, 0); resolve!(builder_args, gtk_widget, { resolve_f64 => { @@ -78,12 +172,3 @@ pub fn build_gtk_layout(builder_args: BuilderArgs) -> Result { Ok(gtk_widget) } - -//"layout_horizontal" => gtk::Box::new(gtk::Orientation::Horizontal, 0).upcast(), - -fn run_command(cmd: &str, arg: T) { - let cmd = cmd.replace(CMD_STRING_PLACEHODLER, &format!("{}", arg)); - if let Err(e) = Command::new("bash").arg("-c").arg(cmd).output() { - eprintln!("{}", e); - } -}