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}