This commit is contained in:
elkowar 2020-09-21 01:37:27 +02:00
parent 7af0cb2489
commit 60c6f1b28f
4 changed files with 111 additions and 114 deletions

View file

@ -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"

View file

@ -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<MuhhMsg>) {
.unwrap();
}
}
fn element_to_gtk_thing(
widget_definitions: &HashMap<String, element::WidgetDefinition>,
eww_state: &mut EwwState,
local_environment: &HashMap<String, AttrValue>,
element: &element::ElementUse,
) -> Result<gtk::Widget> {
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<String, element::WidgetDefinition>,
eww_state: &mut EwwState,
local_environment: &HashMap<String, AttrValue>,
widget: &element::WidgetUse,
) -> Result<gtk::Widget> {
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<String, element::WidgetDefinition>,
eww_state: &mut EwwState,
local_environment: &HashMap<String, AttrValue>,
widget: &element::WidgetUse,
) -> Result<gtk::Widget> {
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<String, element::WidgetDefinition>,
eww_state: &mut EwwState,
local_env: &HashMap<String, AttrValue>,
widget: &element::WidgetUse,
) -> Result<gtk::Widget> {
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)
}

View file

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

View file

@ -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<String, AttrValue>,
pub widget: &'c element::WidgetUse,
fn run_command<T: std::fmt::Display>(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<gtk::Scale> {
pub fn element_to_gtk_thing(
widget_definitions: &HashMap<String, element::WidgetDefinition>,
eww_state: &mut EwwState,
local_env: &HashMap<String, AttrValue>,
element: &element::ElementUse,
) -> Result<gtk::Widget> {
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<String, AttrValue>,
widget: &'c element::WidgetUse,
}
pub fn build_gtk_widget_or_container(
widget_definitions: &HashMap<String, element::WidgetDefinition>,
eww_state: &mut EwwState,
local_env: &HashMap<String, AttrValue>,
widget: &element::WidgetUse,
) -> Result<gtk::Widget> {
let mut builder_args = BuilderArgs {
eww_state,
local_env: &local_env,
widget: &widget,
};
let gtk_widget: Option<gtk::Widget> =
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<Option<gtk::Widget>> {
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<Option<gtk::Container>> {
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<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)),
@ -55,7 +149,7 @@ pub fn build_gtk_scale(builder_args: BuilderArgs) -> Result<gtk::Scale> {
Ok(gtk_widget)
}
pub fn build_gtk_button(builder_args: BuilderArgs) -> Result<gtk::Button> {
fn build_gtk_button(builder_args: &mut BuilderArgs) -> Result<gtk::Button> {
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<gtk::Button> {
Ok(gtk_widget)
}
pub fn build_gtk_layout(builder_args: BuilderArgs) -> Result<gtk::Box> {
fn build_gtk_layout(builder_args: &mut BuilderArgs) -> Result<gtk::Box> {
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<gtk::Box> {
Ok(gtk_widget)
}
//"layout_horizontal" => gtk::Box::new(gtk::Orientation::Horizontal, 0).upcast(),
fn run_command<T: std::fmt::Display>(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);
}
}