diff --git a/Cargo.lock b/Cargo.lock index 41bec182f20..d6a49538315 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1644,6 +1644,7 @@ dependencies = [ "ensogl", "ensogl-hardcoded-theme", "ide-view-component-list-panel-grid", + "ide-view-component-list-panel-icons", "wasm-bindgen", ] @@ -4063,7 +4064,6 @@ dependencies = [ "ensogl-grid-view", "ensogl-gui-component", "ensogl-hardcoded-theme", - "ensogl-list-view", "ensogl-scroll-area", "ensogl-selector", "ensogl-shadow", @@ -4071,6 +4071,7 @@ dependencies = [ "ensogl-tooltip", "ide-view-component-list-panel-breadcrumbs", "ide-view-component-list-panel-grid", + "ide-view-component-list-panel-icons", "ordered-float", ] @@ -4080,6 +4081,7 @@ version = "0.1.0" dependencies = [ "enso-frp", "ensogl-core", + "ensogl-derive-theme", "ensogl-grid-view", "ensogl-hardcoded-theme", "ensogl-text", @@ -4095,13 +4097,21 @@ dependencies = [ "ensogl-grid-view", "ensogl-gui-component", "ensogl-hardcoded-theme", - "ensogl-list-view", "ensogl-shadow", "ensogl-text", "failure", + "ide-view-component-list-panel-icons", "num_enum", ] +[[package]] +name = "ide-view-component-list-panel-icons" +version = "0.1.0" +dependencies = [ + "ensogl-core", + "failure", +] + [[package]] name = "ide-view-graph-editor" version = "0.1.0" diff --git a/app/gui/view/component-browser/component-list-panel/Cargo.toml b/app/gui/view/component-browser/component-list-panel/Cargo.toml index a1a00531d2b..7da760497d9 100644 --- a/app/gui/view/component-browser/component-list-panel/Cargo.toml +++ b/app/gui/view/component-browser/component-list-panel/Cargo.toml @@ -12,7 +12,6 @@ enso-frp = { path = "../../../../../lib/rust/frp" } ensogl-core = { path = "../../../../../lib/rust/ensogl/core" } ensogl-gui-component = { path = "../../../../../lib/rust/ensogl/component/gui/" } ensogl-grid-view = { path = "../../../../../lib/rust/ensogl/component/grid-view/" } -ensogl-list-view = { path = "../../../../../lib/rust/ensogl/component/list-view/" } ensogl-hardcoded-theme = { path = "../../../../../lib/rust/ensogl/app/theme/hardcoded" } ensogl-derive-theme = { path = "../../../../../lib/rust/ensogl/app/theme/derive" } ensogl-scroll-area = { path = "../../../../../lib/rust/ensogl/component/scroll-area" } @@ -22,6 +21,7 @@ ensogl-text = { path = "../../../../../lib/rust/ensogl/component/text" } ensogl-tooltip = { path = "../../../../../lib/rust/ensogl/component/tooltip/" } ide-view-component-list-panel-breadcrumbs = { path = "breadcrumbs" } ide-view-component-list-panel-grid = { path = "grid" } +ide-view-component-list-panel-icons = { path = "icons" } ordered-float = "3.0.0" [dev-dependencies] diff --git a/app/gui/view/component-browser/component-list-panel/breadcrumbs/Cargo.toml b/app/gui/view/component-browser/component-list-panel/breadcrumbs/Cargo.toml index dd36ca5b34c..116e83ea048 100644 --- a/app/gui/view/component-browser/component-list-panel/breadcrumbs/Cargo.toml +++ b/app/gui/view/component-browser/component-list-panel/breadcrumbs/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] enso-frp = { path = "../../../../../../lib/rust/frp" } ensogl-core = { path = "../../../../../../lib/rust/ensogl/core" } +ensogl-derive-theme = { path = "../../../../../../lib/rust/ensogl/app/theme/derive" } ensogl-hardcoded-theme = { path = "../../../../../../lib/rust/ensogl/app/theme/hardcoded" } ensogl-text = { path = "../../../../../../lib/rust/ensogl/component/text" } ensogl-grid-view = { path = "../../../../../../lib/rust/ensogl/component/grid-view" } diff --git a/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/entry.rs b/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/entry.rs index 78b634f9b73..307e9a0f3a7 100644 --- a/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/entry.rs +++ b/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/entry.rs @@ -10,6 +10,7 @@ use ensogl_core::data::color; use ensogl_core::display; use ensogl_core::display::scene::Layer; use ensogl_core::Animation; +use ensogl_derive_theme::FromTheme; use ensogl_grid_view::entry::Contour; use ensogl_grid_view::entry::EntryFrp; use ensogl_grid_view::Col; @@ -27,15 +28,20 @@ pub mod separator { use super::*; use std::f32::consts::PI; - pub const ICON_WIDTH: f32 = 16.0; + pub const ICON_WIDTH: f32 = 30.0; ensogl_core::shape! { above = [ensogl_grid_view::entry::shape]; pointer_events = false; - (style: Style, color: Vector4) { + (style: Style) { + let color = style.get_color(theme::separator::color); let width = style.get_number(theme::separator::width); let height = style.get_number(theme::separator::height); let triangle = Triangle(width, height).rotate((PI/2.0).radians()); + let offset_x = style.get_number(theme::separator::offset_x).px(); + let offset_y = style.get_number(theme::separator::offset_y).px(); + let triangle = triangle.translate_x(offset_x); + let triangle = triangle.translate_y(offset_y); let shape = triangle.fill(color); shape.into() } @@ -47,21 +53,19 @@ pub mod separator { pub mod ellipsis { use super::*; - pub const ICON_WIDTH: f32 = 32.0; + pub const ICON_WIDTH: f32 = 28.0; ensogl_core::shape! { above = [ensogl_grid_view::entry::shape]; pointer_events = false; - (style: Style, alpha: f32) { + (style: Style) { let radius = style.get_number(theme::ellipsis::circles_radius).px(); let gap = style.get_number(theme::ellipsis::circles_gap).px(); let background_width = style.get_number(theme::ellipsis::background_width); let background_height = style.get_number(theme::ellipsis::background_height); let background_corners_radius = style.get_number(theme::ellipsis::background_corners_radius); - let col = style.get_color(theme::ellipsis::circles_color); - let circles_color = Var::::rgba(col.red,col.green,col.blue,alpha.clone()); - let bg_col = style.get_color(theme::ellipsis::background_color); - let background_color = Var::::rgba(bg_col.red,bg_col.green,bg_col.blue,alpha); + let circles_color = style.get_color(theme::ellipsis::circles_color); + let background_color = style.get_color(theme::ellipsis::background_color); let tile_size = radius.clone() * 2.0 + gap; let circles = Circle(radius).repeat((tile_size.clone(), tile_size.clone())); @@ -71,6 +75,10 @@ pub mod ellipsis { let background = background.corners_radius(background_corners_radius.px()); let background = background.fill(background_color); let shape = background + circles; + let offset_x = style.get_number(theme::ellipsis::offset_x).px(); + let offset_y = style.get_number(theme::ellipsis::offset_y).px(); + let shape = shape.translate_x(offset_x); + let shape = shape.translate_y(offset_y); shape.into() } } @@ -78,6 +86,30 @@ pub mod ellipsis { +// ============= +// === Style === +// ============= + +/// Stylesheet-defined portion of the entries' parameters. +#[allow(missing_docs)] +#[derive(Clone, Debug, Default, FromTheme)] +#[base_path = "theme::entry"] +pub struct Style { + /// The margin of the entry's [`Contour`]. The [`Contour`] specifies the size of the + /// clickable area of the entry. If the margin is zero, the contour covers the entire entry. + pub margin: f32, + pub hover_color: color::Rgba, + #[theme_path = "theme::entry::font"] + pub font_name: ImString, + pub text_y_offset: f32, + pub text_padding_left: f32, + pub text_size: f32, + pub selected_color: color::Rgba, + pub highlight_corners_radius: f32, + pub greyed_out_color: color::Rgba, +} + + // ============= // === Model === // ============= @@ -178,25 +210,24 @@ impl EntryData { } } - fn update_layout(&self, contour: Contour, text_size: text::Size, text_padding: f32) { + fn update_layout(&self, contour: Contour, text_padding: f32, text_y_offset: f32) { let size = contour.size; - self.text.set_xy(Vector2(text_padding - size.x / 2.0, text_size.value / 2.0)); - self.separator.size.set(size); - self.ellipsis.size.set(size); + self.text.set_xy(Vector2(text_padding - size.x / 2.0, text_y_offset)); + self.separator.size.set(Vector2(separator::ICON_WIDTH, size.y)); + self.ellipsis.size.set(Vector2(ellipsis::ICON_WIDTH, size.y)); } fn set_default_color(&self, color: color::Lcha) { self.text.set_property_default(color); - self.ellipsis.alpha.set(color.alpha); - self.separator.color.set(color::Rgba::from(color).into()); } fn set_font(&self, font: String) { self.text.set_font(font); } - fn set_default_text_size(&self, size: text::Size) { - self.text.set_property_default(size); + fn set_default_text_size(&self, size: f32) { + self.text.set_property_default(text::Size::new(size)); + self.text.set_property_default(text::Weight::Medium); } fn is_state_change(&self, model: &Model) -> bool { @@ -231,26 +262,19 @@ impl EntryData { } } + // === Params === /// The style parameters of Breadcrumbs' entries. See [`ensogl_grid_view::Frp::set_entries_params`]. #[allow(missing_docs)] #[derive(Clone, Debug, Default)] pub struct Params { - /// The margin of the entry's [`Contour`]. The [`Contour`] specifies the size of the - /// clickable area of the entry. If the margin is zero, the contour covers the entire entry. - pub margin: f32, - pub hover_color: color::Lcha, - pub font_name: ImString, - pub text_padding: f32, - pub text_size: text::Size, - pub selected_color: color::Lcha, - pub highlight_corners_radius: f32, - pub greyed_out_color: color::Lcha, + pub style: Style, /// The first greyed out column. All columns to the right will also be greyed out. - pub greyed_out_start: Option, + pub greyed_out_start: Option, } + // === Entry === /// A Breadcrumbs entry. @@ -279,15 +303,16 @@ impl ensogl_grid_view::Entry for Entry { enso_frp::extend! { network init <- source_(); size <- input.set_size.on_change(); - margin <- input.set_params.map(|p| p.margin).on_change(); - hover_color <- input.set_params.map(|p| p.hover_color).on_change(); - font <- input.set_params.map(|p| p.font_name.clone_ref()).on_change(); - text_padding <- input.set_params.map(|p| p.text_padding).on_change(); - text_color <- input.set_params.map(|p| p.selected_color).on_change(); - text_size <- input.set_params.map(|p| p.text_size).on_change(); - greyed_out_color <- input.set_params.map(|p| p.greyed_out_color).on_change(); + margin <- input.set_params.map(|p| p.style.margin).on_change(); + hover_color <- input.set_params.map(|p| p.style.hover_color).cloned_into().on_change(); + font <- input.set_params.map(|p| p.style.font_name.clone_ref()).on_change(); + text_padding <- input.set_params.map(|p| p.style.text_padding_left).on_change(); + text_color <- input.set_params.map(|p| p.style.selected_color).cloned_into().on_change(); + text_y_offset <- input.set_params.map(|p| p.style.text_y_offset).on_change(); + text_size <- input.set_params.map(|p| p.style.text_size).on_change(); + greyed_out_color <- input.set_params.map(|p| p.style.greyed_out_color).cloned_into().on_change(); + highlight_corners_radius <- input.set_params.map(|p| p.style.highlight_corners_radius).on_change(); greyed_out_from <- input.set_params.map(|p| p.greyed_out_start).on_change(); - highlight_corners_radius <- input.set_params.map(|p| p.highlight_corners_radius).on_change(); transparent_color <- init.constant(color::Lcha::transparent()); col <- input.set_location._1(); @@ -310,8 +335,8 @@ impl ensogl_grid_view::Entry for Entry { size: *size - Vector2(*margin, *margin) * 2.0, corners_radius: 0.0, }); - layout <- all(contour, text_size, text_padding); - eval layout ((&(c, ts, to)) data.update_layout(c, ts, to)); + layout <- all(contour, text_padding, text_y_offset); + eval layout ((&(c, to, tyo)) data.update_layout(c, to, tyo)); eval color((c) data.set_default_color(*c)); eval font((f) data.set_font(f.to_string())); eval text_size((s) data.set_default_text_size(*s)); @@ -335,8 +360,8 @@ impl ensogl_grid_view::Entry for Entry { data.width(*text_padding) }) ); - text_width <- data.text.width.filter(f_!(data.is_text_displayed())); // For text entries, we also listen for [`Text::width`] changes. + text_width <- data.text.width.filter(f_!(data.is_text_displayed())); entry_width <- text_width.map2(&text_padding, f!((w, o) data.text_width(*w, *o))); out.override_column_width <+ entry_width; } diff --git a/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs b/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs index ba2a4897320..c0a0d9a33dd 100644 --- a/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs +++ b/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs @@ -52,7 +52,6 @@ use ensogl_core::Animation; use ensogl_grid_view as grid_view; use ensogl_grid_view::Viewport; use ensogl_hardcoded_theme::application::component_browser as component_browser_theme; -use ensogl_text as text; use entry::Entry; use grid_view::Col; @@ -175,57 +174,17 @@ impl Model { ); grid.model_for_entry <+ requested_entry; } - let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet); - let params = Self::params_from_style(&style, &network, init.clone_ref()); + let style_frp = StyleWatchFrp::new(&app.display.default_scene.style_sheet); + let style = entry::Style::from_theme(&network, &style_frp); frp::extend! { network + params <- style.update.map(|s| entry::Params { style: s.clone(), greyed_out_start: None }); grid.set_entries_params <+ params; } init.emit(()); + style.init.emit(()); Self { display_object, grid, entries, network, mask, show_ellipsis } } - /// Prepare an [`frp::Sampler`] that emits the parameters for the grid view's entries on - /// style sheet changes. - fn params_from_style( - style: &StyleWatchFrp, - network: &frp::Network, - init: frp::Source<()>, - ) -> frp::Sampler { - frp::extend! { network - let margin = style.get_number(theme::entry::margin); - let hover_color = style.get_color(theme::entry::hover_color); - let font = style.get_text(theme::entry::font); - let text_padding = style.get_number(theme::entry::text_padding_left); - let text_size = style.get_number(theme::entry::text_size); - let selected_color = style.get_color(theme::entry::selected_color); - let highlight_corners_radius = style.get_number(theme::entry::highlight_corners_radius); - let greyed_out_color = style.get_color(theme::entry::greyed_out_color); - greyed_out_start <- init.constant(None); - text_params <- all4(&init, &text_padding,&text_size,&font); - colors <- all4(&init, &hover_color,&selected_color,&greyed_out_color); - params <- all_with6(&init,&margin,&text_params,&colors,&highlight_corners_radius, - &greyed_out_start, - |_,&margin,text_params,colors,&highlight_corners_radius,&greyed_out_start| { - let (_, text_padding,text_size,font) = text_params; - let (_, hover_color,selected_color,greyed_out_color) = colors; - entry::Params { - margin, - text_padding: *text_padding, - text_size: text::Size::from(*text_size), - hover_color: hover_color.into(), - font_name: font.clone(), - selected_color: selected_color.into(), - highlight_corners_radius, - greyed_out_color: greyed_out_color.into(), - greyed_out_start - } - } - ); - params_sampler <- params.sampler(); - } - params_sampler - } - fn set_layers(&self, layers: Layers) { layers.mask.add(&self.mask); @@ -498,8 +457,8 @@ impl Breadcrumbs { eval input.set_entry(((index, entry)) model.set_entry(entry, *index)); out.selected <+ selected; - scroll_anim.target <+ all_with3(&model.grid.content_size, &input.set_size, &model.grid - .entry_selected, + scroll_anim.target <+ all_with3( + &model.grid.content_size, &input.set_size, &model.grid.entry_selected, f!((content_size, size, _) { model.update_layout(*content_size, *size); model.offset(*content_size, *size) diff --git a/app/gui/view/component-browser/component-list-panel/grid/Cargo.toml b/app/gui/view/component-browser/component-list-panel/grid/Cargo.toml index d851f988094..f13d2b39c76 100644 --- a/app/gui/view/component-browser/component-list-panel/grid/Cargo.toml +++ b/app/gui/view/component-browser/component-list-panel/grid/Cargo.toml @@ -11,8 +11,8 @@ ensogl-derive-theme = { path = "../../../../../../lib/rust/ensogl/app/theme/deri ensogl-hardcoded-theme = { path = "../../../../../../lib/rust/ensogl/app/theme/hardcoded" } ensogl-text = { path = "../../../../../../lib/rust/ensogl/component/text" } ensogl-grid-view = { path = "../../../../../../lib/rust/ensogl/component/grid-view" } -ensogl-list-view = { path = "../../../../../../lib/rust/ensogl/component/list-view" } ensogl-gui-component = { path = "../../../../../../lib/rust/ensogl/component/gui" } ensogl-shadow = { version = "0.1.0", path = "../../../../../../lib/rust/ensogl/component/shadow" } +ide-view-component-list-panel-icons = { path = "../icons" } failure = "0.1.8" num_enum = "0.5.1" diff --git a/app/gui/view/component-browser/component-list-panel/grid/src/entry.rs b/app/gui/view/component-browser/component-list-panel/grid/src/entry.rs index 4208d1290e0..999b27492cc 100644 --- a/app/gui/view/component-browser/component-list-panel/grid/src/entry.rs +++ b/app/gui/view/component-browser/component-list-panel/grid/src/entry.rs @@ -5,8 +5,8 @@ use ensogl_core::display::shape::*; use crate::content::GroupId; use crate::content::SectionId; -use crate::entry::style::ColorIntensities; use crate::entry::style::Colors; +use crate::entry::style::ResolvedColors; use crate::GroupColors; use crate::Style as GridStyle; @@ -196,11 +196,11 @@ impl DimmedGroups { #[allow(missing_docs)] #[derive(Clone, Debug, Default)] pub struct Params { - pub style: Style, - pub grid_style: GridStyle, - pub color_intensities: ColorIntensities, - pub group_colors: GroupColors, - pub dimmed_groups: DimmedGroups, + pub style: Style, + pub grid_style: GridStyle, + pub colors: Colors, + pub group_colors: GroupColors, + pub dimmed_groups: DimmedGroups, } @@ -216,8 +216,7 @@ pub struct Params { #[derive(Debug)] struct CurrentIcon { display_object: display::object::Instance, - vivid_color: color::Lcha, - dull_color: color::Lcha, + color: color::Lcha, shape: Option, id: Option, } @@ -226,8 +225,7 @@ impl Default for CurrentIcon { fn default() -> Self { Self { display_object: display::object::Instance::new(), - vivid_color: default(), - dull_color: default(), + color: default(), shape: default(), id: default(), } @@ -240,8 +238,7 @@ impl CurrentIcon { self.id = new_icon; if let Some(icon_id) = new_icon { let shape = icon_id.create_shape(Vector2(icon::SIZE, icon::SIZE)); - shape.set_vivid_color(color::Rgba::from(self.vivid_color).into()); - shape.set_dull_color(color::Rgba::from(self.dull_color).into()); + shape.set_color(color::Rgba::from(self.color).into()); self.display_object.add_child(&shape); self.shape = Some(shape); } else { @@ -250,17 +247,10 @@ impl CurrentIcon { } } - fn set_vivid_color(&mut self, color: color::Lcha) { - self.vivid_color = color; + fn set_color(&mut self, color: color::Lcha) { + self.color = color; if let Some(shape) = &self.shape { - shape.set_vivid_color(color::Rgba::from(color).into()); - } - } - - fn set_dull_color(&mut self, color: color::Lcha) { - self.dull_color = color; - if let Some(shape) = &self.shape { - shape.set_dull_color(color::Rgba::from(color).into()); + shape.set_color(color::Rgba::from(color).into()); } } } @@ -326,26 +316,30 @@ impl Data { Kind::LocalScopeEntry { .. } => entry_size.x, _ => grid_style.column_width(), }; - let bg_height = entry_size.y - gap_over_header + overlap; + let bg_height = entry_size.y + overlap; // See comment in [`Self::update_shadow`] method. let shadow_addition = self.background.size.get().y - self.background.height.get(); let bg_sprite_height = bg_height + shadow_addition; - let bg_y = -gap_over_header / 2.0 + overlap / 2.0 + local_scope_offset; + let bg_y = -gap_over_header + overlap / 2.0 + local_scope_offset; self.background.set_y(bg_y); self.background.size.set(Vector2(bg_width, bg_sprite_height)); self.background.height.set(bg_height); - let left = -entry_size.x / 2.0 + style.padding; + let width = grid_style.column_width(); + let left = -width / 2.0 + style.padding; let icon_x = left + style.icon_size / 2.0; let icon_y = local_scope_offset; self.icon.borrow().set_xy(Vector2(icon_x, icon_y)); + let text_y_offset = match kind { + Kind::Header => style.text_y_offset_header, + _ => style.text_y_offset, + }; let text_x = Self::text_x_position(kind, style, grid_style); - let text_y = style.text_size / 2.0 + local_scope_offset; + let text_y = text_y_offset + local_scope_offset; self.label.set_xy(Vector2(text_x, text_y)); } - fn contour(kind: Kind, grid_style: &GridStyle, entry_size: Vector2) -> Contour { - let optional_gap = if kind == Kind::Header { grid_style.column_gap } else { 0.0 }; - let height = entry_size.y - optional_gap; + fn contour(grid_style: &GridStyle, entry_size: Vector2) -> Contour { + let height = entry_size.y; Contour::rectangular(Vector2(grid_style.column_width(), height)) } @@ -356,7 +350,7 @@ impl Data { fn contour_offset(kind: Kind, grid_style: &GridStyle) -> Vector2 { let y = match kind { - Kind::Header => -grid_style.column_gap / 2.0, + Kind::Header => -grid_style.column_gap, Kind::LocalScopeEntry { .. } => -grid_style.column_gap, _ => 0.0, }; @@ -372,7 +366,7 @@ impl Data { fn text_x_position(kind: Kind, style: &Style, grid_style: &GridStyle) -> f32 { let left = -grid_style.column_width() / 2.0 + style.padding; if kind == Kind::Header { - left + left + style.text_x_offset_header } else { left + style.icon_size + style.icon_text_padding } @@ -444,7 +438,7 @@ impl grid_view::Entry for View { kind <- input.set_model.map(|m| m.kind).on_change(); style <- input.set_params.map(|p| p.style.clone()).on_change(); - color_intensities <- input.set_params.map(|p| p.color_intensities).on_change(); + colors <- input.set_params.map(|p| p.colors).on_change(); group_colors <- input.set_params.map(|p| p.group_colors).on_change(); grid_style <- input.set_params.map(|p| p.grid_style).on_change(); kind_and_style <- all(kind, style, grid_style); @@ -452,8 +446,8 @@ impl grid_view::Entry for View { eval layout_data ((((kind, style, grid_style), entry_sz)) data.update_layout(*kind, style, grid_style, *entry_sz) ); - out.contour <+ layout_data.map(|((kind, _, grid_style), entry_sz)| { - Data::contour(*kind, grid_style, *entry_sz) + out.contour <+ all_with(&grid_style, &input.set_size, |grid_style, entry_sz| { + Data::contour(grid_style, *entry_sz) }); out.contour_offset <+ kind_and_style.map(|(k, _, gs)| Data::contour_offset(*k, gs)); out.highlight_contour <+ out.contour.map2(&style, |c, s| Data::highlight_contour(*c, s)); @@ -467,11 +461,10 @@ impl grid_view::Entry for View { is_dimmed <- all_with(&input.set_model, &input.set_params, |m,p| { p.dimmed_groups.is_group_dimmed(m.group_id) }); - let colors = Colors::from_main_color(network, &data.style, &color, &color_intensities, &is_dimmed); + let colors = ResolvedColors::from_main_color(network, &data.style, &color, &colors, &is_dimmed); eval colors.background ((c) data.background.color.set(color::Rgba::from(c).into())); data.label.set_property_default <+ colors.text.ref_into_some(); - eval colors.icon_strong ((c) data.icon.borrow_mut().set_vivid_color(*c)); - eval colors.icon_weak ((c) data.icon.borrow_mut().set_dull_color(*c)); + eval colors.icon ((c) data.icon.borrow_mut().set_color(*c)); out.hover_highlight_color <+ colors.hover_highlight; // We want to animate only when params changed (the different section is highlighted). // Other case, where entry receives new model with new section means it is reused @@ -494,15 +487,20 @@ impl grid_view::Entry for View { data.label.set_view_width <+ max_text_width.some(); content_changed <- data.label.content.constant(()); style_changed <- style.constant(()); - highlight_range <= all_with3( - &input.set_model, - &content_changed, - &style_changed, - |m, (), ()| m.highlighted.deref().clone() - ); + label_updated <- all3(&input.set_model, &content_changed, &style_changed); + highlight_range <= label_updated.map(|(m, (), ())| m.highlighted.deref().clone()); data.label.set_property <+ highlight_range.map2(&style, |range, s| { (range.into(), Some(text::SdfWeight::new(s.highlight_bold).into())) }); + is_header <- label_updated.map(|(m, (), ())| m.kind == Kind::Header); + is_not_header <- is_header.on_false(); + is_header <- is_header.on_true(); + data.label.set_property <+ is_header.map(|_| { + ((..).into(), Some(text::Weight::ExtraBold.into())) + }); + data.label.set_property <+ is_not_header.map(|_| { + ((..).into(), Some(text::Weight::Medium.into())) + }); data.label.set_property_default <+ style.map(|s| text::Size::new(s.text_size)).cloned_into_some(); eval icon ((&icon) data.icon.borrow_mut().update(icon)); data.label.set_font <+ style.map(|s| s.font.clone_ref()).on_change(); diff --git a/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon.rs b/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon.rs index d11ae0d161d..d3be938e05a 100644 --- a/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon.rs +++ b/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon.rs @@ -1,119 +1,25 @@ //! All icons that are used in the Component Browser. +use crate::prelude::*; +use ide_view_component_list_panel_icons::common_part::*; + +use ensogl_core::data::color; +use ensogl_core::display::shape::compound::path::path; +use ensogl_grid_view as grid_view; +use ensogl_hardcoded_theme::application::component_browser::component_list_panel as theme; +use ide_view_component_list_panel_icons::define_icons; +use ide_view_component_list_panel_icons::SHRINK_AMOUNT; +use std::f32::consts::PI; +use theme::grid::entry::icon::dull_color_alpha; +use theme::grid::entry::special_icons; + // ============== // === Export === // ============== -pub use entry::Entry; -pub use entry::Params; - - - -mod common_part; -mod define_macro; -mod entry; - -use crate::icon::common_part::*; -use crate::prelude::*; - -use ensogl_core::data::color; -use ensogl_core::display; -use ensogl_core::display::shape::compound::path::path; -use ensogl_grid_view as grid_view; -use ensogl_hardcoded_theme::application::searcher::icons as theme; -use ensogl_list_view as list_view; -use std::f32::consts::PI; - - - -// ================= -// === Constants === -// ================= - -/// The width and height of all icon. -pub const SIZE: f32 = 16.0; - -/// This constant exists for development purposes only, and is published for debug scene. -/// Due to a rendering error, shapes appear too big when the camera is zoomed in very closely. -/// (Documented here: https://github.com/enso-org/ide/issues/1698) -/// In the user interface, this is not a big problem, since icon are usually shown at lower zoom -/// levels. But it is a problem during development of icon when it becomes necessary to inspect -/// them closely. In those situations, one can apply `.shrink(0.35)` to shapes to compensate for the -/// bug and make them appear at the correct size while the camera is zoomed in. But that work-around -/// will make them appear too thin on the default zoom level. -/// -/// To make it easy to turn this shrinking on and off before and after working on icon, we define -/// the constant `SHRINK_AMOUNT` and apply `.shrink(SHRINK_AMOUNT.px())` to all icon. In every -/// commit, `SHRINK_AMOUNT` should be set to 0.0 to make icon look best in the user interface. But -/// during work on the icon, it can temporarily be set to 0.35. -pub const SHRINK_AMOUNT: f32 = 0.0; - - - -// ============== -// === Errors === -// ============== - -/// Error occuring when we try parse string being an invalid icon name to icon Id. -#[derive(Clone, Debug, Fail)] -#[fail(display = "Unknown icon '{}'.", name)] -pub struct UnknownIcon { - /// The copied icon name from parsed string. - pub name: String, -} - - - -// =============== -// === AnyIcon === -// =============== - -/// One of the icon generated from the [`define_icons`] macro. Returned from `create_shape` method. -pub struct Any { - /// The underlying icon shape. - pub view: Box, - /// Getter for vivid (darker, or more contrasting) color parameter. - pub vivid_color_fn: Box color::Lcha>, - /// Setter for vivid (darker, or more contrasting) color parameter. - pub set_vivid_color_fn: Box, - /// Getter for dull (lighter, or less contrasting) color parameter. - pub dull_color_fn: Box color::Lcha>, - /// Setter for dull (lighter, or less contrasting) color parameter. - pub set_dull_color_fn: Box, -} - -/// See docs of [`Any`] to learn more. -#[allow(missing_docs)] -impl Any { - pub fn vivid_color(&self) -> color::Lcha { - (self.vivid_color_fn)() - } - - pub fn set_vivid_color(&self, color: color::Lcha) { - (self.set_vivid_color_fn)(color) - } - - pub fn dull_color(&self) -> color::Lcha { - (self.dull_color_fn)() - } - - pub fn set_dull_color(&self, color: color::Lcha) { - (self.set_dull_color_fn)(color) - } -} - -impl Debug for Any { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Any") - } -} - -impl display::Object for Any { - fn display_object(&self) -> &display::object::Instance { - self.view.display_object() - } -} +pub use ide_view_component_list_panel_icons::Any; +pub use ide_view_component_list_panel_icons::SIZE; @@ -121,16 +27,16 @@ impl display::Object for Any { // === Icons === // ============= -crate::define_icons! { - +define_icons! { /// A five-pointed star. pub mod star(Star) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let shape = FiveStar(7.0.px(),0.447); - let shape = shape.fill(style.get_color(theme::favorites)); + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let shape = FiveStar(8.0.px(),0.447); + let shape = shape.fill(vivid_color); shape.shrink(SHRINK_AMOUNT.px()).into() } } @@ -139,11 +45,12 @@ crate::define_icons! { /// Local scope section button. A dot inside a circle. pub mod local_scope(LocalScope) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let dot = Circle(2.0.px()); - let outer = Circle(7.0.px()) - Circle(6.0.px()); + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dot = Circle(3.0.px()); + let outer = Circle(8.0.px()) - Circle(7.0.px()); let shape = dot + outer; let shape = shape.fill(vivid_color); let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -155,16 +62,17 @@ crate::define_icons! { /// Sub-modules section button. Three rectangles placed behind each other with perspective. pub mod sub_modules(SubModules) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let corners_radius = 1.5; - let top = Rect((10.0.px(), 1.5.px())); - let top = top.corners_radius(corners_radius.px()).translate_y(5.25.px()); - let middle = Rect((13.0.px(), 2.0.px())); - let middle = middle.corners_radius(corners_radius.px()).translate_y(2.5.px()); - let bottom = Rect((16.0.px(), 6.5.px())); - let bottom = bottom.corners_radius(corners_radius.px()).translate_y((-2.75).px()); + let top = Rect((8.0.px(), 1.5.px())); + let top = top.corners_radius(corners_radius.px()).translate_y(4.75.px()); + let middle = Rect((12.0.px(), 1.5.px())); + let middle = middle.corners_radius(corners_radius.px()).translate_y(2.25.px()); + let bottom = Rect((16.0.px(), 6.0.px())); + let bottom = bottom.corners_radius(corners_radius.px()).translate_y((-2.5).px()); let shape = top + middle + bottom; let shape = shape.fill(vivid_color); let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -173,34 +81,113 @@ crate::define_icons! { } } + /// Four rounded rectangles in different colors aranged in a grid. + pub mod libraries(Libraries) { + ensogl_core::shape! { + above = [grid_view::selectable::highlight::shape, crate::entry::background]; + pointer_events = false; + (style: Style, color: Vector4) { + use special_icons::libraries as theme; + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(theme::dull_alpha).into(); + let secondary_alpha: Var = style.get_number(theme::secondary_alpha).into(); + let tertiary_alpha: Var = style.get_number(theme::tertiary_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); + let secondary_color = vivid_color.clone().multiply_alpha(&secondary_alpha); + let tertiary_color = vivid_color.clone().multiply_alpha(&tertiary_alpha); + let size = 7.0; + let half = size / 2.0; + let corners_radius = 1.0; + let rect0 = Rect((size.px(),size.px())).corners_radius(corners_radius.px()); + let rect0 = rect0.fill(vivid_color); + let rect0 = rect0.translate(((-half - 0.5).px(),(half + 0.5).px())); + + let rect1 = Rect((size.px(),size.px())).corners_radius(corners_radius.px()); + let rect1 = rect1.fill(secondary_color); + let rect1 = rect1.translate(((-half - 0.5).px(),(-half - 0.5).px())); + + let rect2 = Rect((size.px(),size.px())).corners_radius(corners_radius.px()); + let rect2 = rect2.fill(tertiary_color); + let rect2 = rect2.translate(((half + 0.5).px(),(-half - 0.5).px())); + + let rect3 = Rect((size.px(),size.px())).corners_radius(corners_radius.px()); + let rect3 = rect3.fill(dull_color); + let rect3 = rect3.translate(((half + 0.5).px(),(half + 0.5).px())); + + let shape = rect0 + rect1 + rect2 + rect3; + let shape = shape.shrink(SHRINK_AMOUNT.px()); + shape.into() + } + } + } + + /// A plus and three rounded rectangles in different colors aranged in a grid. + pub mod marketplace(Marketplace) { + ensogl_core::shape! { + above = [grid_view::selectable::highlight::shape, crate::entry::background]; + pointer_events = false; + (style: Style, color: Vector4) { + use special_icons::marketplace as theme; + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(theme::dull_alpha).into(); + let secondary_alpha: Var = style.get_number(theme::secondary_alpha).into(); + let tertiary_alpha: Var = style.get_number(theme::tertiary_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); + let secondary_color = vivid_color.clone().multiply_alpha(&secondary_alpha); + let tertiary_color = vivid_color.clone().multiply_alpha(&tertiary_alpha); + let size = 7.0; + let half = size / 2.0; + let corners_radius = 1.0; + let plus = plus(size,1.5); + let plus = plus.fill(vivid_color); + let plus = plus.translate(((-half - 0.5).px(),(half + 0.5).px())); + + let rect1 = Rect((size.px(),size.px())).corners_radius(corners_radius.px()); + let rect1 = rect1.fill(secondary_color); + let rect1 = rect1.translate(((-half - 0.5).px(),(-half - 0.5).px())); + + let rect2 = Rect((size.px(),size.px())).corners_radius(corners_radius.px()); + let rect2 = rect2.fill(tertiary_color); + let rect2 = rect2.translate(((half + 0.5).px(),(-half - 0.5).px())); + + let rect3 = Rect((size.px(),size.px())).corners_radius(corners_radius.px()); + let rect3 = rect3.fill(dull_color); + let rect3 = rect3.translate(((half + 0.5).px(),(half + 0.5).px())); + + let shape = plus + rect1 + rect2 + rect3; + let shape = shape.shrink(SHRINK_AMOUNT.px()); + shape.into() + } + } + } + /// A rounded rectangle with an arrow pointing in from the left. pub mod data_input(DataInput) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); - // === Border === + // === Rectangle === - let border = - Rect((10.0.px(),13.0.px())).corners_radius(1.5.px()).translate_x(1.5.px()); - // Taking just an outline. - let border = &border - border.shrink(1.0.px()); - // Creating a gap for the arrow to pass through. - let gap = Rect((2.0.px(),4.0.px())).translate_x((-3.0).px()); - let border = border - gap; + let rect = Rect((11.0.px(),12.0.px())).corners_radius(2.0.px()); + let rect = rect.translate_x(2.5.px()); + let rect = rect.fill(dull_color); // === Arrow === - let arrow = - arrow(11.0,1.0,4.0,5.0).rotate((PI/2.0).radians()).translate_x(4.0.px()); + let arrow = arrow(11.0,2.0,4.0,6.0).rotate((PI/2.0).radians()); + let arrow = arrow.translate_x(4.0.px()); + let arrow = arrow.fill(vivid_color); // === Shape === - let shape = border + arrow; - let shape = shape.fill(vivid_color); + let shape = rect + arrow; shape.shrink(SHRINK_AMOUNT.px()).into() } } @@ -209,31 +196,30 @@ crate::define_icons! { /// A rounded rectangle with an arrow pointing out to the right. pub mod data_output(DataOutput) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); - // === Border === + // === Rect === - let border = Rect((9.0.px(),13.0.px())).corners_radius(1.5.px()); - let border = border.translate_x((-2.5).px()); - // Taking just an outline. - let border = &border - border.shrink(1.0.px()); - // Creating a gap for the arrow to pass through. - let gap = Rect((2.0.px(),4.0.px())).translate_x((1.5).px()); - let border = border - gap; + let rect = Rect((10.0.px(),12.0.px())).corners_radius(2.0.px()); + let rect = rect.translate_x((-3.0).px()); + let rect = rect.fill(dull_color); // === Arrow === let arrow = - arrow(11.0,1.0,4.0,5.0).rotate((PI/2.0).radians()).translate_x(8.0.px()); + arrow(11.0,2.0,4.0,6.0).rotate((PI/2.0).radians()).translate_x(8.0.px()); + let arrow = arrow.fill(vivid_color); // === Shape === - let shape = border + arrow; - let shape = shape.fill(vivid_color); + let shape = rect + arrow; shape.shrink(SHRINK_AMOUNT.px()).into() } } @@ -242,40 +228,39 @@ crate::define_icons! { /// A rounded rectangle with the letter "A" and a text cursor. pub mod text_input(TextInput) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); - // === Border === + // === Rect === - let border = Rect((16.0.px(),11.0.px())).corners_radius(1.5.px()); - // Using just the outline. - let border = &border - border.shrink(1.0.px()); - // Creating a gap for the cursor. - let gap = Rect((3.0.px(),13.0.px())).translate_x((3.5).px()); - let border = border - gap; + let rect = Rect((16.0.px(),10.0.px())).corners_radius(2.0.px()); + let rect = rect.fill(dull_color); // === Cursor === - let cursor = cursor().translate_x(3.5.px()); + let cursor = cursor().translate_x(3.0.px()).fill(vivid_color.clone()); // === Letter === // We construct the letter "A", consisting of a diagonal stroke on the left, // a diagonal stroke on the right and a horizontal bar in the middle. - let left_stroke = Segment((0.0.px(),2.5.px()),((-2.5).px(),(-2.5).px()),1.0.px()); - let right_stroke = Segment((0.0.px(),2.5.px()),(2.5.px(),(-2.5).px()),1.0.px()); - let bar = Rect((4.0.px(),1.0.px())).translate_y((-1.0).px()); - let letter = left_stroke + right_stroke + bar; - let letter = letter.translate_x((-2.5).px()); + let left_stroke = Segment((0.0.px(),2.5.px()),((-2.5).px(),(-2.5).px()),1.2.px()); + let right_stroke = Segment((0.0.px(),2.5.px()),(2.5.px(),(-2.5).px()),1.2.px()); + let bar = Rect((4.0.px(),1.2.px())).translate_y((-1.0).px()); + let letter = left_stroke + right_stroke + bar; + let letter = letter.translate_x((-3.0).px()); + let letter = letter.fill(vivid_color); // === Shape === - let shape = border + cursor + letter; - let shape = shape.fill(vivid_color); + let shape = rect + cursor + letter; shape.shrink(SHRINK_AMOUNT.px()).into() } } @@ -284,32 +269,31 @@ crate::define_icons! { /// A rounded rectangle with the number "5" and a text cursor. pub mod number_input(NumberInput) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); - // === Border === + // === Rect === - let border = Rect((16.0.px(),11.0.px())).corners_radius(5.5.px()); - // Using just the outline. - let border = &border - border.shrink(1.0.px()); - // Creating a gap for the cursor. - let gap = Rect((3.0.px(),13.0.px())).translate_x((3.5).px()); - let border = border - gap; + let rect = Rect((16.0.px(),10.0.px())).corners_radius(2.0.px()); + let rect = rect.fill(dull_color); // === Cursor === - let cursor = cursor().translate_x(3.5.px()); + let cursor = cursor().translate_x(3.0.px()).fill(vivid_color.clone()); // === Number 5 === // The number "5" consists of a short horizontal bar at the top, a vertical bar // connected to it on the left and a big arc below, connected to the vertical bar. - let top = Rect((3.0.px(),1.0.px())); - let left = - Rect((1.0.px(),3.0.px())).translate_x((-1.0).px()).translate_y((-1.0).px()); + let top = Rect((3.0.px(),1.0.px())); + let left = Rect((1.0.px(),3.0.px())); + let left = left.translate_x((-1.0).px()).translate_y((-1.0).px()); // == Number 5 Arc == @@ -321,19 +305,19 @@ crate::define_icons! { let connection_offset = arc_connection - arc_center; let stroke_width = 1.0; // The outer radius of the arc. - let radius: f32 = connection_offset.norm() + stroke_width; + let radius: f32 = connection_offset.norm() + stroke_width; let connection_direction = connection_offset.x.atan2(connection_offset.y); let arc = arc(radius,stroke_width,connection_direction,228_f32.to_radians()); let arc = arc.translate((arc_center.x.px(),arc_center.y.px())); - let number = (top + left + arc).translate_x((-2.0).px()).translate_y(2.5.px()); + let number = (top + left + arc).translate_x((-3.0).px()).translate_y(2.5.px()); + let number = number.fill(vivid_color); // === Shape === - let shape = border + cursor + number; - let shape = shape.fill(vivid_color); + let shape = rect + cursor + number; shape.shrink(SHRINK_AMOUNT.px()).into() } } @@ -342,18 +326,22 @@ crate::define_icons! { /// A table with 4x2 cells and a cursor shape in front of it. pub mod table_edit(TableEdit) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); // We need to create the table in two parts, left and right of the cursor to achieve // the right cell arangement. - let left_table = table(2,2).translate(((-8.0).px(),(-4.5).px())); - let right_table = table(2,2).translate(((-1.0).px(),(-4.5).px())); - let gap = Rect((3.0.px(),13.0.px())); - let cursor = cursor(); + let left_table = table(2,2, 4.0).translate(((-8.0).px(), (-4.0).px())); + let right_table = table(2,2, 4.0).translate(((-1.0).px(),(-4.0).px())); + let gap = Rect((4.0.px(),16.0.px())); + let table = left_table + right_table - gap; + let table = table.fill(dull_color); + let cursor = cursor().fill(vivid_color); - let shape = left_table + right_table - gap + cursor; - let shape = shape.fill(vivid_color); + let shape = table + cursor; shape.shrink(SHRINK_AMOUNT.px()).into() } } @@ -362,13 +350,14 @@ crate::define_icons! { /// An arrow to the left on top and an arrow to the right below. pub mod convert(Convert) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let upper_arrow = arrow(10.0,1.0,4.5,6.0).rotate((-PI/2.0).radians()); - let upper_arrow = upper_arrow.translate(((-8.0).px(),1.0.px())); - let lower_arrow = arrow(10.0,1.0,4.5,6.0).rotate((PI/2.0).radians()); - let lower_arrow = lower_arrow.translate((8.0.px(),(-1.5).px())); + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let upper_arrow = arrow(11.0,2.0,4.0,6.0).rotate((-PI/2.0).radians()); + let upper_arrow = upper_arrow.translate(((-8.0).px(),2.0.px())); + let lower_arrow = arrow(11.0,2.0,4.0,6.0).rotate((PI/2.0).radians()); + let lower_arrow = lower_arrow.translate((8.0.px(),(-1.0).px())); let shape = upper_arrow + lower_arrow; let shape = shape.fill(vivid_color); @@ -380,28 +369,32 @@ crate::define_icons! { /// A table with an eraser in front. pub mod dataframe_clean(DataframeClean) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); let table_color = dull_color; - let table = - table(2,3).translate(((-8.0).px(),(-6.5).px())).fill(table_color.clone()); - let bottom_line = - Rect((13.0.px(),1.0.px())).corners_radius(1.0.px()).fill(table_color); - let bottom_line = bottom_line.translate_y((-6.0).px()); + let table = table(2,3, 4.0).translate(((-8.0).px(),(-7.0).px())); + let table = table.fill(table_color); - let eraser = Rect((9.0.px(),5.0.px())).corners_radius(1.0.px()); - let eraser_bg = eraser.grow(1.5.px()); - let eraser_bg = eraser_bg.rotate((-0.25 * std::f32::consts::PI).radians()); - let eraser_bg = eraser_bg.translate((3.5.px(),(-1.5).px())); - let eraser_inner = Rect((7.0.px(),3.0.px())); - let eraser_bar = Rect((1.0.px(),4.0.px())).translate_x((-1.0).px()); - let eraser = eraser - eraser_inner + eraser_bar; - let eraser = eraser.fill(vivid_color); - let eraser = eraser.rotate((-0.25 * std::f32::consts::PI).radians()); - let eraser = eraser.translate((3.5.px(),(-1.5).px())); + let eraser_x = 3.5; + let eraser_y = -2.0; + let eraser_rotation = -0.25 * std::f32::consts::PI; - let shape = table - eraser_bg + eraser + bottom_line; + let eraser = Rect((9.0.px(),5.0.px())); + let eraser = eraser.corners_radius(1.0.px()); + let eraser_bar = Rect((1.0.px(),6.0.px())).translate_x((-2.0).px()); + let eraser = eraser - eraser_bar; + let eraser = eraser.rotate(eraser_rotation.radians()); + let eraser = eraser.translate((eraser_x.px(), eraser_y.px())); + let eraser = eraser.fill(vivid_color); + let eraser_bg = Rect((13.0.px(), 9.0.px())); + let eraser_bg = eraser_bg.rotate(eraser_rotation.radians()); + let eraser_bg = eraser_bg.translate((eraser_x.px(), eraser_y.px())); + + let shape = table - eraser_bg + eraser; let shape = shape.shrink(SHRINK_AMOUNT.px()); shape.into() } @@ -411,16 +404,20 @@ crate::define_icons! { /// A light column on the left, a dark column in the middle and a plus on the right. pub mod add_column(AddColumn) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); let old_color = dull_color; let new_color = vivid_color; - let old_column = table(1,3).translate(((-8.0).px(),(-6.5).px())).fill(old_color); - let new_column = - table(1,3).translate(((-4.0).px(),(-6.5).px())).fill(new_color.clone()); - let plus = plus(5.0,1.0).fill(new_color).translate_x(5.0.px()); + let old_column = table(1,3, 4.0).translate(((-8.0).px(),(-7.0).px())); + let old_column = old_column.fill(old_color); + let new_column = table(1,3, 4.0).translate(((-3.0).px(),(-7.0).px())); + let new_column = new_column.fill(new_color.clone()); + let plus = plus(6.0,2.0).fill(new_color).translate_x(5.0.px()); let shape = old_column + new_column + plus; let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -432,16 +429,19 @@ crate::define_icons! { /// A light row at the top, a dark row in the middle and a plus at the bottom. pub mod add_row(AddRow) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); let old_color = dull_color; let new_color = vivid_color; - let old_row = table(3,1).translate(((-6.5).px(),3.0.px())).fill(old_color); + let old_row = table(3,1, 4.0).translate(((-7.0).px(),4.0.px())).fill(old_color); let new_row = - table(3,1).translate(((-6.5).px(),(-1.0).px())).fill(new_color.clone()); - let plus = plus(5.0,1.0).fill(new_color).translate_y((-5.0).px()); + table(3,1, 4.0).translate(((-7.0).px(),(-1.0).px())).fill(new_color.clone()); + let plus = plus(6.0,2.0).fill(new_color).translate_y((-5.0).px()); let shape = old_row + new_row + plus; let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -453,13 +453,16 @@ crate::define_icons! { /// Two light columns on the left and one dark column detached on the right. pub mod select_column(SelectColumn) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let unselected = table(2,3).translate(((-8.0).px(),(-6.5).px())); + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); + let unselected = table(2,3, 4.0).translate(((-8.0).px(),(-7.0).px())); let unselected = unselected.fill(dull_color); - let selected = table(1,3).translate((3.0.px(),(-6.5).px())); - let selected = selected.fill(vivid_color); + let selected = table(1,3, 4.0).translate((4.0.px(),(-7.0).px())); + let selected = selected.fill(vivid_color); let shape = unselected + selected; let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -471,13 +474,16 @@ crate::define_icons! { /// Two light rows at the top and one dark row detached at the bottom. pub mod select_row(SelectRow) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let unselected = table(3,2).translate(((-6.5).px(),(-1.0).px())); + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); + let unselected = table(3,2, 4.0).translate(((-7.0).px(),(-1.0).px())); let unselected = unselected.fill(dull_color); - let selected = table(3,1).translate(((-6.5).px(),(-8.0).px())); - let selected = selected.fill(vivid_color); + let selected = table(3,1, 4.0).translate(((-7.0).px(),(-8.0).px())); + let selected = selected.fill(vivid_color); let shape = unselected + selected; let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -489,18 +495,22 @@ crate::define_icons! { /// A light column, a dark column and a lightning bolt on the right. pub mod dataframe_map_column(DataframeMapColumn) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let dull_color = dull_color; + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); + let dull_color = dull_color; let vivid_color = vivid_color; - let dull_column = table(1,3).translate(((-8.0).px(),(-6.5).px())).fill(dull_color); - let vivid_column = - table(1,3).translate(((-4.0).px(),(-6.5).px())).fill(vivid_color.clone()); + let weak_column = table(1,3, 4.0).translate(((-8.0).px(),(-7.0).px())); + let weak_column = weak_column.fill(dull_color); + let strong_column = table(1,3, 4.0).translate(((-3.0).px(),(-7.0).px())); + let strong_column = strong_column.fill(vivid_color.clone()); let lightning = lightning_bolt().translate_x(5.25.px()).fill(vivid_color); - let shape = dull_column + vivid_column + lightning; + let shape = weak_column + strong_column + lightning; let shape = shape.shrink(SHRINK_AMOUNT.px()); shape.into() } @@ -510,19 +520,22 @@ crate::define_icons! { /// A light row, a dark row and a lightning bolt below. pub mod dataframe_map_row(DataframeMapRow) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let dull_color = dull_color; + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); + let dull_color = dull_color; let vivid_color = vivid_color; - let dull_row = table(3,1).translate(((-6.5).px(),3.0.px())).fill(dull_color); - let vivid_row = - table(3,1).translate(((-6.5).px(),(-1.0).px())).fill(vivid_color.clone()); - let lightning = lightning_bolt().rotate((PI/2.0).radians()); - let lightning = lightning.translate_y((-5.25).px()).fill(vivid_color); + let weak_row = table(3,1, 4.0).translate(((-7.0).px(),4.0.px())).fill(dull_color); + let strong_row = + table(3,1, 4.0).translate(((-7.0).px(),(-1.0).px())).fill(vivid_color.clone()); + let lightning = lightning_bolt().rotate((PI/2.0).radians()); + let lightning = lightning.translate_y((-5.25).px()).fill(vivid_color); - let shape = dull_row + vivid_row + lightning; + let shape = weak_row + strong_row + lightning; let shape = shape.shrink(SHRINK_AMOUNT.px()); shape.into() } @@ -532,16 +545,20 @@ crate::define_icons! { /// Two columns with a plus in-between. pub mod dataframes_join(DataframesJoin) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let column_color = dull_color; - let plus_color = vivid_color; + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.multiply_alpha(&dull_alpha); + let column_color = dull_color.clone(); + let plus_color = dull_color; - let left_column = - table(1,3).translate(((-8.0).px(),(-6.5).px())).fill(column_color.clone()); - let right_column = table(1,3).translate((3.0.px(),(-6.5).px())).fill(column_color); - let plus = plus(5.0,1.0).fill(plus_color); + let left_column = table(1,3, 3.0).translate(((-8.0).px(),(-5.5).px())); + let left_column = left_column.fill(column_color.clone()); + let right_column = table(1,3, 3.0).translate((5.0.px(),(-5.5).px())); + let right_column = right_column.fill(column_color); + let plus = plus(6.0,1.0).fill(plus_color); let shape = left_column + right_column + plus; let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -553,15 +570,20 @@ crate::define_icons! { /// Two rows with a plus in-between. pub mod dataframes_union(DataframesUnion) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let row_color = dull_color; - let plus_color = vivid_color; + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.multiply_alpha(&dull_alpha); + let row_color = dull_color.clone(); + let plus_color = dull_color; - let top_row = table(3,1).translate(((-6.5).px(),3.0.px())).fill(row_color.clone()); - let bottom_row = table(3,1).translate(((-6.5).px(),(-8.0).px())).fill(row_color); - let plus = plus(5.0,1.0).fill(plus_color); + let top_row = table(3,1, 3.0).translate(((-5.5).px(),5.0.px())); + let top_row = top_row.fill(row_color.clone()); + let bottom_row = table(3,1, 3.0).translate(((-5.5).px(),(-8.0).px())); + let bottom_row = bottom_row.fill(row_color); + let plus = plus(6.0,1.0).fill(plus_color); let shape = top_row + bottom_row + plus; let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -573,9 +595,10 @@ crate::define_icons! { /// A capital "Σ". pub mod sigma(Sigma) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let shape = path(2.0,&[ ( 4.0 , 4.0), ( 4.0 , 5.5), @@ -596,15 +619,18 @@ crate::define_icons! { /// middle. Both pieces contain two thin rectangles as a simple representation of lines of text. pub mod split_text(SplitText) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); // === Page border === let page = Rect((16.0.px(),14.0.px())).corners_radius(2.0.px()); let page = &page - page.shrink(1.0.px()); - let gap = Rect((3.0.px(),15.0.px())).translate_x(0.5.px()); + let gap = Rect((3.0.px(),15.0.px())).translate_x(0.5.px()); let page = page - gap; @@ -614,8 +640,8 @@ crate::define_icons! { let line2 = Rect((2.0.px(),1.0.px())).translate(((-5.0).px(),(-3.0).px())); let line3 = Rect((2.0.px(),1.0.px())).translate_x(5.0.px()); let line4 = Rect((3.0.px(),1.0.px())).translate((4.5.px(),(-3.0).px())); - let page = page + line1 + line2 + line3 + line4; - let page = page.fill(dull_color); + let page = page + line1 + line2 + line3 + line4; + let page = page.fill(dull_color); // === Crack === @@ -645,9 +671,12 @@ crate::define_icons! { /// Some rectangles and circles in different colors. pub mod data_science(DataScience) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); let circle = Circle(2.0.px()); let circle1 = circle.translate_y(5.5.px()).fill(dull_color.clone()); let circle2 = circle.translate(((-5.5).px(),(-3.0).px())).fill(dull_color.clone()); @@ -668,17 +697,19 @@ crate::define_icons! { /// A WiFi symbol, consisting of a small circle and three arcs of increasing size above it. pub mod network(Network) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let circle = Circle(1.0.px()) - .fill(vivid_color.clone()); - let arc1 = RoundedArc((10.5/3.0*1.0).px(),(PI/2.0).radians(),1.5.px()) - .fill(vivid_color.clone()); - let arc2 = RoundedArc((10.5/3.0*2.0).px(),(PI/2.0).radians(),1.5.px()) - .fill(vivid_color); - let arc3 = RoundedArc((10.5/3.0*3.0).px(),(PI/2.0).radians(),1.5.px()) - .fill(dull_color); + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); + let circle = Circle(1.0.px()).fill(vivid_color.clone()); + let arc1 = RoundedArc((10.5/3.0*1.0).px(),(PI/2.0).radians(),1.5.px()); + let arc1= arc1.fill(vivid_color.clone()); + let arc2 = RoundedArc((10.5/3.0*2.0).px(),(PI/2.0).radians(),1.5.px()); + let arc2 = arc2.fill(vivid_color); + let arc3 = RoundedArc((10.5/3.0*3.0).px(),(PI/2.0).radians(),1.5.px()); + let arc3 = arc3.fill(dull_color); let shape = circle + arc1 + arc2 + arc3; let shape = shape.translate_y((-5.5).px()); @@ -691,20 +722,21 @@ crate::define_icons! { /// A dark rectangle containing the simple terminal prompt ">_". pub mod system(System) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + use special_icons::system as theme; let background = Rect((14.0.px(),14.0.px())).corners_radius(2.0.px()); let background = background.translate_y((-0.5).px()); - let background = background.fill(style.get_color(theme::system::background)); - let greater = path(1.5,&[ + let background = background.fill(style.get_color(theme::background)); + let greater = path(1.5,&[ (-3.75 , 2.25), (-1.25 , -0.25), (-3.75 , -2.25), ]); let bar = Rect((4.0.px(),1.5.px())).translate((2.5.px(),(-2.75).px())); let content = greater + bar; - let content = content.fill(style.get_color(theme::system::content)); + let content = content.fill(style.get_color(theme::content)); let shape = background + content; let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -713,71 +745,16 @@ crate::define_icons! { } } - /// Four rounded rectangles in different colors aranged in a grid. - pub mod libraries(Libraries) { - ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; - pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let rect0 = Rect((6.5.px(),6.5.px())).corners_radius(1.0.px()); - let rect0 = rect0.fill(style.get_color(theme::libraries::_0)); - let rect0 = rect0.translate(((-3.75).px(),3.75.px())); - - let rect1 = Rect((6.5.px(),6.5.px())).corners_radius(1.0.px()); - let rect1 = rect1.fill(style.get_color(theme::libraries::_1)); - let rect1 = rect1.translate(((-3.75).px(),(-3.75).px())); - - let rect2 = Rect((6.5.px(),6.5.px())).corners_radius(1.0.px()); - let rect2 = rect2.fill(style.get_color(theme::libraries::_2)); - let rect2 = rect2.translate((3.75.px(),(-3.75).px())); - - let rect3 = Rect((6.5.px(),6.5.px())).corners_radius(1.0.px()); - let rect3 = rect3.fill(style.get_color(theme::libraries::_3)); - let rect3 = rect3.translate((3.75.px(),3.75.px())); - - let shape = rect0 + rect1 + rect2 + rect3; - let shape = shape.shrink(SHRINK_AMOUNT.px()); - shape.into() - } - } - } - - /// A plus and three rounded rectangles in different colors aranged in a grid. - pub mod marketplace(Marketplace) { - ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; - pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let plus = plus(6.5,1.5); - let plus = plus.fill(style.get_color(theme::libraries::_0)); - let plus = plus.translate(((-3.75).px(),3.75.px())); - - let rect1 = Rect((6.5.px(),6.5.px())).corners_radius(1.0.px()); - let rect1 = rect1.fill(style.get_color(theme::libraries::_1)); - let rect1 = rect1.translate(((-3.75).px(),(-3.75).px())); - - let rect2 = Rect((6.5.px(),6.5.px())).corners_radius(1.0.px()); - let rect2 = rect2.fill(style.get_color(theme::libraries::_2)); - let rect2 = rect2.translate((3.75.px(),(-3.75).px())); - - let rect3 = Rect((6.5.px(),6.5.px())).corners_radius(1.0.px()); - let rect3 = rect3.fill(style.get_color(theme::libraries::_3)); - let rect3 = rect3.translate((3.75.px(),3.75.px())); - - let shape = plus + rect1 + rect2 + rect3; - let shape = shape.shrink(SHRINK_AMOUNT.px()); - shape.into() - } - } - } - /// Two half arrow, one on top and pointing to the right, one at the bottom and pointing to the /// left. The shape has an outline in a darker color. pub mod io(IO) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); let half_arrow = arrow(14.0,5.0,7.0,11.0).rotate((PI/2.0).radians()) - HalfPlane(); let upper = half_arrow.translate((7.0.px(),0.5.px())); let lower = half_arrow.rotate(PI.radians()).translate(((-7.0).px(),(-1.0).px())); @@ -798,9 +775,12 @@ crate::define_icons! { /// outline. pub mod preparation(Preparation) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); // === Outline === @@ -841,21 +821,29 @@ crate::define_icons! { /// different colors. pub mod join(Join) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let left_circle = Circle(5.0.px()).translate_x((-3.0).px()); - let right_circle = Circle(5.0.px()).translate_x(3.0.px()); + (style: Style, color: Vector4) { + use special_icons::join as theme; + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let intersection_alpha: Var = style.get_number(theme::intersection_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); + let intersection_color = vivid_color.clone().multiply_alpha(&intersection_alpha); + let left_circle = Circle(4.5.px()).translate_x((-2.5).px()); + let right_circle = Circle(4.5.px()).translate_x(2.5.px()); let intersection = &left_circle * &right_circle; let left_outline = left_circle.grow(1.0.px()) - &left_circle; + let left_outline = left_outline.fill(vivid_color.clone()); let right_outline = right_circle.grow(1.0.px()) - &right_circle; + let right_outline = right_outline.fill(vivid_color); let left_circle = left_circle.fill(dull_color.clone()); let right_circle = right_circle.fill(dull_color); - let intersection = intersection.fill(vivid_color.clone()); + let intersection = intersection.fill(intersection_color); let shape = - left_circle + right_circle + intersection - left_outline - right_outline; + left_circle + right_circle + intersection + left_outline + right_outline; let shape = shape.shrink(SHRINK_AMOUNT.px()); shape.into() } @@ -866,9 +854,10 @@ crate::define_icons! { /// to the right. pub mod text(Text) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let page = Rect((10.0.px(),14.0.px())).corners_radius(2.0.px()); let page = page.translate_x((-2.0).px()); let page = &page - page.shrink(1.0.px()); @@ -891,13 +880,14 @@ crate::define_icons! { /// A clock shape. pub mod date_and_time(DateAndTime) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let circle = Circle(7.75.px()); let circle = &circle - circle.shrink(1.0.px()); - let big_hand = Segment((0.0.px(),0.0.px()),(3.0.px(),(-2.0).px()),1.5.px()); + let big_hand = Segment((0.0.px(),0.0.px()),(3.0.px(),(-2.0).px()),1.5.px()); let small_hand = Segment((0.0.px(),0.0.px()),(0.0.px(),2.5.px()),1.5.px()); let shape = circle + big_hand + small_hand; @@ -913,20 +903,21 @@ crate::define_icons! { /// down. Around the tip there is an ellipse outline. pub mod spatial(Spatial) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let circle = Circle(4.5.px()).translate_y(3.5.px()); - let circle = &circle - circle.shrink(2.0.px()); + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); + let circle = Circle(4.5.px()).translate_y(3.5.px()); + let circle = &circle - circle.shrink(2.0.px()); let triangle = Triangle(7.0,5.75).rotate(PI.radians()).translate_y((-2.125).px()); - let marker = circle + ▵ + let marker = circle + ▵ - let ellipse = Ellipse(6.5.px(),2.5.px()).translate_y((-5.0).px()); - let ellipse = &ellipse - ellipse.shrink(1.0.px()); + let ellipse = Ellipse(6.5.px(),2.5.px()).translate_y((-5.0).px()); + let ellipse = &ellipse - ellipse.shrink(1.0.px()); // If we used just the triangle for the gap then it would also cut into the lower // part of the ellipse. let ellipse_gap = triangle.grow(1.5.px()) - HalfPlane().translate_y((-5.0).px()); - let ellipse = ellipse - ellipse_gap; + let ellipse = ellipse - ellipse_gap; let shape = marker + ellipse; let shape = shape.fill(vivid_color); @@ -939,16 +930,17 @@ crate::define_icons! { /// The shape of a christal ball with a bas below. pub mod predictive(Predictive) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let circle = Circle(5.5.px()); let sphere = &circle - circle.shrink(1.0.px()); let reflection1 = arc(3.5,1.0,-114.0_f32.to_radians(),-95.0_f32.to_radians()); let reflection2 = arc(3.5,1.0,276.0_f32.to_radians(),13.0_f32.to_radians()); - let sphere = sphere + reflection1 + reflection2; - let sphere = sphere.translate_y(1.5.px()); + let sphere = sphere + reflection1 + reflection2; + let sphere = sphere.translate_y(1.5.px()); let base = Triangle(21.0,8.0).translate_y((-4.0).px()); let base = base * Rect((13.0.px(),5.0.px())).translate_y((-5.0).px()); @@ -965,9 +957,10 @@ crate::define_icons! { /// The shape of an android. pub mod machine_learning(MachineLearning) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let body = Rect((10.0.px(),15.0.px())) .corners_radiuses(5.0.px(),5.0.px(),2.0.px(),2.0.px()) .translate_y((-0.5).px()); @@ -993,16 +986,20 @@ crate::define_icons! { /// outline, representing the lens and a base above that the camera is mounted on. pub mod computer_vision(ComputerVision) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; + above = [grid_view::selectable::highlight::shape, crate::entry::background]; pointer_events = false; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { - let lens = - Circle(2.0.px()).fill(style.get_color(theme::computer_vision::highlight)); + (style: Style, color: Vector4) { + use special_icons::computer_vision as theme; + let vivid_color: Var = color.into(); + let dull_alpha: Var = style.get_number(dull_color_alpha).into(); + let dull_color = vivid_color.clone().multiply_alpha(&dull_alpha); + let lens = Circle(2.0.px()).fill(style.get_color(theme::highlight)); let outline = Circle(4.5.px()) - Circle(3.5.px()); let outline = outline.fill(vivid_color); - let base = - Circle(7.0.px()).translate_y(6.0.px()) * HalfPlane().translate_y(7.0.px()); + let base = Circle(7.0.px()); + let base = base.translate_y(6.0.px()) * HalfPlane(); + let base = base.translate_y(7.0.px()); let base = base + Rect((14.0.px(),2.0.px())).translate_y(7.0.px()); let base = base - Circle(5.5.px()); let base = base.fill(dull_color); @@ -1020,8 +1017,9 @@ crate::define_icons! { /// replaced by a carefully designed icon in the future. pub mod r#type(Type) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + above = [grid_view::selectable::highlight::shape, crate::entry::background]; + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let circle = Circle(5.5.px()) - Circle(4.0.px()); let shape = circle.fill(vivid_color); let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -1035,8 +1033,9 @@ crate::define_icons! { /// replaced by a carefully designed icon in the future. pub mod constructor(Constructor) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + above = [grid_view::selectable::highlight::shape, crate::entry::background]; + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let circle = Circle(5.5.px()) - Circle(4.0.px()); let shape = circle.fill(vivid_color); let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -1050,8 +1049,9 @@ crate::define_icons! { /// replaced by a carefully designed icon in the future. pub mod function(Function) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + above = [grid_view::selectable::highlight::shape, crate::entry::background]; + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let triangle = Triangle(12.0, 12.0).rotate((PI/2.0).radians()); let shape = triangle.fill(vivid_color); let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -1065,8 +1065,9 @@ crate::define_icons! { /// replaced by a carefully designed icon in the future. pub mod local(Local) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + above = [grid_view::selectable::highlight::shape, crate::entry::background]; + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let dot = Circle(4.0.px()); let shape = dot.fill(vivid_color); let shape = shape.shrink(SHRINK_AMOUNT.px()); @@ -1080,8 +1081,9 @@ crate::define_icons! { /// replaced by a carefully designed icon in the future. pub mod method(Method) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + above = [grid_view::selectable::highlight::shape, crate::entry::background]; + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let rhomb = path(1.5, &[ (6.0, 0.0), (0.0, -6.0), @@ -1101,8 +1103,9 @@ crate::define_icons! { /// replaced by a carefully designed icon in the future. pub mod module(Module) { ensogl_core::shape! { - above = [grid_view::selectable::highlight::shape, list_view::selection, crate::entry::background]; - (style: Style, vivid_color: Vector4, dull_color: Vector4) { + above = [grid_view::selectable::highlight::shape, crate::entry::background]; + (style: Style, color: Vector4) { + let vivid_color: Var = color.into(); let rect = Rect((14.0.px(), 14.0.px())).corners_radius(3.0.px()); let rect = &rect - rect.shrink(1.5.px()); let shape = rect.fill(vivid_color); @@ -1115,6 +1118,6 @@ crate::define_icons! { impl Default for Id { fn default() -> Self { - Self::Star + Self::DataScience } } diff --git a/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon/entry.rs b/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon/entry.rs deleted file mode 100644 index 5cca9c97821..00000000000 --- a/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon/entry.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! A module containing the list view entry type which represents an arbitrary icon. - -use ensogl_core::prelude::*; - -use crate::icon; - -use enso_frp as frp; -use ensogl_core::application::Application; -use ensogl_core::data::color; -use ensogl_core::display; -use ensogl_core::display::scene::Layer; -use ensogl_core::display::style::Path; -use ensogl_list_view as list_view; - - - -// ================= -// === IconEntry === -// ================= - -/// List view entry type which represents a single icon. We use list view with icons instead of -/// three separate buttons to simplify the implementation. -#[derive(Debug, Clone, CloneRef)] -pub struct Entry { - display_object: display::object::Instance, - icon: Rc>>, - icon_id: Rc>>, - params: Params, -} - -impl display::Object for Entry { - fn display_object(&self) -> &display::object::Instance { - &self.display_object - } -} - -impl list_view::Entry for Entry { - type Model = icon::Id; - type Params = Params; - - fn new(_app: &Application, _style_prefix: &Path, params: &Self::Params) -> Self { - let display_object = display::object::Instance::new(); - let icon: Rc>> = default(); - let icon_id = default(); - let network = frp::Network::new("searcher_list_panel::navigator::Icon"); - frp::extend! { network - eval params.vivid_color((&c) - icon.borrow().as_ref().map(|icon| icon.set_vivid_color(c.into())) - ); - eval params.dull_color((&c) - icon.borrow().as_ref().map(|icon| icon.set_dull_color(c.into())) - ); - } - - Self { display_object, icon, icon_id, params: params.clone_ref() } - } - - fn update(&self, model: &Self::Model) { - if !self.icon_id.get().contains(model) { - let size = Vector2(icon::SIZE, icon::SIZE); - let icon = model.create_shape(size); - icon.set_vivid_color(self.params.vivid_color.value().into()); - icon.set_dull_color(self.params.dull_color.value().into()); - self.display_object.add_child(&icon); - *self.icon.borrow_mut() = Some(icon); - self.icon_id.set(Some(*model)); - } - } - - fn set_max_width(&self, _max_width_px: f32) {} - - fn set_label_layer(&self, _label_layer: &Layer) {} -} - -// === IconParams === - -/// Entry parameters of the icon. -#[derive(Clone, CloneRef, Debug)] -pub struct Params { - /// Strong (darker, or more contrasting) color parameter. - pub vivid_color: frp::Sampler, - /// Weak (lighter, or less contrasting) color parameter. - pub dull_color: frp::Sampler, -} - -impl Default for Params { - fn default() -> Self { - let network = frp::Network::new("searcher_list_panel::navigator::Params::default"); - frp::extend! { network - default_color <- source::().sampler(); - } - Self { vivid_color: default_color.clone_ref(), dull_color: default_color.clone_ref() } - } -} diff --git a/app/gui/view/component-browser/component-list-panel/grid/src/entry/style.rs b/app/gui/view/component-browser/component-list-panel/grid/src/entry/style.rs index b108f25c933..01e18aeaf31 100644 --- a/app/gui/view/component-browser/component-list-panel/grid/src/entry/style.rs +++ b/app/gui/view/component-browser/component-list-panel/grid/src/entry/style.rs @@ -5,65 +5,141 @@ use crate::prelude::*; use enso_frp as frp; use ensogl_core::data::color; use ensogl_core::display::shape::StyleWatchFrp; -use ensogl_core::Animation; +use ensogl_core::display::style::data::DataMatch; use ensogl_derive_theme::FromTheme; +use ensogl_hardcoded_theme::application::component_browser::component_list_panel as panel_theme; use ensogl_hardcoded_theme::application::component_browser::component_list_panel::grid as grid_theme; use entry_theme::highlight::selection as selection_theme; use grid_theme::entry as entry_theme; +// ============= +// === Color === +// ============= + +/// Color of the different parts of the entry. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Color { + /// The final color is "main" color of the component group with the specified alpha value. + #[allow(missing_docs)] + ComponentGroup { alpha_multiplier: f32 }, + /// The final color is defined as an arbitrary color in the stylesheet. + Arbitrary(color::Lcha), +} + +impl Default for Color { + fn default() -> Self { + Self::Arbitrary(color::Lcha::black()) + } +} + +impl Color { + /// Get the final color by either taking the value from [`Self::Arbitrary`] or by applying the + /// specified transparency from [`Self::MainColorWithAlpha`] to [`main`] color. + fn resolve(&self, main: &color::Lcha) -> color::Lcha { + match self { + Self::ComponentGroup { alpha_multiplier } => main.multiply_alpha(*alpha_multiplier), + Self::Arbitrary(color) => *color, + } + } + + /// A custom accessor for retrieving the color from the stylesheet using the [`FromTheme`] + /// macro. In the stylesheet, the color can be defined as either a `color::Rgba` or a `float` + /// value for the mixing coefficient. This accessor produces the corresponding variants of + /// [`Color`] or returns a default value ([`Color::MainColorWithAlpha(0.0)`]) if there is no + /// such property in the stylesheet. + fn accessor>( + network: &frp::Network, + style: &StyleWatchFrp, + path: P, + ) -> frp::Sampler { + let path = path.into(); + let value = style.get(path.clone()); + frp::extend! { network + init <- source_(); + color <- value.all_with(&init, move |data, _| { + data.color().map(|color| { + let color = color::Lcha::from(color); + Color::Arbitrary(color) + }).unwrap_or_else(|| { + let alpha_multiplier = match data.number() { + Some(number) => number, + None => { + error!("Neither color nor alpha defined for {path}."); + 0.0 + } + }; + Color::ComponentGroup { alpha_multiplier } + }) + }); + sampler <- color.sampler(); + } + init.emit(()); + sampler + } +} + + + // ============= // === Style === // ============= -// === Color Intensities === +// === Colors === -/// The intensities of various parts of Component Entry view. The actual color is computed by mixing -/// the main groups color with the application background - see [`Colors`] for more information. +/// The colors of various parts of the Component Entry view. The actual color can be computed by +/// modifying the transparency of the "main" color of the component group - see [`Color`] for more +/// information. #[allow(missing_docs)] #[derive(Clone, Copy, Debug, Default, PartialEq, FromTheme)] -pub struct ColorIntensities { - #[theme_path = "entry_theme::text::color_intensity"] - pub text: f32, - #[theme_path = "entry_theme::background::color_intensity"] - pub background: f32, - #[theme_path = "entry_theme::highlight::hover::color_intensity"] - pub hover_highlight: f32, - #[theme_path = "entry_theme::dimmed::color_intensity"] - pub dimmed: f32, - /// The more contrasting parts of the [icon](crate::icon::Any). - #[theme_path = "entry_theme::icon::strong_color_intensity"] - pub icon_strong: f32, - /// The less contrasting parts of the [icon](crate::icon::Any). - #[theme_path = "entry_theme::icon::weak_color_intensity"] - pub icon_weak: f32, +pub struct Colors { + #[theme_path = "entry_theme::text::color"] + #[accessor = "Color::accessor"] + pub text: Color, + #[theme_path = "entry_theme::background::intensity"] + pub background_intensity: f32, + #[theme_path = "entry_theme::highlight::hover::color"] + #[accessor = "Color::accessor"] + pub hover_highlight: Color, + #[theme_path = "entry_theme::icon::color"] + #[accessor = "Color::accessor"] + pub icon: Color, + /// The "main color" of dimmed component groups. For dimmed component groups, + /// [`ResolvedColors`] would use this value instead of "main" color of the component group. + #[theme_path = "entry_theme::dimmed"] + #[accessor = "Color::accessor"] + pub dimmed: Color, } -/// The intensities of various parts of selected Component Entry view. A subset of -/// [`ColorIntensities`], but `FromTheme` derive takes different style's paths, plus unrelated +/// The colors of various parts of selected the Component Entry view. A subset of +/// [`StyleColors`], but `FromTheme` derive takes different style's paths, plus unrelated /// entries are omitted. #[allow(missing_docs)] #[derive(Clone, Copy, Debug, Default, PartialEq, FromTheme)] -pub struct SelectionColorIntensities { - #[theme_path = "selection_theme::text::color_intensity"] - pub text: f32, - #[theme_path = "selection_theme::background::color_intensity"] - pub background: f32, - /// The more contrasting parts of the [icon](crate::icon::Any). - #[theme_path = "selection_theme::icon_strong::color_intensity"] - pub icon_strong: f32, - /// The less contrasting parts of the [icon](crate::icon::Any). - #[theme_path = "selection_theme::icon_weak::color_intensity"] - pub icon_weak: f32, +pub struct SelectionColors { + #[theme_path = "selection_theme::text::color"] + #[accessor = "Color::accessor"] + pub text: Color, + #[theme_path = "selection_theme::background::intensity"] + pub background_intensity: f32, + #[theme_path = "selection_theme::icon::color"] + #[accessor = "Color::accessor"] + pub icon: Color, + /// The main color of dimmed component groups. Selection is never displayed in a dimmed + /// component group. Still, we need to duplicate this parameter to avoid sudden color + /// changes while the selection shape is animated and moves through different component + /// groups. + #[theme_path = "entry_theme::dimmed"] + #[accessor = "Color::accessor"] + pub dimmed: Color, } -impl From for ColorIntensities { - fn from(selection: SelectionColorIntensities) -> Self { - let SelectionColorIntensities { text, background, icon_strong, icon_weak } = selection; - let dimmed = 1.0; - let hover_highlight = background; - Self { text, background, icon_weak, icon_strong, dimmed, hover_highlight } +impl From for Colors { + fn from(selection: SelectionColors) -> Self { + let SelectionColors { text, background_intensity, icon, dimmed } = selection; + let hover_highlight = default(); + Self { text, background_intensity, icon, dimmed, hover_highlight } } } @@ -82,6 +158,12 @@ pub struct Style { pub icon_size: f32, #[theme_path = "entry_theme::text::size"] pub text_size: f32, + #[theme_path = "entry_theme::text::y_offset"] + pub text_y_offset: f32, + #[theme_path = "entry_theme::text::y_offset_header"] + pub text_y_offset_header: f32, + #[theme_path = "entry_theme::text::x_offset_header"] + pub text_x_offset_header: f32, /// The distance between right edge of the icon and left edge of the caption. #[theme_path = "entry_theme::icon::text_padding"] pub icon_text_padding: f32, @@ -97,75 +179,73 @@ pub struct Style { -// ============== -// === Colors === -// ============== +// ====================== +// === ResolvedColors === +// ====================== /// Colors used in the Component Group Entries. /// -/// This structure can be created from single "main color" input. Each of these colors will be -/// computed by mixing "main color" with application background. -/// -/// `icon_strong` and `icon_weak` parameters represent the more/less contrasting parts of the -/// [icon](crate::icon::Any), they do not represent highlighted state of the icon. +/// This structure can be created from a single "main color" input. Each of these colors can be +/// computed by modifying the transparency of the "main color". See [`Color`] for more information. #[allow(missing_docs)] #[derive(Clone, CloneRef, Debug)] -pub struct Colors { +pub struct ResolvedColors { pub background: frp::Sampler, pub hover_highlight: frp::Sampler, pub text: frp::Sampler, - pub icon_strong: frp::Sampler, - pub icon_weak: frp::Sampler, + pub icon: frp::Sampler, pub skip_animations: frp::Any, } -impl Colors { +impl ResolvedColors { /// Create color outputs from given main color and style. /// - /// Each of these colors will be computed by mixing "main color" with application background - /// according to the proper field in [`Style::color_intensities`]. The dimming of group is - /// animated. + /// Each of these colors can be computed by modifying the transparency of the "main color". See + /// [`Color`] for more information. All color changes are animated. pub fn from_main_color( network: &frp::Network, style_watch: &StyleWatchFrp, - color: &frp::Stream, - color_intensities: &frp::Stream, + main_color: &frp::Stream, + colors: &frp::Stream, is_dimmed: &frp::Stream, ) -> Self { - fn mix((c1, c2): &(color::Lcha, color::Lcha), coefficient: &f32) -> color::Lcha { - color::mix(*c1, *c2, *coefficient) - } - let app_bg = style_watch.get_color(ensogl_hardcoded_theme::application::background); - let color_intensities = color_intensities.clone_ref(); + let panel_background = style_watch.get_color(panel_theme::background_color); + let colors = colors.clone_ref(); + let color_anim = color::Animation::new(network); - let intensity = Animation::new(network); frp::extend! { network init <- source_(); - text_intensity <- color_intensities.map(|c| c.text); - bg_intensity <- color_intensities.map(|c| c.background); - hover_hg_intensity <- color_intensities.map(|c| c.hover_highlight); - dimmed_intensity <- color_intensities.map(|c| c.dimmed); - icon_strong_intensity <- color_intensities.map(|c| c.icon_strong); - icon_weak_intensity <- color_intensities.map(|c| c.icon_weak); - - one <- init.constant(1.0); let is_dimmed = is_dimmed.clone_ref(); - intensity.target <+ is_dimmed.switch(&one, &dimmed_intensity); - app_bg <- all_with(&app_bg, &init, |col, ()| color::Lcha::from(col)); - app_bg_and_input <- all(&app_bg, color); - main <- app_bg_and_input.all_with(&intensity.value, mix); - app_bg_and_main <- all(&app_bg, &main); - background <- app_bg_and_main.all_with(&bg_intensity, mix).sampler(); - hover_highlight <- app_bg_and_main.all_with(&hover_hg_intensity, mix).sampler(); - text <- app_bg_and_main.all_with(&text_intensity, mix).sampler(); - icon_weak <- app_bg_and_main.all_with(&icon_weak_intensity, mix).sampler(); - icon_strong <- app_bg_and_main.all_with(&icon_strong_intensity, mix).sampler(); + dimmed <- all_with3(&init, main_color, &colors, + |_, main, colors| colors.dimmed.resolve(main) + ); + color_anim.target <+ switch(&is_dimmed, main_color, &dimmed); + + // We do not support the semi-transparent background of entries. Because headers share + // the same background color; therefore, the semi-transparent header's background + // reveals the underlying entries. Instead, we mix the color of the component browser's + // background and the main color of the component group. + panel_bg <- all_with(&panel_background, &init, |col, ()| color::Lcha::from(col)); + panel_bg_and_main <- all(&panel_bg, &color_anim.value); + bg_intensity <- colors.map(|c| c.background_intensity); + background <- all_with(&panel_bg_and_main, &bg_intensity, + |(bg, main), intensity| color::mix(*bg, *main, *intensity) + ).sampler(); + hover_highlight <- all_with(&color_anim.value, &colors, + |main, colors| colors.hover_highlight.resolve(main) + ).sampler(); + text <- all_with(&color_anim.value, &colors, + |main, colors| colors.text.resolve(main) + ).sampler(); + icon <- all_with(&color_anim.value, &colors, + |main, colors| colors.icon.resolve(main) + ).sampler(); skip_animations <- any(...); - intensity.skip <+ skip_animations; + color_anim.skip <+ skip_animations; } init.emit(()); - Self { icon_weak, icon_strong, text, background, hover_highlight, skip_animations } + Self { icon, text, background, hover_highlight, skip_animations } } } diff --git a/app/gui/view/component-browser/component-list-panel/grid/src/lib.rs b/app/gui/view/component-browser/component-list-panel/grid/src/lib.rs index 8ffbbb3d862..a8085140063 100644 --- a/app/gui/view/component-browser/component-list-panel/grid/src/lib.rs +++ b/app/gui/view/component-browser/component-list-panel/grid/src/lib.rs @@ -524,10 +524,10 @@ impl Model { fn entries_params( &self, - (style, entry_style, color_intensities, group_colors): &( + (style, entry_style, colors, group_colors): &( Style, entry::Style, - entry::style::ColorIntensities, + entry::style::Colors, GroupColors, ), dimmed_groups: entry::DimmedGroups, @@ -536,16 +536,16 @@ impl Model { style: entry_style.clone(), grid_style: *style, group_colors: *group_colors, - color_intensities: *color_intensities, + colors: *colors, dimmed_groups, } } fn selection_entries_params( &self, - (base_params, color_intensities): &(entry::Params, entry::style::SelectionColorIntensities), + (base_params, colors): &(entry::Params, entry::style::SelectionColors), ) -> entry::Params { - entry::Params { color_intensities: (*color_intensities).into(), ..base_params.clone() } + entry::Params { colors: (*colors).into(), ..base_params.clone() } } fn navigation_scroll_margins( @@ -599,9 +599,8 @@ impl component::Frp for Frp { let corners_radius = style_frp.get_number(panel_theme::corners_radius); let style = Style::from_theme(network, style_frp); let entry_style = entry::Style::from_theme(network, style_frp); - let color_intensities = entry::style::ColorIntensities::from_theme(network, style_frp); - let selection_color_intensities = - entry::style::SelectionColorIntensities::from_theme(network, style_frp); + let colors = entry::style::Colors::from_theme(network, style_frp); + let selection_colors = entry::style::SelectionColors::from_theme(network, style_frp); frp::extend! { network // === Active and Hovered Entry === @@ -637,7 +636,7 @@ impl component::Frp for Frp { group_colors <- all_with(&groups, &local_scope_group, |&((), g0, g1, g2, g3, g4, g5), ls| { GroupColors { variants: [g0, g1, g2, g3, g4, g5].map(color::Lcha::from), - local_scope_group: ls.into() + local_scope_group: ls.into(), } }); @@ -650,10 +649,10 @@ impl component::Frp for Frp { None => entry::DimmedGroups::None, }); entries_style <- - all4(&style.update, &entry_style.update, &color_intensities.update, &group_colors); + all4(&style.update, &entry_style.update, &colors.update, &group_colors); entries_params <- all_with(&entries_style, &dimmed_groups, f!((s, d) model.entries_params(s, *d))); - selection_entries_style <- all(entries_params, selection_color_intensities.update); + selection_entries_style <- all(entries_params, selection_colors.update); selection_entries_params <- selection_entries_style.map(f!((input) model.selection_entries_params(input))); grid_scroll_frp.resize <+ style_and_content_size.map(Model::grid_size); @@ -732,8 +731,8 @@ impl component::Frp for Frp { grid.resize_grid(0, column::COUNT); style.init.emit(()); entry_style.init.emit(()); - color_intensities.init.emit(()); - selection_color_intensities.init.emit(()); + colors.init.emit(()); + selection_colors.init.emit(()); } fn default_shortcuts() -> Vec { diff --git a/app/gui/view/component-browser/component-list-panel/icons/Cargo.toml b/app/gui/view/component-browser/component-list-panel/icons/Cargo.toml new file mode 100644 index 00000000000..e0a4661af45 --- /dev/null +++ b/app/gui/view/component-browser/component-list-panel/icons/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ide-view-component-list-panel-icons" +version = "0.1.0" +authors = ["Enso Team "] +edition = "2021" + +[dependencies] +ensogl-core = { path = "../../../../../../lib/rust/ensogl/core" } +failure = "0.1.8" diff --git a/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon/common_part.rs b/app/gui/view/component-browser/component-list-panel/icons/src/common_part.rs similarity index 79% rename from app/gui/view/component-browser/component-list-panel/grid/src/entry/icon/common_part.rs rename to app/gui/view/component-browser/component-list-panel/icons/src/common_part.rs index d19241308a0..0a8e8c14d78 100644 --- a/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon/common_part.rs +++ b/app/gui/view/component-browser/component-list-panel/icons/src/common_part.rs @@ -36,9 +36,9 @@ pub fn grid(stroke_width: f32, cell_size: f32) -> AnyShape { /// A cursor shape, looking roughly like a capital "I". pub fn cursor() -> AnyShape { - let middle = Rect((1.0.px(), 15.0.px())); - let top = Rect((5.0.px(), 1.0.px())).translate_y(7.5.px()); - let bottom = Rect((5.0.px(), 1.0.px())).translate_y((-7.5).px()); + let middle = Rect((2.0.px(), 16.0.px())); + let top = Rect((6.0.px(), 2.0.px())).translate_y(7.0.px()); + let bottom = Rect((6.0.px(), 2.0.px())).translate_y((-7.0).px()); (middle + top + bottom).into() } @@ -57,18 +57,24 @@ pub fn arc(outer_radius: f32, stroke_width: f32, start_angle: f32, end_angle: f3 (circle * angle).into() } -/// The shape of a table, given by a grid with size `columns` x `rows`. The stroke width is 1.0 and -/// the cell size 4.0. The origin is at the lower left corner. -pub fn table(columns: i32, rows: i32) -> AnyShape { - const STROKE_WIDTH: f32 = 1.0; - const CELL_SIZE: f32 = 4.0; +/// An 2d-array of squares of size `cell_size`. +pub fn table(columns: i32, rows: i32, cell_size: f32) -> AnyShape { + const GAP: f32 = 1.0; - let width = columns as f32 * CELL_SIZE + STROKE_WIDTH; - let height = rows as f32 * CELL_SIZE + STROKE_WIDTH; - let bounds = - Rect((width.px(), height.px())).translate(((width / 2.0).px(), (height / 2.0).px())); - let grid = grid(STROKE_WIDTH, CELL_SIZE); - (grid * bounds).into() + let cell = Rect((cell_size.px(), cell_size.px())); + let table = cell.repeat(((cell_size + GAP).px(), (cell_size + GAP).px())); + let table = table.translate_x((-cell_size / 2.0 - GAP).px()); + let table = table.translate_y((-cell_size / 2.0 - GAP).px()); + + let width = (cell_size + GAP) * columns as f32 - GAP; + let height = (cell_size + GAP) * rows as f32 - GAP; + + let bounds = Rect((width.px(), height.px())); + let bounds = bounds.translate_x((width / 2.0).px()); + let bounds = bounds.translate_y((height / 2.0).px()); + + let shape = table * bounds; + shape.into() } /// A plus, consisting of two strokes of length `size` and width `stroke_width`, intersecting at the diff --git a/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon/define_macro.rs b/app/gui/view/component-browser/component-list-panel/icons/src/define_macro.rs similarity index 75% rename from app/gui/view/component-browser/component-list-panel/grid/src/entry/icon/define_macro.rs rename to app/gui/view/component-browser/component-list-panel/icons/src/define_macro.rs index a31f81d88b7..a37f06377db 100644 --- a/app/gui/view/component-browser/component-list-panel/grid/src/entry/icon/define_macro.rs +++ b/app/gui/view/component-browser/component-list-panel/icons/src/define_macro.rs @@ -17,8 +17,7 @@ /// use ensogl_core::prelude::*; /// use ensogl_core::display::shape::*; /// use ensogl_core::data::color; -/// use ide_view_component_list_panel_grid::entry::icon; -/// use ide_view_component_list_panel_grid::define_icons; +/// use ide_view_component_list_panel_icons::define_icons; /// /// define_icons! { /// /// The example of icon. @@ -28,7 +27,7 @@ /// // /// // `use super::*` import is added silently. /// ensogl_core::shape! { -/// (style:Style, vivid_color: Vector4, dull_color: Vector4) { +/// (style:Style, color: Vector4) { /// Plane().into() /// } /// } @@ -36,8 +35,8 @@ /// /// pub mod icon2(Icon2) { /// ensogl_core::shape! { -/// (style:Style, vivid_color: Vector4, dull_color: Vector4) { -/// Plane().fill(vivid_color).into() +/// (style:Style, color: Vector4) { +/// Plane().fill(color).into() /// } /// } /// } @@ -81,30 +80,22 @@ macro_rules! define_icons { impl Id { /// Create icon's shape with given size. - pub fn create_shape(&self, size: Vector2) -> $crate::entry::icon::Any { + pub fn create_shape(&self, size: Vector2) -> $crate::Any { match self {$( Self::$variant => { let view = $name::View::new(); view.size.set(size); - let vivid_color_fn = Box::new(f!([view]() - color::Lcha::from(color::Rgba::from(view.vivid_color.get())) + let color_fn = Box::new(f!([view]() + color::Lcha::from(color::Rgba::from(view.color.get())) )); - let dull_color_fn = Box::new(f!([view]() - color::Lcha::from(color::Rgba::from(view.dull_color.get())) - )); - let set_vivid_color_fn = Box::new(f!((c) - view.vivid_color.set(color::Rgba::from(c).into()) - )); - let set_dull_color_fn = Box::new(f!((c) - view.dull_color.set(color::Rgba::from(c).into()) + let set_color_fn = Box::new(f!((c) + view.color.set(color::Rgba::from(c).into()) )); let view = Box::new(view); - $crate::entry::icon::Any { + $crate::Any { view, - vivid_color_fn, - dull_color_fn, - set_vivid_color_fn, - set_dull_color_fn + color_fn, + set_color_fn, } } )*} @@ -124,7 +115,7 @@ macro_rules! define_icons { } impl FromStr for Id { - type Err = $crate::entry::icon::UnknownIcon; + type Err = $crate::UnknownIcon; fn from_str(s: &str) -> Result { match s { $(stringify!($variant) => Ok(Self::$variant),)* diff --git a/app/gui/view/component-browser/component-list-panel/icons/src/lib.rs b/app/gui/view/component-browser/component-list-panel/icons/src/lib.rs new file mode 100644 index 00000000000..9c03b007c65 --- /dev/null +++ b/app/gui/view/component-browser/component-list-panel/icons/src/lib.rs @@ -0,0 +1,100 @@ +// === Standard Linter Configuration === +#![deny(non_ascii_idents)] +#![warn(unsafe_code)] +#![allow(clippy::bool_to_int_with_if)] +#![allow(clippy::let_and_return)] + +use prelude::*; + +use ensogl_core::data::color; +use ensogl_core::display; + + + +mod prelude { + pub use ensogl_core::application::traits::*; + pub use ensogl_core::display::shape::*; + pub use ensogl_core::prelude::*; +} + +pub mod common_part; +mod define_macro; + + + +// ================= +// === Constants === +// ================= + +/// The width and height of all icons. +pub const SIZE: f32 = 16.0; + +/// This constant exists for development purposes only, and is published for debug scene. +/// Due to a rendering error, shapes appear too big when the camera is zoomed in very closely. +/// (Documented here: https://github.com/enso-org/ide/issues/1698) +/// In the user interface, this is not a big problem, since icon are usually shown at lower zoom +/// levels. But it is a problem during development of icon when it becomes necessary to inspect +/// them closely. In those situations, one can apply `.shrink(0.35)` to shapes to compensate for the +/// bug and make them appear at the correct size while the camera is zoomed in. But that work-around +/// will make them appear too thin on the default zoom level. +/// +/// To make it easy to turn this shrinking on and off before and after working on icon, we define +/// the constant `SHRINK_AMOUNT` and apply `.shrink(SHRINK_AMOUNT.px())` to all icon. In every +/// commit, `SHRINK_AMOUNT` should be set to 0.0 to make icon look best in the user interface. But +/// during work on the icon, it can temporarily be set to 0.35. +pub const SHRINK_AMOUNT: f32 = 0.0; + + + +// ============== +// === Errors === +// ============== + +/// Error occuring when we try parse string being an invalid icon name to icon Id. +#[derive(Clone, Debug, Fail)] +#[fail(display = "Unknown icon '{}'.", name)] +pub struct UnknownIcon { + /// The copied icon name from parsed string. + pub name: String, +} + + + +// =============== +// === AnyIcon === +// =============== + +/// One of the icon generated from the [`define_icons`] macro. Returned from `create_shape` method. +pub struct Any { + /// The underlying icon shape. + pub view: Box, + /// The primary color of the icon. Secondary colors are calculated by applying transparency to + /// the primary color. + pub color_fn: Box color::Lcha>, + /// Setter for vivid (darker, or more contrasting) color parameter. + pub set_color_fn: Box, +} + +/// See docs of [`Any`] to learn more. +#[allow(missing_docs)] +impl Any { + pub fn color(&self) -> color::Lcha { + (self.color_fn)() + } + + pub fn set_color(&self, color: color::Lcha) { + (self.set_color_fn)(color) + } +} + +impl Debug for Any { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Any") + } +} + +impl display::Object for Any { + fn display_object(&self) -> &display::object::Instance { + self.view.display_object() + } +} diff --git a/app/gui/view/component-browser/component-list-panel/src/lib.rs b/app/gui/view/component-browser/component-list-panel/src/lib.rs index 97e3d28078a..868abb2c662 100644 --- a/app/gui/view/component-browser/component-list-panel/src/lib.rs +++ b/app/gui/view/component-browser/component-list-panel/src/lib.rs @@ -46,7 +46,6 @@ use crate::prelude::*; use ensogl_core::display::shape::*; -use crate::navigator::navigator_shadow; use crate::navigator::Navigator as SectionNavigator; use enso_frp as frp; @@ -60,9 +59,9 @@ use ensogl_core::display::navigation::navigator::Navigator; use ensogl_core::display::object::ObjectOps; use ensogl_core::display::shape::StyleWatchFrp; use ensogl_derive_theme::FromTheme; +use ensogl_grid_view as grid_view; use ensogl_gui_component::component; use ensogl_hardcoded_theme::application::component_browser::component_list_panel as theme; -use ensogl_list_view as list_view; use ensogl_shadow as shadow; @@ -148,7 +147,7 @@ impl AllStyles { fn breadcrumbs_pos(&self) -> Vector2 { let crop_left = self.panel.breadcrumbs_crop_left; let x = -self.grid.width / 2.0 + self.navigator.width / 2.0 + crop_left; - let y = self.grid.height / 2.0 + self.panel.menu_height / 2.0 - self.grid.padding; + let y = self.size().y / 2.0; Vector2(x, y) } @@ -179,36 +178,47 @@ mod background { use super::*; ensogl_core::shape! { - below = [grid::entry::background, list_view::overlay]; + below = [grid::entry::background, grid_view::entry::overlay, grid_view::selectable::highlight::shape]; (style:Style,bg_color:Vector4) { let alpha = Var::::from(format!("({0}.w)",bg_color)); let bg_color = &Var::::from(bg_color.clone()); + let grid_padding = style.get_number(theme::grid::padding); let grid_width = style.get_number(theme::grid::width); let grid_height = style.get_number(theme::grid::height); let corners_radius = style.get_number(theme::corners_radius); let menu_divider_color = style.get_color(theme::menu_divider_color); + let navigator_divider_color = style.get_color(theme::navigator_divider_color); + let menu_divider_width = grid_width - grid_padding * 2.0; let menu_divider_height = style.get_number(theme::menu_divider_height); + let navigator_divider_width = style.get_number(theme::navigator_divider_width); let menu_height = style.get_number(theme::menu_height); let navigator_width = style.get_number(theme::navigator::width); let width = grid_width + navigator_width; let height = grid_height + menu_height; - let divider_x_pos = navigator_width / 2.0; - let divider_y_pos = height / 2.0 - menu_height + menu_divider_height ; + let menu_divider_x_pos = navigator_width / 2.0; + let menu_divider_y_pos = height / 2.0 - menu_height + menu_divider_height; + let navigator_divider_x = -width / 2.0 + navigator_width - navigator_divider_width / 2.0; + let navigator_divider_y = 0.0; - let divider = Rect((grid_width.px(),menu_divider_height.px())); - let divider = divider.fill(menu_divider_color); - let divider = divider.translate_x(divider_x_pos.px()); - let divider = divider.translate_y(divider_y_pos.px()); + let menu_divider = Rect((menu_divider_width.px(),menu_divider_height.px())); + let menu_divider = menu_divider.fill(menu_divider_color); + let menu_divider = menu_divider.translate_x(menu_divider_x_pos.px()); + let menu_divider = menu_divider.translate_y(menu_divider_y_pos.px()); + + let navigator_divider = Rect((navigator_divider_width.px(), height.px())); + let navigator_divider = navigator_divider.fill(navigator_divider_color); + let navigator_divider = navigator_divider.translate_x(navigator_divider_x.px()); + let navigator_divider = navigator_divider.translate_y(navigator_divider_y.px()); let base_shape = Rect((width.px(), height.px())); let base_shape = base_shape.corners_radius(corners_radius.px()); let background = base_shape.fill(bg_color); let shadow = shadow::from_shape_with_alpha(base_shape.into(),&alpha,style); - (shadow + background + divider).into() + (shadow + background + menu_divider + navigator_divider).into() } } } @@ -225,13 +235,6 @@ mod background { pub struct Model { display_object: display::object::Instance, background: background::View, - // FIXME[#182593513]: This separate shape for navigator shadow can be removed and replaced - // with a shadow embedded into the [`background`] shape when the - // [issue](https://www.pivotaltracker.com/story/show/182593513) is fixed. - // To display the shadow correctly it needs to be clipped to the [`background`] shape, but - // we can't do that because of a bug in the renderer. So instead we add the shadow as a - // separate shape and clip it using `size.set(...)`. - navigator_shadow: navigator_shadow::View, pub grid: grid::View, pub section_navigator: SectionNavigator, pub breadcrumbs: breadcrumbs::Breadcrumbs, @@ -246,8 +249,6 @@ impl Model { let background = background::View::new(); display_object.add_child(&background); - let navigator_shadow = navigator_shadow::View::new(); - display_object.add_child(&navigator_shadow); let grid = app.new_view::(); display_object.add_child(&grid); @@ -259,15 +260,7 @@ impl Model { breadcrumbs.set_base_layer(&app.display.default_scene.layers.node_searcher); display_object.add_child(&breadcrumbs); - Self { - display_object, - background, - navigator_shadow, - grid, - section_navigator, - scene_navigator, - breadcrumbs, - } + Self { display_object, background, grid, section_navigator, scene_navigator, breadcrumbs } } fn set_initial_breadcrumbs(&self) { @@ -281,11 +274,6 @@ impl Model { self.background.size.set(style.background_sprite_size()); self.section_navigator.update_layout(style); - let navigator_shadow_x = -style.grid.width / 2.0; - self.navigator_shadow.set_x(navigator_shadow_x); - let section_navigator_shadow_size = Vector2(style.navigator.width, style.size().y); - self.navigator_shadow.size.set(section_navigator_shadow_size); - self.breadcrumbs.set_xy(style.breadcrumbs_pos()); self.breadcrumbs.set_size(style.breadcrumbs_size()); self.grid.set_xy(style.grid_pos()); @@ -397,14 +385,6 @@ impl component::Frp for Frp { model.section_navigator.select_section <+ model.grid.active_section.on_change(); - // === Navigator icons colors === - - let vivid_color = style.get_color(theme::navigator::icon_strong_color); - let dull_color = style.get_color(theme::navigator::icon_weak_color); - let params = icon::Params { vivid_color, dull_color }; - model.section_navigator.set_bottom_buttons_entry_params(params); - - // === Breadcrumbs === eval_ input.show(model.set_initial_breadcrumbs()); diff --git a/app/gui/view/component-browser/component-list-panel/src/navigator.rs b/app/gui/view/component-browser/component-list-panel/src/navigator.rs index 708430902f1..25ee8dd415e 100644 --- a/app/gui/view/component-browser/component-list-panel/src/navigator.rs +++ b/app/gui/view/component-browser/component-list-panel/src/navigator.rs @@ -8,6 +8,7 @@ use ensogl_core::prelude::*; use crate::AllStyles; +use crate::grid::entry::icon; use enso_frp as frp; use ensogl_core::animation::animation::delayed::DelayedAnimation; use ensogl_core::application::tooltip; @@ -15,57 +16,33 @@ use ensogl_core::application::Application; use ensogl_core::data::color; use ensogl_core::display; use ensogl_derive_theme::FromTheme; +use ensogl_grid_view as grid; use ensogl_hardcoded_theme::application::component_browser::component_list_panel as list_panel_theme; -use ensogl_list_view as list_view; -use ensogl_list_view::entry::AnyModelProvider; -use ensogl_shadow as shadow; use ensogl_tooltip::Tooltip; -use ide_view_component_list_panel_grid::entry::icon; +use grid::Col; +use grid::Row; use ide_view_component_list_panel_grid::SectionId; use list_panel_theme::navigator as theme; +mod entry; + +type Grid = grid::selectable::GridView; + + + // ================= // === Constants === // ================= +const MARKETPLACE_BUTTON_INDEX: usize = 1; const MARKETPLACE_TOOLTIP_TEXT: &str = "Marketplace will be available soon."; const MARKETPLACE_TOOLTIP_HIDE_DELAY_MS: f32 = 3000.0; const MARKETPLACE_TOOLTIP_PLACEMENT: tooltip::Placement = tooltip::Placement::Bottom; const TOP_BUTTONS: [icon::Id; 2] = [icon::Id::Libraries, icon::Id::Marketplace]; -const MARKETPLACE_BUTTON_INDEX: usize = 1; -const BOTTOM_BUTTONS: [icon::Id; 3] = [icon::Id::SubModules, icon::Id::Star, icon::Id::LocalScope]; - - - -// ============== -// === Shadow === -// ============== - -/// A shadow between the navigator bar and the main part of the Searcher List Panel. -/// -/// We should have this shape embedded into the background shape, but we use a separate object -/// because of https://www.pivotaltracker.com/story/show/182593513. -pub mod navigator_shadow { - use super::*; - - ensogl_core::shape! { - above = [crate::background]; - below = [list_view::overlay, list_view::selection]; - pointer_events = false; - (style:Style) { - let grid_height = style.get_number(list_panel_theme::grid::height); - let menu_height = style.get_number(list_panel_theme::menu_height); - let navigator_width = style.get_number(theme::width); - let height = grid_height + menu_height; - let width = navigator_width; - let base_shape = Rect((width.px(), height.px() * 2.0)).translate_x(width.px()); - shadow::from_shape(base_shape.into(), style) - } - } -} - +const TOP_BUTTONS_COUNT: usize = TOP_BUTTONS.len(); +const BOTTOM_BUTTONS_COUNT: usize = 3; // ============= @@ -75,39 +52,92 @@ pub mod navigator_shadow { #[derive(Copy, Clone, Debug, Default, FromTheme)] #[base_path = "theme"] pub struct Style { - pub width: f32, - pub list_view_width: f32, - pub icon_strong_color: color::Rgba, - pub icon_weak_color: color::Rgba, - pub top_padding: f32, - pub bottom_padding: f32, + pub width: f32, + pub button_size: f32, + pub top_padding: f32, + pub bottom_padding: f32, + pub hover_color: color::Rgba, + #[theme_path = "theme::highlight::color"] + pub highlight_color: color::Rgba, + #[theme_path = "theme::highlight::size"] + pub highlight_size: f32, + #[theme_path = "theme::highlight::corners_radius"] + pub highlight_corners_radius: f32, } - - -// ========================================================= -// === Conversions Between SectionId and List View Index === -// ========================================================= - -/// Convert [`SectionId`] to index on [`Navigator::bottom_buttons`]. -fn section_id_to_list_index(id: SectionId) -> usize { - match id { - SectionId::Popular => 1, - SectionId::LocalScope => 2, - SectionId::SubModules => 0, +impl From