Allow literal-tag content to use user-defined widgets

This commit is contained in:
elkowar 2021-03-02 17:24:14 +01:00
parent c37c5b3cf3
commit 0c762de864
5 changed files with 59 additions and 22 deletions

View file

@ -247,7 +247,10 @@ impl App {
let mut window_def = self.eww_config.get_window(window_name)?.clone(); let mut window_def = self.eww_config.get_window(window_name)?.clone();
window_def.geometry = window_def.geometry.override_if_given(anchor, pos, size); window_def.geometry = window_def.geometry.override_if_given(anchor, pos, size);
let root_widget = window_def.widget.render(&mut self.eww_state, window_name)?; let root_widget =
window_def
.widget
.render(&mut self.eww_state, window_name, &self.eww_config.get_widget_definitions())?;
root_widget.get_style_context().add_class(&window_name.to_string()); root_widget.get_style_context().add_class(&window_name.to_string());
let monitor_geometry = get_monitor_geometry(window_def.screen_number.unwrap_or_else(get_default_monitor_index)); let monitor_geometry = get_monitor_geometry(window_def.screen_number.unwrap_or_else(get_default_monitor_index));

View file

@ -16,6 +16,7 @@ use std::path::PathBuf;
/// Eww configuration structure. /// Eww configuration structure.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct EwwConfig { pub struct EwwConfig {
widgets: HashMap<String, WidgetDefinition>,
windows: HashMap<WindowName, EwwWindowDefinition>, windows: HashMap<WindowName, EwwWindowDefinition>,
initial_variables: HashMap<VarName, PrimitiveValue>, initial_variables: HashMap<VarName, PrimitiveValue>,
script_vars: HashMap<VarName, ScriptVar>, script_vars: HashMap<VarName, ScriptVar>,
@ -35,9 +36,6 @@ impl EwwConfig {
widgets, widgets,
} = conf; } = conf;
Ok(EwwConfig { Ok(EwwConfig {
initial_variables,
script_vars,
filepath,
windows: windows windows: windows
.into_iter() .into_iter()
.map(|(name, window)| { .map(|(name, window)| {
@ -47,6 +45,10 @@ impl EwwConfig {
)) ))
}) })
.collect::<Result<HashMap<_, _>>>()?, .collect::<Result<HashMap<_, _>>>()?,
widgets,
initial_variables,
script_vars,
filepath,
}) })
} }
@ -76,6 +78,10 @@ impl EwwConfig {
.get(name) .get(name)
.with_context(|| format!("No script var named '{}' exists", name)) .with_context(|| format!("No script var named '{}' exists", name))
} }
pub fn get_widget_definitions(&self) -> &HashMap<String, WidgetDefinition> {
&self.widgets
}
} }
/// Raw Eww configuration, before expanding widget usages. /// Raw Eww configuration, before expanding widget usages.

View file

@ -1,7 +1,12 @@
use crate::{config::window_definition::WindowName, eww_state::*, value::AttrName}; use crate::{
config::{element::WidgetDefinition, window_definition::WindowName},
eww_state::*,
value::AttrName,
};
use anyhow::*; use anyhow::*;
use gtk::prelude::*; use gtk::prelude::*;
use itertools::Itertools; use itertools::Itertools;
use std::collections::HashMap;
use std::process::Command; use std::process::Command;
use widget_definitions::*; use widget_definitions::*;
@ -36,11 +41,12 @@ pub(self) fn run_command<T: 'static + std::fmt::Display + Send + Sync>(cmd: &str
}); });
} }
struct BuilderArgs<'a, 'b, 'c, 'd> { struct BuilderArgs<'a, 'b, 'c, 'd, 'e> {
eww_state: &'a mut EwwState, eww_state: &'a mut EwwState,
widget: &'b widget_node::Generic, widget: &'b widget_node::Generic,
unhandled_attrs: Vec<&'c AttrName>, unhandled_attrs: Vec<&'c AttrName>,
window_name: &'d WindowName, window_name: &'d WindowName,
widget_definitions: &'e HashMap<String, WidgetDefinition>,
} }
/// build a [`gtk::Widget`] out of a [`element::WidgetUse`] that uses a /// build a [`gtk::Widget`] out of a [`element::WidgetUse`] that uses a
@ -55,6 +61,7 @@ struct BuilderArgs<'a, 'b, 'c, 'd> {
fn build_builtin_gtk_widget( fn build_builtin_gtk_widget(
eww_state: &mut EwwState, eww_state: &mut EwwState,
window_name: &WindowName, window_name: &WindowName,
widget_definitions: &HashMap<String, WidgetDefinition>,
widget: &widget_node::Generic, widget: &widget_node::Generic,
) -> Result<Option<gtk::Widget>> { ) -> Result<Option<gtk::Widget>> {
let mut bargs = BuilderArgs { let mut bargs = BuilderArgs {
@ -62,6 +69,7 @@ fn build_builtin_gtk_widget(
widget, widget,
window_name, window_name,
unhandled_attrs: widget.attrs.keys().collect(), unhandled_attrs: widget.attrs.keys().collect(),
widget_definitions,
}; };
let gtk_widget = match widget_to_gtk_widget(&mut bargs) { let gtk_widget = match widget_to_gtk_widget(&mut bargs) {
Ok(Some(gtk_widget)) => gtk_widget, Ok(Some(gtk_widget)) => gtk_widget,
@ -81,14 +89,16 @@ fn build_builtin_gtk_widget(
if let Some(gtk_widget) = gtk_widget.dynamic_cast_ref::<gtk::Container>() { if let Some(gtk_widget) = gtk_widget.dynamic_cast_ref::<gtk::Container>() {
resolve_container_attrs(&mut bargs, &gtk_widget); resolve_container_attrs(&mut bargs, &gtk_widget);
for child in &widget.children { for child in &widget.children {
let child_widget = child.render(bargs.eww_state, window_name).with_context(|| { let child_widget = child
format!( .render(bargs.eww_state, window_name, widget_definitions)
"{}error while building child '{:#?}' of '{}'", .with_context(|| {
widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(), format!(
&child, "{}error while building child '{:#?}' of '{}'",
&gtk_widget.get_widget_name() widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(),
) &child,
})?; &gtk_widget.get_widget_name()
)
})?;
gtk_widget.add(&child_widget); gtk_widget.add(&child_widget);
child_widget.show(); child_widget.show();
} }

View file

@ -410,6 +410,7 @@ fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result<gtk::Box> {
// TODO these clones here are dumdum // TODO these clones here are dumdum
let window_name = bargs.window_name.clone(); let window_name = bargs.window_name.clone();
let widget_definitions = bargs.widget_definitions.clone();
resolve_block!(bargs, gtk_widget, { resolve_block!(bargs, gtk_widget, {
// @prop content - inline Eww XML that will be rendered as a widget. // @prop content - inline Eww XML that will be rendered as a widget.
prop(content: as_string) { prop(content: as_string) {
@ -418,8 +419,8 @@ fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result<gtk::Box> {
let document = roxmltree::Document::parse(&content).map_err(|e| anyhow!("Failed to parse eww xml literal: {:?}", e))?; let document = roxmltree::Document::parse(&content).map_err(|e| anyhow!("Failed to parse eww xml literal: {:?}", e))?;
let content_widget_use = config::element::WidgetUse::from_xml_node(document.root_element().into())?; let content_widget_use = config::element::WidgetUse::from_xml_node(document.root_element().into())?;
let widget_node = &*widget_node::generate_generic_widget_node(&HashMap::new(), &HashMap::new(), content_widget_use)?; let widget_node = &*widget_node::generate_generic_widget_node(&widget_definitions, &HashMap::new(), content_widget_use)?;
let child_widget = widget_node.render( &mut eww_state::EwwState::default(), &window_name)?; let child_widget = widget_node.render(&mut eww_state::EwwState::default(), &window_name, &widget_definitions)?;
gtk_widget.add(&child_widget); gtk_widget.add(&child_widget);
child_widget.show(); child_widget.show();
} }

View file

@ -20,7 +20,12 @@ pub trait WidgetNode: std::fmt::Debug + dyn_clone::DynClone + Send + Sync {
/// This may return `Err` in case there was an actual error while parsing or /// This may return `Err` in case there was an actual error while parsing or
/// resolving the widget, Or `Ok(None)` if the widget_use just didn't match any /// resolving the widget, Or `Ok(None)` if the widget_use just didn't match any
/// widget name. /// widget name.
fn render(&self, eww_state: &mut EwwState, window_name: &WindowName) -> Result<gtk::Widget>; fn render(
&self,
eww_state: &mut EwwState,
window_name: &WindowName,
widget_definitions: &HashMap<String, WidgetDefinition>,
) -> Result<gtk::Widget>;
} }
dyn_clone::clone_trait_object!(WidgetNode); dyn_clone::clone_trait_object!(WidgetNode);
@ -41,8 +46,13 @@ impl WidgetNode for UserDefined {
self.text_pos.as_ref() self.text_pos.as_ref()
} }
fn render(&self, eww_state: &mut EwwState, window_name: &WindowName) -> Result<gtk::Widget> { fn render(
self.content.render(eww_state, window_name) &self,
eww_state: &mut EwwState,
window_name: &WindowName,
widget_definitions: &HashMap<String, WidgetDefinition>,
) -> Result<gtk::Widget> {
self.content.render(eww_state, window_name, widget_definitions)
} }
} }
@ -76,9 +86,16 @@ impl WidgetNode for Generic {
self.text_pos.as_ref() self.text_pos.as_ref()
} }
fn render(&self, eww_state: &mut EwwState, window_name: &WindowName) -> Result<gtk::Widget> { fn render(
Ok(crate::widgets::build_builtin_gtk_widget(eww_state, window_name, &self)? &self,
.with_context(|| format!("Unknown widget '{}'", self.get_name()))?) eww_state: &mut EwwState,
window_name: &WindowName,
widget_definitions: &HashMap<String, WidgetDefinition>,
) -> Result<gtk::Widget> {
Ok(
crate::widgets::build_builtin_gtk_widget(eww_state, window_name, widget_definitions, &self)?
.with_context(|| format!("Unknown widget '{}'", self.get_name()))?,
)
} }
} }