diff --git a/gui/CHANGELOG.md b/gui/CHANGELOG.md
index 1a3729e82c2..b68af204bbf 100644
--- a/gui/CHANGELOG.md
+++ b/gui/CHANGELOG.md
@@ -91,6 +91,9 @@
#### EnsoGL (rendering engine)
+- [Unified shadow generation][1411]. Added a toolset to create shadows for
+ arbitrary UI components.
+
#### Enso Compiler
If you're interested in the enhancements and fixes made to the Enso compiler,
@@ -121,6 +124,7 @@ you can find their release notes
[1335]: https://github.com/enso-org/ide/pull/1335
[1358]: https://github.com/enso-org/ide/pull/1358
[1377]: https://github.com/enso-org/ide/pull/1377
+[1411]: https://github.com/enso-org/ide/pull/1411
diff --git a/gui/src/rust/ensogl/lib/components/src/label.rs b/gui/src/rust/ensogl/lib/components/src/label.rs
index 7b3dd0263b7..d6747361aaa 100644
--- a/gui/src/rust/ensogl/lib/components/src/label.rs
+++ b/gui/src/rust/ensogl/lib/components/src/label.rs
@@ -1,6 +1,7 @@
//! Label component. Appears as text with background.
use crate::prelude::*;
+use crate::shadow;
use enso_frp as frp;
use enso_frp;
@@ -25,36 +26,17 @@ mod background {
ensogl_core::define_shape_system! {
(style:Style,bg_color:Vector4) {
- let width = Var::::from("input_size.x");
- let height = Var::::from("input_size.y");
- let padding = style.get_number_or(theme::padding, 0.0);
- let width = width - padding.px() * 2.0;
- let height = height - padding.px() * 2.0;
- let radius = &height / 2.0;
- let shape = Rect((&width,&height)).corners_radius(&radius);
- let shape = shape.fill(Var::::from(bg_color.clone()));
+ let width = Var::::from("input_size.x");
+ let height = Var::::from("input_size.y");
+ let padding = style.get_number_or(theme::padding, 0.0);
+ let width = width - padding.px() * 2.0;
+ let height = height - padding.px() * 2.0;
+ let radius = &height / 2.0;
+ let base_shape = Rect((&width,&height)).corners_radius(&radius);
+ let shape = base_shape.fill(Var::::from(bg_color.clone()));
-
- // === Shadow ===
let alpha = Var::::from(format!("({0}.w)",bg_color));
- let border_size_f = 16.0;
- let shaow_size = style.get_number_or(theme::shadow::size,0.0);
- let shadow_size = shaow_size.px();
- let shadow_width = &width + &shadow_size * 2.0;
- let shadow_height = &height + &shadow_size * 2.0;
- let shadow_radius = &shadow_height / 2.0;
- let shadow = Rect((shadow_width,shadow_height)).corners_radius(shadow_radius);
- let base_color = color::Rgba::from(style.get_color(theme::shadow));
- let base_color = Var::::from(base_color);
- let base_color = base_color.multiply_alpha(&alpha);
- let fading_color = color::Rgba::from(style.get_color(theme::shadow::fading));
- let fading_color = Var::::from(fading_color);
- let fading_color = fading_color.multiply_alpha(&alpha);
- let exponent = style.get_number_or(theme::shadow::exponent,2.0);
- let shadow_color = color::gradient::Linear::>
- ::new(fading_color.into_linear(),base_color.into_linear());
- let shadow_color = shadow_color.sdf_sampler().size(border_size_f).exponent(exponent);
- let shadow = shadow.fill(shadow_color);
+ let shadow = shadow::from_shape_with_alpha(base_shape.into(),&alpha,style);
(shadow+shape).into()
}
diff --git a/gui/src/rust/ensogl/lib/components/src/lib.rs b/gui/src/rust/ensogl/lib/components/src/lib.rs
index 884be691141..8cd16939077 100644
--- a/gui/src/rust/ensogl/lib/components/src/lib.rs
+++ b/gui/src/rust/ensogl/lib/components/src/lib.rs
@@ -20,6 +20,7 @@ pub mod drop_down_menu;
pub mod list_view;
pub mod label;
pub mod toggle_button;
+pub mod shadow;
/// Commonly used types and functions.
pub mod prelude {
diff --git a/gui/src/rust/ensogl/lib/components/src/list_view.rs b/gui/src/rust/ensogl/lib/components/src/list_view.rs
index eaba88562cd..36114e2ebd4 100644
--- a/gui/src/rust/ensogl/lib/components/src/list_view.rs
+++ b/gui/src/rust/ensogl/lib/components/src/list_view.rs
@@ -6,6 +6,7 @@
pub mod entry;
use crate::prelude::*;
+use crate::shadow;
use enso_frp as frp;
use ensogl_core::application;
@@ -66,22 +67,13 @@ mod background {
(style:Style) {
let sprite_width : Var = "input_size.x".into();
let sprite_height : Var = "input_size.y".into();
- let width = sprite_width.clone() - SHADOW_PX.px() * 2.0 - PADDING_PX.px() * 2.0;
- let height = sprite_height.clone() - SHADOW_PX.px() * 2.0 - PADDING_PX.px() * 2.0;
+ let width = sprite_width - SHADOW_PX.px() * 2.0 - PADDING_PX.px() * 2.0;
+ let height = sprite_height - SHADOW_PX.px() * 2.0 - PADDING_PX.px() * 2.0;
let color = style.get_color(theme::widget::list_view::background);
let rect = Rect((&width,&height)).corners_radius(CORNER_RADIUS_PX.px());
let shape = rect.fill(color::Rgba::from(color));
- let corner_radius = CORNER_RADIUS_PX.px() + SHADOW_PX.px();
- let width = sprite_width - PADDING_PX.px() * 2.0;
- let height = sprite_height - PADDING_PX.px() * 2.0;
- let shadow = Rect((&width,&height)).corners_radius(corner_radius);
- let base_color = style.get_color(theme::widget::list_view::shadow);
- let fading_color = style.get_color(theme::widget::list_view::shadow::fading);
- let exponent = style.get_number_or(theme::widget::list_view::shadow::exponent,2.0);
- let shadow_color = color::gradient::Linear::::new(fading_color,base_color);
- let shadow_color = shadow_color.sdf_sampler().size(SHADOW_PX).exponent(exponent);
- let shadow = shadow.fill(shadow_color);
+ let shadow = shadow::from_shape(rect.into(),style);
(shadow + shape).into()
}
diff --git a/gui/src/rust/ensogl/lib/components/src/shadow.rs b/gui/src/rust/ensogl/lib/components/src/shadow.rs
new file mode 100644
index 00000000000..8355951c381
--- /dev/null
+++ b/gui/src/rust/ensogl/lib/components/src/shadow.rs
@@ -0,0 +1,62 @@
+//! Utilities to create consistent shadows for UI components.
+use crate::prelude::*;
+
+use ensogl_core::data::color;
+use ensogl_core::display::DomSymbol;
+use ensogl_core::display::shape::*;
+use ensogl_core::display::shape::AnyShape;
+use ensogl_core::system::web::StyleSetter;
+use ensogl_theme as theme;
+
+
+
+/// Return a shadow for the given shape. Exact appearance will depends on the theme parameters.
+pub fn from_shape(base_shape:AnyShape, style:&StyleWatch) -> AnyShape {
+ let alpha = Var::::from(1.0);
+ from_shape_with_alpha(base_shape,&alpha,style)
+}
+
+/// Return a shadow for the given shape. Exact appearance will depends on the theme parameters.
+/// The color will be multiplied with the given alpha value, which is useful for fade-in/out
+/// animations.
+pub fn from_shape_with_alpha(base_shape:AnyShape,alpha:&Var,style:&StyleWatch) -> AnyShape {
+ let shadow_size = style.get_number(theme::shadow::size);
+ let shadow_spread = style.get_number(theme::shadow::spread);
+ let shadow_off_x = style.get_number(theme::shadow::offset_x).px();
+ let shadow_off_y = style.get_number(theme::shadow::offset_y).px();
+
+ let shadow_grow = Var::::from(shadow_size);
+ let shadow = base_shape.grow(shadow_grow);
+ let shadow = shadow.translate((shadow_off_x,shadow_off_y));
+
+ let base_color = color::Rgba::from(style.get_color(theme::shadow));
+ let base_color = Var::::from(base_color);
+ let base_color = base_color.multiply_alpha(&alpha);
+
+ let fading_color = color::Rgba::from(style.get_color(theme::shadow::fading));
+ let fading_color = Var::::from(fading_color);
+ let fading_color = fading_color.multiply_alpha(&alpha);
+
+ let exp = style.get_number(theme::shadow::exponent);
+
+ let shadow_color = color::gradient::Linear::>
+ ::new(fading_color.into_linear(),base_color.into_linear());
+ let shadow_color = shadow_color.sdf_sampler().size(shadow_size)
+ .spread(shadow_spread).exponent(exp);
+ let shadow = shadow.fill(shadow_color);
+ shadow.into()
+}
+
+/// Add a theme defined box shadow to the given `DomSymbol`.
+pub fn add_to_dom_element(element:&DomSymbol, style:&StyleWatch,logger:&Logger) {
+
+ let shadow_off_x = style.get_number(theme::shadow::offset_x);
+ let shadow_off_y = style.get_number(theme::shadow::offset_y);
+
+ let shadow_alpha = style.get_number_or(ensogl_theme::shadow::html::alpha,0.16);
+ let shadow_blur = style.get_number_or(ensogl_theme::shadow::html::blur,16.0);
+ let shadow_spread = style.get_number_or(ensogl_theme::shadow::html::spread,0.0);
+ let shadow = format!("{}px {}px {}px {}px rgba(0, 0, 0, {})",shadow_off_x,shadow_off_y,
+ shadow_blur,shadow_spread,shadow_alpha);
+ element.dom().set_style_or_warn("box-shadow",shadow,&logger);
+}
diff --git a/gui/src/rust/ensogl/lib/theme/src/lib.rs b/gui/src/rust/ensogl/lib/theme/src/lib.rs
index 8bc47973d41..dda5d46913a 100644
--- a/gui/src/rust/ensogl/lib/theme/src/lib.rs
+++ b/gui/src/rust/ensogl/lib/theme/src/lib.rs
@@ -161,6 +161,9 @@ define_themes! { [light:0, dark:1]
hide_delay_duration_ms = 150.0, 150.0;
show_delay_duration_ms = 150.0, 150.0;
}
+ searcher {
+ action_list_gap = 5.0, 5.0;
+ }
}
code {
syntax {
@@ -197,15 +200,6 @@ define_themes! { [light:0, dark:1]
node {
background = Rgba(0.984,0.992,1.0,1.0) , Lcha(0.2,0.014,0.18,1.0);
background.skipped = Lcha(0.98,0.014,0.18,1.0) , Lcha(0.15,0.014,0.18,1.0);
- shadow = shadow , shadow;
- shadow {
- size = shadow::size , shadow::size;
- spread = shadow::spread , shadow::spread;
- fading = shadow::fading , shadow::fading;
- exponent = shadow::exponent , shadow::exponent;
- offset_x = shadow::offset_x , shadow::offset_x;
- offset_y = shadow::offset_y , shadow::offset_y;
- }
selection = selection, selection;
selection {
size = 10.0 , 5.0;
@@ -241,18 +235,6 @@ define_themes! { [light:0, dark:1]
}
visualization {
background = Lcha(0.98,0.014,0.18,1.0) , Lcha(0.2,0.014,0.18,1.0);
- shadow = Lcha(0.0,0.0,0.0,0.20) , Lcha(0.0,0.0,0.0,0.20);
- shadow {
- // Note[mm]: at the moment we use a CSS replacement shadow defined in the .visualization class of
- // `src/js/lib/content/src/index.html`. While that is in use this shadow is deactivated.
- size = 0.0, 0.0;
- fading = Lcha(0.0,0.0,0.0,0.0) , Lcha(0.0,0.0,0.0,0.0);
- exponent = 2.0 , 2.0;
- html {
- alpha = 0.16 , 0.16;
- size = 16.0 , 16.0;
- }
- }
text = Lcha(0.0,0.0,0.0,0.7) , Lcha(1.0,0.0,0.0,0.7);
text.selection = Lcha(0.7,0.0,0.125,0.7) , Lcha(0.7,0.0,0.125,0.7);
error {
@@ -286,11 +268,6 @@ define_themes! { [light:0, dark:1]
list_view {
background = graph_editor::node::background , graph_editor::node::background;
highlight = selection , selection;
- shadow = shadow , shadow;
- shadow {
- fading = shadow::fading , shadow::fading;
- exponent = shadow::exponent , shadow::exponent;
- }
text = Lcha(0.0,0.0,0.0,0.7) , Lcha(1.0,0.0,0.0,0.7);
text {
highlight = Lcha(0.8,0.0,0.0,1.0) , Lcha(0.7,0.0,0.0,1.0);
@@ -307,13 +284,7 @@ define_themes! { [light:0, dark:1]
component {
label {
background = Lcha(0.98,0.014,0.18,1.0) , Lcha(0.2,0.014,0.18,1.0);
- shadow = Lcha(0.0,0.0,0.0,0.20) , Lcha(0.0,0.0,0.0,0.20);
- shadow {
- fading = Lcha(0.0,0.0,0.0,0.0) , Lcha(0.0,0.0,0.0,0.0);
- exponent = 2.0 , 2.0;
- size = 10.0, 10.0;
- }
- text = Lcha(0.0,0.0,0.0,0.7) , Lcha(1.0,0.0,0.0,0.7);
+ text = Lcha(0.0,0.0,0.0,0.7) , Lcha(1.0,0.0,0.0,0.7);
text {
offset = 10.0, 10.0;
size = 12.0, 12.0;
@@ -335,5 +306,10 @@ define_themes! { [light:0, dark:1]
exponent = 3.0 , 3.0; // 2
offset_x = 0.0 , 0.0;
offset_y = -2.0 , -2.0;
+ html {
+ alpha = 0.16 , 0.16;
+ blur = 10.0 , 10.0;
+ spread = -2.0 , -2.0;
+ }
}
}
diff --git a/gui/src/rust/ide/view/graph-editor/src/component/node.rs b/gui/src/rust/ide/view/graph-editor/src/component/node.rs
index cc9e64704ed..5edaf47aa7e 100644
--- a/gui/src/rust/ide/view/graph-editor/src/component/node.rs
+++ b/gui/src/rust/ide/view/graph-editor/src/component/node.rs
@@ -31,6 +31,7 @@ use ensogl::data::color;
use ensogl::display::shape::*;
use ensogl::display::traits::*;
use ensogl::display;
+use ensogl_gui_components::shadow;
use ensogl_text::Text;
use ensogl_theme;
use std::f32::EPSILON;
@@ -89,7 +90,6 @@ pub mod backdrop {
ensogl::define_shape_system! {
(style:Style, selection:f32) {
- use ensogl_theme::graph_editor::node as node_theme;
let width = Var::::from("input_size.x");
let height = Var::::from("input_size.y");
@@ -98,21 +98,9 @@ pub mod backdrop {
// === Shadow ===
- let shadow_size = style.get_number(node_theme::shadow::size);
- let shadow_spread = style.get_number(node_theme::shadow::spread);
- let shadow_width = &width + &shadow_size.px() * 2.0;
- let shadow_height = &height + &shadow_size.px() * 2.0;
- let shadow_radius = &shadow_height / 2.0;
- let shadow_off_x = style.get_number(node_theme::shadow::offset_x).px();
- let shadow_off_y = style.get_number(node_theme::shadow::offset_y).px();
- let shadow = Rect((shadow_width,shadow_height)).corners_radius(shadow_radius);
- let shadow = shadow.translate((shadow_off_x,shadow_off_y));
- let base_color = style.get_color(node_theme::shadow);
- let fading_color = style.get_color(node_theme::shadow::fading);
- let exp = style.get_number(node_theme::shadow::exponent);
- let shadow_color = color::gradient::Linear::::new(fading_color,base_color);
- let shadow_color = shadow_color.sdf_sampler().size(shadow_size).spread(shadow_spread).exponent(exp);
- let shadow = shadow.fill(shadow_color);
+ let shadow_radius = &height / 2.0;
+ let shadow_base = Rect((&width,&height)).corners_radius(shadow_radius);
+ let shadow = shadow::from_shape(shadow_base.into(),style);
// === Selection ===
diff --git a/gui/src/rust/ide/view/graph-editor/src/component/visualization/container.rs b/gui/src/rust/ide/view/graph-editor/src/component/visualization/container.rs
index 94fc386b6b2..7e978f9e159 100644
--- a/gui/src/rust/ide/view/graph-editor/src/component/visualization/container.rs
+++ b/gui/src/rust/ide/view/graph-editor/src/component/visualization/container.rs
@@ -20,17 +20,17 @@ use crate::component::visualization::instance::PreprocessorConfiguration;
use action_bar::ActionBar;
use enso_frp as frp;
+use ensogl::application::Application;
use ensogl::data::color;
use ensogl::display::DomSymbol;
-use ensogl::display::scene;
use ensogl::display::scene::Scene;
+use ensogl::display::scene;
use ensogl::display::shape::*;
use ensogl::display::traits::*;
use ensogl::display;
-use ensogl::application::Application;
-use ensogl::system::web;
use ensogl::system::web::StyleSetter;
-use ensogl_theme as theme;
+use ensogl::system::web;
+use ensogl_gui_components::shadow;
@@ -49,52 +49,6 @@ const ACTION_BAR_HEIGHT : f32 = 2.0 * CORNER_RADIUS;
// === Shape ===
// =============
-/// Container background shape definition.
-///
-/// Provides a backdrop and outline for visualizations. Can indicate the selection status of the
-/// container.
-/// TODO : We do not use backgrounds because otherwise they would overlap JS
-/// visualizations. Instead, we added an HTML background to the `View`.
-/// This should be further investigated while fixing rust visualization displaying. (#526)
-pub mod background {
- use super::*;
-
- ensogl::define_shape_system! {
- (style:Style,selected:f32,radius:f32,roundness:f32) {
- use theme::graph_editor::visualization as visualization_theme;
-
- let width = Var::::from("input_size.x");
- let height = Var::::from("input_size.y");
- let shadow_size = style.get_number(visualization_theme::shadow::size);
- let width = &width - shadow_size.px() * 2.0;
- let height = &height - shadow_size.px() * 2.0;
- let radius = 1.px() * &radius;
- let color_bg = style.get_color(visualization_theme::background);
- let corner_radius = &radius * &roundness;
- let background = Rect((&width,&height)).corners_radius(&corner_radius);
- let background = background.fill(color::Rgba::from(color_bg));
-
- // === Shadow ===
-
- let corner_radius = corner_radius*1.75;
- let width = &width + shadow_size.px() * 2.0;
- let height = &height + shadow_size.px() * 2.0;
- let shadow = Rect((&width,&height)).corners_radius(&corner_radius).shrink(1.px());
- let base_color = style.get_color(visualization_theme::shadow);
- let fading_color = style.get_color(visualization_theme::shadow::fading);
- let exp = style.get_number_or(visualization_theme::shadow::exponent,2.0);
- let shadow_color = color::gradient::Linear::::new(fading_color,base_color);
- let shadow_color = shadow_color.sdf_sampler().size(shadow_size).exponent(exp);
- let shadow = shadow.fill(shadow_color);
-
- let out = shadow + background;
- out.into()
- }
- }
-}
-
-
-
/// Container overlay shape definition. Used to capture events over the visualisation within the
/// container.
pub mod overlay {
@@ -180,10 +134,6 @@ impl View {
let bg_color = color::Rgba::from(bg_color);
let bg_hex = format!("rgba({},{},{},{})",bg_color.red*255.0,bg_color.green*255.0,bg_color.blue*255.0,bg_color.alpha);
- let shadow_alpha = styles.get_number_or(ensogl_theme::graph_editor::visualization::shadow::html::alpha,0.16);
- let shadow_size = styles.get_number_or(ensogl_theme::graph_editor::visualization::shadow::html::size,16.0);
- let shadow = format!("0 0 {}px rgba(0, 0, 0, {})",shadow_size,shadow_alpha);
-
let div = web::create_div();
let background_dom = DomSymbol::new(&div);
// TODO : We added a HTML background to the `View`, because "shape" background was overlapping
@@ -196,7 +146,7 @@ impl View {
background_dom.dom().set_style_or_warn("overflow-x" ,"auto",&logger);
background_dom.dom().set_style_or_warn("background" ,bg_hex,&logger);
background_dom.dom().set_style_or_warn("border-radius","14px",&logger);
- background_dom.dom().set_style_or_warn("box-shadow" ,shadow,&logger);
+ shadow::add_to_dom_element(&background_dom,&styles,&logger);
display_object.add_child(&background_dom);
scene.dom.layers.back.manage(&background_dom);
diff --git a/gui/src/rust/ide/view/src/documentation.rs b/gui/src/rust/ide/view/src/documentation.rs
index 602b0ef6ea1..5ce5216b1b7 100644
--- a/gui/src/rust/ide/view/src/documentation.rs
+++ b/gui/src/rust/ide/view/src/documentation.rs
@@ -19,6 +19,7 @@ use ensogl::system::web::AttributeSetter;
use ensogl::system::web::StyleSetter;
use ensogl::system::web::clipboard;
use ensogl::system::web;
+use ensogl_gui_components::shadow;
use wasm_bindgen::JsCast;
use wasm_bindgen::closure::Closure;
use web_sys::HtmlElement;
@@ -98,12 +99,6 @@ impl Model {
let bg_hex = format!("rgba({},{},{},{})",
bg_color.red*255.0,bg_color.green*255.0,bg_color.blue*255.0,bg_color.alpha);
- let shadow_alpha_path = ensogl_theme::graph_editor::visualization::shadow::html::alpha;
- let shadow_alpha_size = ensogl_theme::graph_editor::visualization::shadow::html::size;
- let shadow_alpha = styles.get_number_or(shadow_alpha_path,0.16);
- let shadow_size = styles.get_number_or(shadow_alpha_size,16.0);
- let shadow = format!("0 0 {}px rgba(0, 0, 0, {})",shadow_size,shadow_alpha);
-
dom.dom().set_attribute_or_warn("class" ,"scrollable" ,&logger);
dom.dom().set_style_or_warn("white-space" ,"normal" ,&logger);
dom.dom().set_style_or_warn("overflow-y" ,"auto" ,&logger);
@@ -112,7 +107,7 @@ impl Model {
dom.dom().set_style_or_warn("padding" ,format!("{}px",PADDING) ,&logger);
dom.dom().set_style_or_warn("pointer-events" ,"auto" ,&logger);
dom.dom().set_style_or_warn("border-radius" ,format!("{}px",CORNER_RADIUS),&logger);
- dom.dom().set_style_or_warn("box-shadow" ,shadow ,&logger);
+ shadow::add_to_dom_element(&dom,&styles,&logger);
overlay.roundness.set(1.0);
overlay.radius.set(CORNER_RADIUS);
diff --git a/gui/src/rust/ide/view/src/searcher.rs b/gui/src/rust/ide/view/src/searcher.rs
index 6399dba1a38..9b7bc7988dd 100644
--- a/gui/src/rust/ide/view/src/searcher.rs
+++ b/gui/src/rust/ide/view/src/searcher.rs
@@ -7,12 +7,13 @@ use crate::prelude::*;
use crate::documentation;
use enso_frp as frp;
-use ensogl::application;
-use ensogl::application::{Application, shortcut};
-use ensogl::display;
use ensogl::DEPRECATED_Animation;
-use ensogl_gui_components::list_view;
+use ensogl::application::{Application, shortcut};
+use ensogl::application;
+use ensogl::display::shape::*;
+use ensogl::display;
use ensogl_gui_components::list_view::ListView;
+use ensogl_gui_components::list_view;
pub use ensogl_gui_components::list_view::entry;
@@ -104,6 +105,13 @@ impl Model {
scene.layers.below_main.add_exclusive(&list);
display_object.add_child(&documentation);
display_object.add_child(&list);
+
+ // FIXME: StyleWatch is unsuitable here, as it was designed as an internal tool for shape
+ // system (#795)
+ let style = StyleWatch::new(&app.display.scene().style_sheet);
+ let action_list_gap_path = ensogl_theme::application::searcher::action_list_gap;
+ let action_list_gap = style.get_number_or(action_list_gap_path,0.0);
+ list.set_position_y(-action_list_gap);
list.set_position_x(ACTION_LIST_X);
documentation.set_position_x(DOCUMENTATION_X);
Self{app,logger,display_object,list,documentation,doc_provider}