From 988b9b508512e1429cb58866f5bb13d364c295e7 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Tue, 22 Sep 2020 00:30:13 +0200 Subject: [PATCH] more cleanup --- src/eww_state.rs | 20 ++++++++++++++- src/main.rs | 3 ++- src/value.rs | 34 ++++++++++++++++++++++--- src/widgets.rs | 66 ++++++++++++++++++++++++++++++++++++------------ 4 files changed, 101 insertions(+), 22 deletions(-) diff --git a/src/eww_state.rs b/src/eww_state.rs index 5233f3c..ba09958 100644 --- a/src/eww_state.rs +++ b/src/eww_state.rs @@ -1,4 +1,6 @@ use std::collections::HashMap; +use std::convert::TryFrom; +use std::convert::TryInto; use crate::value::{AttrValue, PrimitiveValue}; @@ -51,6 +53,22 @@ impl EwwState { } } + pub fn resolve_into< + TE: std::fmt::Debug, + V: TryFrom, + F: Fn(V) + 'static + Clone, + >( + &mut self, + local_env: &HashMap, + value: &AttrValue, + set_value: F, + ) -> bool { + self.resolve(local_env, value, move |x| { + if let Err(e) = x.try_into().map(|v| set_value(v)) { + eprintln!("error while resolving value: {:?}", e); + }; + }) + } pub fn resolve_f64( &mut self, local_env: &HashMap, @@ -77,7 +95,7 @@ impl EwwState { }; }) } - pub fn resolve_string( + pub fn resolve_str( &mut self, local_env: &HashMap, value: &AttrValue, diff --git a/src/main.rs b/src/main.rs index 30689ef..1ef577b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -37,8 +37,9 @@ const EXAMPLE_CONFIG: &str = r#"{ "hi", { button: { children: "click me you" } } { slider: { value: "$$some_value", min: 0, max: 100, onchange: "notify-send 'changed' {}" } } - { slider: { value: "$$some_value", min: 0, max: 100, onchange: "notify-send 'changed' {}" } } + { slider: { value: "$$some_value", orientation: "vertical" } } "hu" + { image: { path: "/home/leon/Bilder/ElCoward.png" } } ] } } diff --git a/src/value.rs b/src/value.rs index a52c33e..b5cab24 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,17 +1,43 @@ use anyhow::*; -use derive_more::*; +use derive_more; use hocon::Hocon; +use std::convert::TryFrom; use try_match::try_match; -// TODO implement TryFrom for the types properly - -#[derive(Clone, Debug, PartialEq, From)] +#[derive(Clone, Debug, PartialEq, derive_more::From)] pub enum PrimitiveValue { String(String), Number(f64), Boolean(bool), } +impl TryFrom for String { + type Error = anyhow::Error; + fn try_from(x: PrimitiveValue) -> Result { + match x { + PrimitiveValue::String(x) => Ok(x), + _ => return Err(anyhow!("'{:?}' is not a string", x.clone())), + } + } +} +impl TryFrom for f64 { + type Error = anyhow::Error; + fn try_from(x: PrimitiveValue) -> Result { + try_match!(PrimitiveValue::Number(x) = &x) + .map_err(|_| anyhow!("'{:?}' is not a number", &x)) + .map(|&x| x) + } +} + +impl TryFrom for bool { + type Error = anyhow::Error; + fn try_from(x: PrimitiveValue) -> Result { + try_match!(PrimitiveValue::Boolean(x) = &x) + .map_err(|_| anyhow!("'{:?}' is not a bool", &x)) + .map(|&x| x) + } +} + impl From<&str> for PrimitiveValue { fn from(s: &str) -> Self { PrimitiveValue::String(s.to_string()) diff --git a/src/widgets.rs b/src/widgets.rs index 8501d92..9c5fc7c 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -3,14 +3,35 @@ use crate::eww_state::*; use crate::value::{AttrValue, PrimitiveValue}; use anyhow::*; use gtk::prelude::*; +use gtk::ImageExt; +use std::path::Path; use std::{collections::HashMap, process::Command}; const CMD_STRING_PLACEHODLER: &str = "{}"; +macro_rules! log_errors { + ($body:expr) => {{ + let result = try { $body }; + if let Err(e) = result { + eprintln!("WARN: {}", e); + } + }}; +} + macro_rules! resolve { + ($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); + )+ + }; + ($args:ident, $gtk_widget:ident, { $($func:ident => { - $($attr:literal $([$default:literal])? $(req $(@$required:tt)?)? => |$arg:ident| $body:expr),+ $(,)? + $($attr:literal $(= $default:literal)? $(= req $(@$required:tt)?)? => |$arg:ident| $body:expr),+ $(,)? }),+ $(,)? }) => { $($( @@ -43,7 +64,6 @@ macro_rules! resolve { move |$arg| { $body; } }); }; - } fn run_command(cmd: &str, arg: T) { @@ -110,7 +130,7 @@ pub fn build_gtk_widget_or_container( &element_to_gtk_thing(widget_definitions, eww_state, local_env, child) .with_context(|| { format!( - "error while building child '{:?}' of '{:?}'", + "error while building child '{:?}' of '{}'", &child, >k_widget.get_widget_name() ) @@ -128,6 +148,7 @@ pub fn build_gtk_widget_or_container( 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(), + "image" => build_gtk_image(builder_args)?.upcast(), _ => return Ok(None), }; Ok(Some(gtk_widget)) @@ -152,11 +173,12 @@ fn build_gtk_scale(builder_args: &mut BuilderArgs) -> Result { resolve!(builder_args, gtk_widget, { resolve_f64 => { - "value" req => |v| gtk_widget.set_value(v), - "min" => |v| gtk_widget.get_adjustment().set_lower(v), - "max" => |v| gtk_widget.get_adjustment().set_upper(v) + "value" = req => |v| gtk_widget.set_value(v), + "min" => |v| gtk_widget.get_adjustment().set_lower(v), + "max" => |v| gtk_widget.get_adjustment().set_upper(v), }, - resolve_string => { + resolve_str => { + "orientation" => |v| gtk_widget.set_orientation(parse_orientation(&v)), "onchange" => |cmd| { gtk_widget.connect_value_changed(move |gtk_widget| { run_command(&cmd, gtk_widget.get_value()); @@ -170,12 +192,17 @@ fn build_gtk_scale(builder_args: &mut BuilderArgs) -> Result { fn build_gtk_button(builder_args: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Button::new(); resolve!(builder_args, gtk_widget, { - resolve_bool => { - "active" [true] => |v| gtk_widget.set_sensitive(v) - }, - resolve_string => { - "onclick" => |cmd| gtk_widget.connect_clicked(move |_| run_command(&cmd, "")) - } + resolve_bool => "active" = true => |v| gtk_widget.set_sensitive(v), + resolve_str => "onclick" => |v| gtk_widget.connect_clicked(move |_| run_command(&v, "")) + + }); + Ok(gtk_widget) +} + +fn build_gtk_image(builder_args: &mut BuilderArgs) -> Result { + let gtk_widget = gtk::Image::new(); + resolve!(builder_args, gtk_widget, { + resolve_str => "path" = req => |v| gtk_widget.set_from_file(Path::new(&v)) }); Ok(gtk_widget) } @@ -183,9 +210,16 @@ fn build_gtk_button(builder_args: &mut 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 => { - "spacing" [10.0] => |v| gtk_widget.set_spacing(v as i32) - } + resolve_f64 => "spacing" = 10.0 => |v| gtk_widget.set_spacing(v as i32), + resolve_str => "orientation" => |v| gtk_widget.set_orientation(parse_orientation(&v)), + }); Ok(gtk_widget) } + +fn parse_orientation(o: &str) -> gtk::Orientation { + match o { + "vertical" => gtk::Orientation::Vertical, + _ => gtk::Orientation::Horizontal, + } +}