From c855ec07d5a962848c258216bc9edce9e0f18d90 Mon Sep 17 00:00:00 2001 From: viandox <43315863+viandoxdev@users.noreply.github.com> Date: Thu, 26 May 2022 13:40:09 +0200 Subject: [PATCH] Add overlay widget (#457) --- CHANGELOG.md | 1 + crates/eww/src/widgets/build_widget.rs | 5 +++ crates/eww/src/widgets/widget_definitions.rs | 41 ++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53edcad1..eb858edd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ All notable changes to eww will be listed here, starting at changes since versio - Add transform widget (By: druskus20) - Add `:onaccept` to input field, add `:onclick` to eventbox - Add `EWW_CMD`, `EWW_CONFIG_DIR`, `EWW_EXECUTABLE` magic variables +- Add `overlay` widget (By: viandoxdev) ### Notable Internal changes - Rework state management completely, now making local state and dynamic widget hierarchy changes possible. diff --git a/crates/eww/src/widgets/build_widget.rs b/crates/eww/src/widgets/build_widget.rs index 897a912b..7b1ac0dc 100644 --- a/crates/eww/src/widgets/build_widget.rs +++ b/crates/eww/src/widgets/build_widget.rs @@ -341,6 +341,11 @@ pub struct CustomWidgetInvocation { /// Make sure that [`gtk::Bin`] widgets only get a single child. fn validate_container_children_count(container: >k::Container, widget_use: &BasicWidgetUse) -> Result<(), DiagError> { + // ignore for overlay as it can take more than one. + if container.dynamic_cast_ref::().is_some() { + return Ok(()); + } + if container.dynamic_cast_ref::().is_some() && widget_use.children.len() > 1 { Err(DiagError::new(gen_diagnostic! { kind = Severity::Error, diff --git a/crates/eww/src/widgets/widget_definitions.rs b/crates/eww/src/widgets/widget_definitions.rs index 3dd98852..af83bb40 100644 --- a/crates/eww/src/widgets/widget_definitions.rs +++ b/crates/eww/src/widgets/widget_definitions.rs @@ -79,6 +79,7 @@ pub const BUILTIN_WIDGET_NAMES: &[&str] = &[ WIDGET_NAME_CHECKBOX, WIDGET_NAME_REVEALER, WIDGET_NAME_SCROLL, + WIDGET_NAME_OVERLAY, ]; //// widget definitions @@ -105,6 +106,7 @@ pub(super) fn widget_use_to_gtk_widget(bargs: &mut BuilderArgs) -> Result build_gtk_checkbox(bargs)?.upcast(), WIDGET_NAME_REVEALER => build_gtk_revealer(bargs)?.upcast(), WIDGET_NAME_SCROLL => build_gtk_scrolledwindow(bargs)?.upcast(), + WIDGET_NAME_OVERLAY => build_gtk_overlay(bargs)?.upcast(), _ => { return Err(AstError::ValidationError(ValidationError::UnknownWidget( bargs.widget_use.name_span, @@ -514,6 +516,45 @@ fn build_gtk_box(bargs: &mut BuilderArgs) -> Result { Ok(gtk_widget) } +const WIDGET_NAME_OVERLAY: &str = "overlay"; +/// @widget overlay +/// @desc a widget that places its children on top of each other. The overlay widget takes the size +/// of its first child. +fn build_gtk_overlay(bargs: &mut BuilderArgs) -> Result { + let gtk_widget = gtk::Overlay::new(); + + // no def_widget because this widget has no props. + // And this widget has no proprs because they would pretty much just be the same as boxes, + // so you might as well just use a box inside the widget to get them. + + match bargs.widget_use.children.len().cmp(&1) { + Ordering::Less => { + Err(DiagError::new(gen_diagnostic!("overlay must contain at least one element", bargs.widget_use.span)).into()) + } + Ordering::Greater | Ordering::Equal => { + let mut children = bargs.widget_use.children.iter().map(|child| { + build_gtk_widget( + bargs.scope_graph, + bargs.widget_defs.clone(), + bargs.calling_scope, + child.clone(), + bargs.custom_widget_invocation.clone(), + ) + }); + // we have more than one children, we can unwrap + let first = children.next().unwrap()?; + gtk_widget.add(&first); + first.show(); + for child in children { + let child = child?; + gtk_widget.add_overlay(&child); + child.show(); + } + Ok(gtk_widget) + } + } +} + const WIDGET_NAME_CENTERBOX: &str = "centerbox"; /// @widget centerbox /// @desc a box that must contain exactly three children, which will be layed out at the start, center and end of the container.