From 9ee852c0fd7c6e4510cd3954c07bd09cf325f71a Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Thu, 12 Aug 2021 16:19:00 +0200 Subject: [PATCH] Add centerbox widget --- crates/eww/src/app.rs | 5 ++- crates/eww/src/error_handling_ctx.rs | 6 +-- crates/eww/src/widgets/mod.rs | 24 ++++++------ crates/eww/src/widgets/widget_definitions.rs | 40 +++++++++++++++++++- crates/eww/src/widgets/widget_node.rs | 2 +- 5 files changed, 59 insertions(+), 18 deletions(-) diff --git a/crates/eww/src/app.rs b/crates/eww/src/app.rs index 4158f6c..18076a9 100644 --- a/crates/eww/src/app.rs +++ b/crates/eww/src/app.rs @@ -1,4 +1,7 @@ -use crate::{EwwPaths, config, daemon_response::DaemonResponseSender, display_backend, error_handling_ctx, eww_state, script_var_handler::*}; +use crate::{ + config, daemon_response::DaemonResponseSender, display_backend, error_handling_ctx, eww_state, script_var_handler::*, + EwwPaths, +}; use anyhow::*; use debug_stub_derive::*; use eww_shared_util::VarName; diff --git a/crates/eww/src/error_handling_ctx.rs b/crates/eww/src/error_handling_ctx.rs index af05638..dc052cf 100644 --- a/crates/eww/src/error_handling_ctx.rs +++ b/crates/eww/src/error_handling_ctx.rs @@ -35,10 +35,8 @@ pub fn format_error(err: &anyhow::Error) -> String { for err in err.chain() { format!("chain: {}", err); } - match err.downcast_ref::() { - Some(err) => stringify_diagnostic(err.to_diagnostic()).unwrap_or_else(|_| format!("{:?}", err)), - None => format!("{:?}", err), - } + let diag = anyhow_err_to_diagnostic(err); + stringify_diagnostic(diag).unwrap_or_else(|_| format!("{}", err)) } pub fn anyhow_err_to_diagnostic(err: &anyhow::Error) -> Diagnostic { diff --git a/crates/eww/src/widgets/mod.rs b/crates/eww/src/widgets/mod.rs index 6d83bb2..61d084c 100644 --- a/crates/eww/src/widgets/mod.rs +++ b/crates/eww/src/widgets/mod.rs @@ -70,17 +70,19 @@ fn build_builtin_gtk_widget( if let Some(gtk_widget) = gtk_widget.dynamic_cast_ref::() { resolve_container_attrs(&mut bargs, gtk_widget); - for child in &widget.children { - let child_widget = child.render(bargs.eww_state, window_name, widget_definitions).with_context(|| { - format!( - "{}error while building child '{:#?}' of '{}'", - format!("{} | ", widget.span), - &child, - >k_widget.get_widget_name() - ) - })?; - gtk_widget.add(&child_widget); - child_widget.show(); + if gtk_widget.get_children().is_empty() { + for child in &widget.children { + let child_widget = child.render(bargs.eww_state, window_name, widget_definitions).with_context(|| { + format!( + "{}error while building child '{:#?}' of '{}'", + format!("{} | ", widget.span), + &child, + >k_widget.get_widget_name() + ) + })?; + gtk_widget.add(&child_widget); + child_widget.show(); + } } } diff --git a/crates/eww/src/widgets/widget_definitions.rs b/crates/eww/src/widgets/widget_definitions.rs index dd3d9b4..2bc4c5f 100644 --- a/crates/eww/src/widgets/widget_definitions.rs +++ b/crates/eww/src/widgets/widget_definitions.rs @@ -1,14 +1,18 @@ #![allow(clippy::option_map_unit_fn)] use super::{run_command, BuilderArgs}; -use crate::{enum_parse, error_handling_ctx, eww_state, resolve_block, util::list_difference, widgets::widget_node}; +use crate::{ + enum_parse, error::DiagError, error_handling_ctx, eww_state, resolve_block, util::list_difference, widgets::widget_node, +}; use anyhow::*; use gdk::WindowExt; use glib; use gtk::{self, prelude::*, ImageExt}; +use itertools::Itertools; use std::{cell::RefCell, collections::HashMap, rc::Rc, time::Duration}; use yuck::{ config::validate::ValidationError, error::{AstError, AstResult, AstResultExt}, + gen_diagnostic, parser::from_ast::FromAst, }; @@ -20,6 +24,7 @@ use yuck::{ pub(super) fn widget_to_gtk_widget(bargs: &mut BuilderArgs) -> Result { let gtk_widget = match bargs.widget.name.as_str() { "box" => build_gtk_box(bargs)?.upcast(), + "centerbox" => build_center_box(bargs)?.upcast(), "scale" => build_gtk_scale(bargs)?.upcast(), "progress" => build_gtk_progress(bargs)?.upcast(), "image" => build_gtk_image(bargs)?.upcast(), @@ -494,6 +499,39 @@ fn build_gtk_box(bargs: &mut BuilderArgs) -> Result { Ok(gtk_widget) } +/// @widget centerbox extends container +/// @desc a box that must contain exactly three children, which will be layed out at the start, center and end of the container. +fn build_center_box(bargs: &mut BuilderArgs) -> Result { + let gtk_widget = gtk::Box::new(gtk::Orientation::Horizontal, 0); + resolve_block!(bargs, gtk_widget, { + // @prop orientation - orientation of the centerbox. possible values: $orientation + prop(orientation: as_string) { gtk_widget.set_orientation(parse_orientation(&orientation)?) }, + }); + + if bargs.widget.children.len() < 3 { + Err(DiagError::new(gen_diagnostic!("centerbox must contain exactly 3 elements", bargs.widget.span)))? + } else if bargs.widget.children.len() > 3 { + let (_, additional_children) = bargs.widget.children.split_at(3); + // we know that there is more than three children, so unwrapping on first and left here is fine. + let first_span = additional_children.first().unwrap().span(); + let last_span = additional_children.last().unwrap().span(); + Err(DiagError::new(gen_diagnostic!("centerbox must contain exactly 3 elements, but got more", first_span.to(last_span))))? + } + + let mut children = + bargs.widget.children.iter().map(|child| child.render(bargs.eww_state, bargs.window_name, bargs.widget_definitions)); + // we know that we have exactly three children here, so we can unwrap here. + let (first, center, end) = children.next_tuple().unwrap(); + let (first, center, end) = (first?, center?, end?); + gtk_widget.pack_start(&first, true, true, 0); + gtk_widget.set_center_widget(Some(¢er)); + gtk_widget.pack_end(&end, true, true, 0); + first.show(); + center.show(); + end.show(); + Ok(gtk_widget) +} + /// @widget label /// @desc A text widget giving you more control over how the text is displayed fn build_gtk_label(bargs: &mut BuilderArgs) -> Result { diff --git a/crates/eww/src/widgets/widget_node.rs b/crates/eww/src/widgets/widget_node.rs index 0bfc959..08740d5 100644 --- a/crates/eww/src/widgets/widget_node.rs +++ b/crates/eww/src/widgets/widget_node.rs @@ -9,7 +9,7 @@ use yuck::{ error::{AstError, AstResult}, }; -pub trait WidgetNode: std::fmt::Debug + dyn_clone::DynClone + Send + Sync { +pub trait WidgetNode: Spanned + std::fmt::Debug + dyn_clone::DynClone + Send + Sync { fn get_name(&self) -> &str; /// Generate a [gtk::Widget] from a [element::WidgetUse].