From b55d610c9b8a994e7a98f26176e79f7083f16809 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Thu, 6 May 2021 11:17:55 +0100 Subject: [PATCH 01/29] Add profiling mode --- src/rust/ensogl/lib/theme/src/lib.rs | 6 + .../view/graph-editor/src/component/node.rs | 78 +++++-- .../src/component/node/input/area.rs | 32 ++- .../src/component/node/profiling_indicator.rs | 188 +++++++++++++++++ src/rust/ide/view/graph-editor/src/lib.rs | 198 ++++++++++++++++-- .../ide/view/src/debug_scenes/interface.rs | 11 + 6 files changed, 473 insertions(+), 40 deletions(-) create mode 100644 src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs diff --git a/src/rust/ensogl/lib/theme/src/lib.rs b/src/rust/ensogl/lib/theme/src/lib.rs index 0d34377d02..7d13e0396b 100644 --- a/src/rust/ensogl/lib/theme/src/lib.rs +++ b/src/rust/ensogl/lib/theme/src/lib.rs @@ -262,6 +262,12 @@ define_themes! { [light:0, dark:1] stripe_width = 10.0 , 10.0; stripe_angle = 45.0 , 45.0; } + profiling { + lightness = code::types::lightness , code::types::lightness; + chroma = code::types::chroma , code::types::chroma; + min_hue = 0.38 , 0.38; + max_hue = 0.07 , 0.07; + } } visualization { background = graph_editor::node::background , graph_editor::node::background; diff --git a/src/rust/ide/view/graph-editor/src/component/node.rs b/src/rust/ide/view/graph-editor/src/component/node.rs index 432df85b28..36e7199340 100644 --- a/src/rust/ide/view/graph-editor/src/component/node.rs +++ b/src/rust/ide/view/graph-editor/src/component/node.rs @@ -12,12 +12,15 @@ pub mod output; pub mod error; #[deny(missing_docs)] pub mod vcs; +mod profiling_indicator; pub use error::Error; pub use expression::Expression; use crate::prelude::*; +use profiling_indicator::ProfilingIndicator; +use crate::Mode as EditorMode; use crate::component::visualization; use crate::tooltip; use crate::Type; @@ -50,10 +53,10 @@ pub const HEIGHT : f32 = 28.0; pub const PADDING : f32 = 40.0; pub const RADIUS : f32 = 14.0; -const INFINITE : f32 = 99999.0; -const ERROR_VISUALIZATION_SIZE : (f32,f32) = visualization::container::DEFAULT_SIZE; +const INFINITE : f32 = 99999.0; +const ERROR_VISUALIZATION_SIZE : (f32,f32) = visualization::container::DEFAULT_SIZE; -const VISUALIZATION_OFFSET_Y : f32 = -120.0; +const VISUALIZATION_OFFSET_Y : f32 = -120.0; const VIS_PREVIEW_ONSET_MS : f32 = 3000.0; const ERROR_PREVIEW_ONSET_MS : f32 = 0000.0; @@ -205,6 +208,24 @@ pub mod error_shape { +// ======================== +// === Execution Status === +// ======================== + +#[derive(Debug,Copy,Clone)] +pub enum ExecutionStatus { + Running, + Finished { duration: f32 } +} + +impl Default for ExecutionStatus { + fn default() -> Self { + ExecutionStatus::Running + } +} + + + // ============== // === Crumbs === // ============== @@ -256,11 +277,15 @@ ensogl::define_endpoints! { /// Set the expression USAGE type. This is not the definition type, which can be set with /// `set_expression` instead. In case the usage type is set to None, ports still may be /// colored if the definition type was present. - set_expression_usage_type (Crumbs,Option), - set_output_expression_visibility (bool), - set_vcs_status (Option), + set_expression_usage_type (Crumbs,Option), + set_output_expression_visibility (bool), + set_vcs_status (Option), /// Indicate whether preview visualisations should be delayed or immediate. - quick_preview_vis (bool), + quick_preview_vis (bool), + set_editor_mode (EditorMode), + set_profiling_min_global_duration (f32), + set_profiling_max_global_duration (f32), + set_execution_status (ExecutionStatus), } Output { /// Press event. Emitted when user clicks on non-active part of the node, like its @@ -359,6 +384,7 @@ pub struct NodeModel { pub background : background::View, pub drag_area : drag_area::View, pub error_indicator : error_shape::View, + pub profiling_indicator : ProfilingIndicator, pub input : input::Area, pub output : output::Area, pub visualization : visualization::Container, @@ -370,7 +396,7 @@ pub struct NodeModel { impl NodeModel { /// Constructor. - pub fn new(app:&Application, registry:visualization::Registry) -> Self { + pub fn new(app:&Application,registry:visualization::Registry) -> Self { ensogl::shapes_order_dependencies! { app.display.scene() => { edge::back::corner -> backdrop; @@ -395,13 +421,15 @@ impl NodeModel { let drag_logger = Logger::sub(&logger,"drag_area"); let error_indicator_logger = Logger::sub(&logger,"error_indicator"); - let error_indicator = error_shape::View::new(&error_indicator_logger); - let backdrop = backdrop::View::new(&main_logger); - let background = background::View::new(&main_logger); - let drag_area = drag_area::View::new(&drag_logger); - let vcs_indicator = vcs::StatusIndicator::new(app); - let display_object = display::object::Instance::new(&logger); + let error_indicator = error_shape::View::new(&error_indicator_logger); + let profiling_indicator = ProfilingIndicator::new(app); + let backdrop = backdrop::View::new(&main_logger); + let background = background::View::new(&main_logger); + let drag_area = drag_area::View::new(&drag_logger); + let vcs_indicator = vcs::StatusIndicator::new(app); + let display_object = display::object::Instance::new(&logger); + display_object.add_child(&profiling_indicator); display_object.add_child(&drag_area); display_object.add_child(&backdrop); display_object.add_child(&background); @@ -432,7 +460,8 @@ impl NodeModel { let app = app.clone_ref(); Self {app,display_object,logger,backdrop,background,drag_area,output,input,visualization - ,error_visualization,action_bar,error_indicator,vcs_indicator,style}.init() + ,error_visualization,profiling_indicator,action_bar,error_indicator,vcs_indicator,style} + .init() } pub fn get_crumbs_by_id(&self, id:ast::Id) -> Option { @@ -473,12 +502,14 @@ impl NodeModel { self.backdrop.size.set(padded_size); self.background.size.set(padded_size); self.drag_area.size.set(padded_size); + self.profiling_indicator.set_size(padded_size); self.error_indicator.size.set(padded_size); self.vcs_indicator.set_size(padded_size); self.backdrop.mod_position(|t| t.x = width/2.0); self.background.mod_position(|t| t.x = width/2.0); self.drag_area.mod_position(|t| t.x = width/2.0); + self.profiling_indicator.set_position_x(width/2.0); self.error_indicator.set_position_x(width/2.0); self.vcs_indicator.set_position_x(width/2.0); @@ -587,6 +618,12 @@ impl Node { out.source.skip <+ action_bar.action_skip; out.source.freeze <+ action_bar.action_freeze; eval out.hover ((t) action_bar.set_visibility(t)); + + + // === Editor Mode === + + model.input.set_editor_mode <+ frp.set_editor_mode; + model.profiling_indicator.set_editor_mode <+ frp.set_editor_mode; } @@ -663,6 +700,17 @@ impl Node { } + // === Profiling Indicator === + + frp::extend! { network + model.profiling_indicator.set_min_global_duration + <+ frp.set_profiling_min_global_duration; + model.profiling_indicator.set_max_global_duration + <+ frp.set_profiling_max_global_duration; + model.profiling_indicator.set_execution_status <+ frp.set_execution_status; + } + + frp::extend! { network // === Color Handling === diff --git a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs index 0178804d8f..12a93f7cfa 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs @@ -21,6 +21,7 @@ use crate::Type; use crate::component::type_coloring; use crate::node::input::port; use crate::node; +use crate::Mode as EditorMode; @@ -193,6 +194,8 @@ ensogl::define_endpoints! { /// if any. It is used to highlight ports if they are missing type information or if their /// types are polymorphic. set_ports_active (bool,Option), + + set_editor_mode(EditorMode), } Output { @@ -206,6 +209,7 @@ ensogl::define_endpoints! { on_port_hover (Switch), on_port_type_change (Crumbs,Option), on_background_press (), + editor_mode (EditorMode), } } @@ -387,6 +391,10 @@ impl Area { // === Expression Type === eval frp.set_expression_usage_type (((a,b)) model.set_expression_usage_type(a,b)); + + + // === Editor Mode === + frp.output.source.editor_mode <+ frp.set_editor_mode; } Self {model,frp} @@ -592,11 +600,16 @@ impl Area { let port_shape_hover = port_shape.hover.clone_ref(); pointer_style_out <- mouse_out.map(|_| default()); - pointer_style_over <- map3(&mouse_over,&frp.set_ports_active,&port.tp, - move |_,(_,edge_tp),port_tp| { + pointer_style_over <- map4 + (&mouse_over,&frp.set_ports_active,&port.tp,&frp.editor_mode, + move |_,(_,edge_tp),port_tp,editor_mode| { let tp = port_tp.as_ref().or_else(||edge_tp.as_ref()); let color = tp.map(|tp| type_coloring::compute(tp,&styles)); let color = color.unwrap_or(any_type_sel_color); + let color = match editor_mode { + EditorMode::Normal => color, + EditorMode::Profiling => any_type_sel_color + }; cursor::Style::new_highlight(&port_shape_hover,padded_size,Some(color)) } ); @@ -703,10 +716,17 @@ impl Area { if let Some(port_shape) = &node.payload.shape { frp::extend! { port_network port_tp <- all(&frp.set_hover,&frp.tp)._1(); - new_viz_color <- all_with(&port_tp,&frp.set_connected,f!([styles] - (port_tp,(is_connected,edge_tp)) { - let tp = port_tp.as_ref().or_else(||edge_tp.as_ref()); - let color = select_color(&styles,tp); + new_viz_color <- all_with3 + (&port_tp,&frp.set_connected,&self.editor_mode, + f!([styles](port_tp,(is_connected,edge_tp),editor_mode) { + let tp = port_tp.as_ref().or_else(||edge_tp.as_ref()); + let color = select_color(&styles,tp); + let neutral_color_theme = theme::code::types::any::selection; + let neutral_color = styles.get_color(neutral_color_theme); + let color = match editor_mode { + EditorMode::Normal => color, + EditorMode::Profiling => neutral_color.into() + }; if *is_connected {color} else { color::Lcha::transparent() } } )); diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs new file mode 100644 index 0000000000..5a500c2def --- /dev/null +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs @@ -0,0 +1,188 @@ +use crate::prelude::*; + +use crate::Mode as EditorMode; +use crate::component::node; +use node::ExecutionStatus; + +use enso_frp as frp; +use ensogl::application::Application; +use ensogl::data::color; +use ensogl::display::shape::*; +use ensogl::display; +use ensogl::gui::text; + + + +// ============= +// === Shape === +// ============= + +mod shape { + use super::*; + + pub const WIDTH_OUTER : f32 = 15.0; + pub const WIDTH_INNER : f32 = 10.0; + pub const THICKNESS : f32 = WIDTH_OUTER - WIDTH_INNER; + pub const LABEL_GAP_PADDING : f32 = 5.0; + pub const LABEL_GAP_HEIGHT : f32 = 16.0; + + ensogl::define_shape_system! { + (style:Style,color_rgba:Vector4,label_width:f32) { + let width = Var::::from("input_size.x"); + let height = Var::::from("input_size.y"); + let width = width - node::PADDING.px() * 2.0; + let height = height - node::PADDING.px() * 2.0; + let radius = node::RADIUS.px(); + + let base = Rect((&width,&height)).corners_radius(&radius); + let outer = base.grow(WIDTH_OUTER.px()); + let inner = base.grow(WIDTH_INNER.px()); + let outline = outer - inner; + + let upper_center_y = height / 2.0 + WIDTH_INNER.px() + THICKNESS.px() / 2.0; + let label_gap_width = label_width * 1.px() + LABEL_GAP_PADDING.px() * 2.0; + let label_gap = Rect((&label_gap_width,LABEL_GAP_HEIGHT.px())); + let label_gap = label_gap.corners_radius(LABEL_GAP_PADDING.px()); + let label_gap = label_gap.translate_y(upper_center_y); + + (outline-label_gap).fill(color_rgba).into() + } + } +} + + + +// ============ +// === Frp === +// ============ + +ensogl::define_endpoints! { + Input { + set_size (Vector2), + set_execution_status (ExecutionStatus), + set_min_global_duration (f32), + set_max_global_duration (f32), + set_editor_mode (EditorMode), + } +} + + + +// =========================== +// === Profiling Indicator === +// =========================== + +#[derive(Clone,CloneRef,Debug)] +pub struct ProfilingIndicator { + display_object : display::object::Instance, + shape : shape::View, + label : text::Area, + frp : Frp +} + +impl Deref for ProfilingIndicator { + type Target = Frp; + + fn deref(&self) -> &Self::Target { + &self.frp + } +} + + +impl ProfilingIndicator { + pub fn new(app: &Application) -> Self { + let scene = app.display.scene(); + let styles = StyleWatch::new(&scene.style_sheet); + let logger = Logger::new("ProfilingIndicator"); + let display_object = display::object::Instance::new(&logger); + + let shape = shape::View::new(&logger); + display_object.add_child(&shape); + + let label = text::Area::new(app); + display_object.add_child(&label); + label.remove_from_scene_layer_DEPRECATED(&scene.layers.main); + label.add_to_scene_layer_DEPRECATED(&scene.layers.label); + + let frp = Frp::new(); + let network = &frp.network; + let color = color::Animation::new(network); + + frp::extend! { network + + // === Visibility === + + visibility <- all_with(&frp.set_editor_mode,&frp.set_execution_status,|mode,status| { + match (mode,status) { + (EditorMode::Profiling,ExecutionStatus::Finished {..}) => true, + _ => false, + } + }); + + color.target_alpha <+ visibility.map(|&is_visible| { + if is_visible { + 1.0 + } else { + 0.0 + } + }); + + + // === Color === + + color.target_color <+ all_with3 + (&frp.set_execution_status,&frp.set_min_global_duration, + &frp.set_max_global_duration,f!([styles](&status,&min,&max) { + let theme = ensogl_theme::graph_editor::node::profiling::HERE.path(); + let lightness = styles.get_number(theme.sub("lightness")); + let chroma = styles.get_number(theme.sub("chroma")); + let min_hue = styles.get_number(theme.sub("min_hue")); + let max_hue = styles.get_number(theme.sub("max_hue")); + let hue_delta = max_hue - min_hue; + let running_color = color::Lch::new(lightness,chroma,max_hue); + match status { + ExecutionStatus::Running => running_color, + ExecutionStatus::Finished {duration} => { + let relative_duration = (duration - min) / (max - min); + let hue = min_hue + relative_duration * hue_delta; + color::Lch::new(lightness,chroma,hue) + } + } + }) + ); + + + // === Shape === + + eval frp.set_size((size) shape.size.set(*size)); + eval label.width((&width) shape.label_width.set(width)); + eval color.value((&color) shape.color_rgba.set(color::Rgba::from(color).into())); + + + // === Label === + + eval frp.set_size([label](size) { + let height = size.y - node::PADDING * 2.0; + let upper_center_y = height / 2.0 + shape::WIDTH_INNER + shape::THICKNESS / 2.0; + label.set_position_y(upper_center_y + text::area::LINE_HEIGHT / 2.0) + }); + eval label.width((&width) label.set_position_x(-width/2.0)); + label.set_content <+ frp.set_execution_status.map(|&status| + match status { + ExecutionStatus::Running => "Running".to_string(), + ExecutionStatus::Finished {duration} => format!("{} ms", duration) + }); + label.set_default_color <+ color.value.map(|c| c.into()); + label.set_color_all <+ color.value.map(|c| c.into()); + } + + ProfilingIndicator {display_object,shape,label,frp} + } +} + + +impl display::Object for ProfilingIndicator { + fn display_object(&self) -> &display::object::Instance { + &self.display_object + } +} \ No newline at end of file diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index 4417406250..710400b23f 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -35,6 +35,7 @@ pub mod builtin; pub mod data; use crate::component::node; +pub use crate::component::node::ExecutionStatus as NodeExecutionStatus; use crate::component::tooltip::Tooltip; use crate::component::visualization::instance::PreprocessorConfiguration; use crate::component::tooltip; @@ -61,6 +62,8 @@ use ensogl::prelude::*; use ensogl::system::web; use ensogl_theme as theme; +use std::f32; + // =============== @@ -101,6 +104,95 @@ fn breadcrumbs_gap_width() -> f32 { +// ============ +// === Mode === +// ============ + +#[derive(Debug,Copy,Clone,CloneRef,PartialEq)] +pub enum Mode { + Normal, + Profiling +} + +impl Default for Mode { + fn default() -> Self { + Mode::Normal + } +} + + + +// ========================= +// === ExecutionStatuses === +// ========================= + +/// [`ExecutionsStatuses`] can be used to collect the execution statuses of all nodes in a graph. It +/// exposes their minimum and maximum running times through its FRP endpoints. The structure needs +/// to be updated whenever a node is added or deleted or changes its execution status. +mod execution_statuses { + use super::*; + use std::cmp::Ordering::Equal; + + ensogl::define_endpoints! { + Output { + min_duration (f32), + max_duration (f32), + } + } + + #[derive(Debug,Clone,CloneRef)] + pub struct ExecutionStatuses { + frp : Frp, + // If performance becomes an issue then we could try to store the durations in efficient + // priority queues instead, one to determine the minimum and one to determine the maximum. + durations : SharedHashMap + } + + impl Deref for ExecutionStatuses { + type Target = Frp; + + fn deref(&self) -> &Self::Target { + &self.frp + } + } + + impl ExecutionStatuses { + pub fn new() -> Self { + let frp = Frp::new(); + let durations = SharedHashMap::new(); + Self {frp,durations} + } + + pub fn set(&self,node:NodeId,status:NodeExecutionStatus) { + match status { + NodeExecutionStatus::Finished {duration} => self.durations.insert(node,duration), + _ => self.durations.remove(&node), + }; + self.update_min_max(); + } + + pub fn remove(&self,node:NodeId) { + self.durations.remove(&node); + self.update_min_max(); + } + + fn update_min_max(&self) { + let durations = self.durations.raw.borrow(); + // We need a custom compare function because `f32` does not implement `Ord`. + let cmp_f32 = |a:&&f32, b:&&f32| a.partial_cmp(&b).unwrap_or(Equal); + + let min = durations.values().min_by(cmp_f32).unwrap_or(&f32::INFINITY); + self.source.min_duration.emit(min); + + let max = durations.values().max_by(cmp_f32).unwrap_or(&0.0); + self.source.max_duration.emit(max); + } + } +} +pub use execution_statuses::ExecutionStatuses; + + + // ================= // === SharedVec === // ================= @@ -397,6 +489,8 @@ ensogl::define_endpoints! { collapse_selected_nodes(), /// Indicate whether this node had an error or not. set_node_error_status(NodeId,Option), + /// Indicate whether this node has finished execution. + set_node_execution_status(NodeId,NodeExecutionStatus), // === Visualization === @@ -421,6 +515,11 @@ ensogl::define_endpoints! { set_navigator_disabled(bool), + // === Modes === + + toggle_profiling_mode(), + + // === Debug === /// Push a hardcoded breadcrumb without notifying the controller. @@ -549,6 +648,8 @@ ensogl::define_endpoints! { node_being_edited (Option), node_editing (bool), + mode (Mode), + navigator_active (bool), } } @@ -1143,6 +1244,19 @@ impl GraphEditorModelWithNetwork { output.source.visualization_enabled <+ vis_enabled.map2(&metadata,move |_,metadata| (node_id,metadata.clone())); output.source.visualization_disabled <+ vis_disabled.constant(node_id); + + + // === Mode === + + node.set_editor_mode <+ self.model.frp.mode; + + + // === Profiling === + + node.set_profiling_min_global_duration <+ self.model.execution_statuses.min_duration; + node.set_profiling_min_global_duration(self.model.execution_statuses.min_duration.value()); + node.set_profiling_max_global_duration <+ self.model.execution_statuses.max_duration; + node.set_profiling_max_global_duration(self.model.execution_statuses.max_duration.value()); } let initial_metadata = visualization::Metadata { preprocessor : node.model.visualization.frp.preprocessor.value() @@ -1249,6 +1363,7 @@ pub struct GraphEditorModel { visualisations : Visualisations, frp : FrpEndpoints, navigator : Navigator, + execution_statuses : ExecutionStatuses, } @@ -1260,24 +1375,25 @@ impl GraphEditorModel { , cursor : cursor::Cursor , frp : &Frp ) -> Self { - let network = &frp.network; - let scene = app.display.scene(); - let logger = Logger::new("GraphEditor"); - let display_object = display::object::Instance::new(&logger); - let nodes = Nodes::new(&logger); - let edges = Edges::new(&logger); - let vis_registry = visualization::Registry::with_default_visualizations(); - let visualisations = default(); - let touch_state = TouchState::new(network,&scene.mouse.frp); - let breadcrumbs = component::Breadcrumbs::new(app.clone_ref(),breadcrumbs_gap_width()); - let app = app.clone_ref(); - let frp = frp.output.clone_ref(); - let navigator = Navigator::new(&scene,&scene.camera()); - let tooltip = Tooltip::new(&app); + let network = &frp.network; + let scene = app.display.scene(); + let logger = Logger::new("GraphEditor"); + let display_object = display::object::Instance::new(&logger); + let nodes = Nodes::new(&logger); + let edges = Edges::new(&logger); + let vis_registry = visualization::Registry::with_default_visualizations(); + let visualisations = default(); + let touch_state = TouchState::new(network,&scene.mouse.frp); + let breadcrumbs = component::Breadcrumbs::new(app.clone_ref(),breadcrumbs_gap_width()); + let app = app.clone_ref(); + let frp = frp.output.clone_ref(); + let navigator = Navigator::new(&scene,&scene.camera()); + let tooltip = Tooltip::new(&app); + let execution_statuses = ExecutionStatuses::new(); Self { logger,display_object,app,cursor,nodes,edges,touch_state,frp,breadcrumbs, - vis_registry,visualisations,navigator,tooltip, + vis_registry,visualisations,navigator,tooltip,execution_statuses, }.init() } @@ -1400,6 +1516,7 @@ impl GraphEditorModel { let node_id = node_id.into(); self.nodes.remove(&node_id); self.nodes.selected.remove_item(&node_id); + self.execution_statuses.remove(node_id); } fn node_in_edges(&self, node_id:impl Into) -> Vec { @@ -1812,10 +1929,13 @@ impl GraphEditorModel { let edge_type = self.edge_hover_type() .or_else(|| self.edge_target_type(edge_id)) .or_else(|| self.edge_source_type(edge_id)); - let opt_color = edge_type.map(|t|type_coloring::compute(&t,&styles)); - opt_color.unwrap_or_else(|| - color::Lcha::from(styles.get_color(theme::code::types::any::selection)) - ) + let opt_color = edge_type.map(|t|type_coloring::compute(&t,&styles)); + let neutral_color = color::Lcha::from(styles.get_color(theme::code::types::any::selection)); + let type_color = opt_color.unwrap_or(neutral_color); + match self.frp.mode.value() { + Mode::Normal => type_color, + Mode::Profiling => neutral_color + } } fn first_detached_edge(&self) -> Option { @@ -1941,6 +2061,9 @@ impl application::View for GraphEditor { , (Release , "" , "cmd left-mouse-button" , "edit_mode_off") , (Release , "" , "enter" , "stop_editing") + // === Profiling Mode === + , (Press , "" , "cmd p" , "toggle_profiling_mode") + // === Debug === , (Press , "debug_mode" , "ctrl d" , "debug_set_test_visualization_data_for_selected_node") , (Press , "debug_mode" , "ctrl shift enter" , "debug_push_breadcrumb") @@ -2555,6 +2678,20 @@ fn new_graph_editor(app:&Application) -> GraphEditor { } + // === Profiling === + + frp::extend! { network + + eval inputs.set_node_execution_status([model]((node_id,status)) { + if let Some(node) = model.nodes.get_cloned_ref(node_id) { + model.execution_statuses.set(*node_id,*status); + node.set_execution_status(status); + } + }); + + } + + // ================== // === Move Nodes === @@ -3042,6 +3179,29 @@ fn new_graph_editor(app:&Application) -> GraphEditor { eval quick_visualization_preview((value) model.nodes.set_quick_preview(*value)); } + + + // ============= + // === Modes === + // ============= + + frp::extend! { network + out.source.mode <+ frp.toggle_profiling_mode.map2(&frp.mode,|_,&mode| { + match mode { + Mode::Profiling => Mode::Normal, + _ => Mode::Profiling, + } + }); + + eval out.source.mode([model](_) { + for edge_id in model.edges.keys() { + model.refresh_edge_color(edge_id); + } + }); + } + + + GraphEditor {model,frp} } diff --git a/src/rust/ide/view/src/debug_scenes/interface.rs b/src/rust/ide/view/src/debug_scenes/interface.rs index ce9bd089b3..a85f14c507 100644 --- a/src/rust/ide/view/src/debug_scenes/interface.rs +++ b/src/rust/ide/view/src/debug_scenes/interface.rs @@ -8,6 +8,7 @@ use crate::prelude::*; use crate::graph_editor; use crate::graph_editor::GraphEditor; +use crate::graph_editor::NodeExecutionStatus; use crate::graph_editor::Type; use crate::project; use crate::status_bar; @@ -193,6 +194,16 @@ fn init(app:&Application) { }); + // === Profiling === + + let node1_status = NodeExecutionStatus::Finished { duration: 400.0 }; + graph_editor.set_node_execution_status(node1_id, node1_status); + let node2_status = NodeExecutionStatus::Finished { duration: 300.0 }; + graph_editor.set_node_execution_status(node2_id, node2_status); + let node3_status = NodeExecutionStatus::Finished { duration: 200.0 }; + graph_editor.set_node_execution_status(node3_id, node3_status); + + // let tgt_type = dummy_type_generator.get_dummy_type(); let mut was_rendered = false; let mut loader_hidden = false; From 4d352566e74d75bbc1170dc0214f30e7ad5aada2 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Thu, 6 May 2021 11:46:48 +0100 Subject: [PATCH 02/29] Include profiling shortcut in documentation --- docs/product/shortcuts.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/product/shortcuts.md b/docs/product/shortcuts.md index d46eb266cd..49527fdb4b 100644 --- a/docs/product/shortcuts.md +++ b/docs/product/shortcuts.md @@ -38,6 +38,7 @@ further investigation. | ctrl+q | Close the application (Linux) | | alt+F4 | Close the application (MacOS, Windows, Linux) | | ctrl+w | Close the application (Windows, Linux) | +| ctrl+p | Toggle profiling mode | #### Navigation @@ -107,6 +108,7 @@ further investigation. | meta + z | Zoom into selection if available in visualization. | + #### Debug | Shortcut | Action | | -------- | ------ | From 798defb639bdbdabd23c0dcad48dce163da6cb4b Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Thu, 6 May 2021 12:06:01 +0100 Subject: [PATCH 03/29] Display profiling indicators in front of edges --- .../graph-editor/src/component/node/profiling_indicator.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs index 5a500c2def..c896780b2c 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs @@ -98,6 +98,12 @@ impl ProfilingIndicator { let shape = shape::View::new(&logger); display_object.add_child(&shape); + ensogl::shapes_order_dependencies! { + app.display.scene() => { + crate::component::edge::front::corner -> shape; + crate::component::edge::front::line -> shape; + } + } let label = text::Area::new(app); display_object.add_child(&label); From c02c45e6c10c3efe51faf9e636bda835d5a231ca Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Thu, 6 May 2021 12:06:13 +0100 Subject: [PATCH 04/29] Fix formatting of CHANGELOG.md --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ef1f83115..46e3354963 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,6 @@ #### EnsoGL (rendering engine) -
![Bug Fixes](/docs/assets/tags/bug_fixes.svg) #### Visual Environment From 332d3cd5a36d99458429be47da90d045fee4773d Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Thu, 6 May 2021 12:28:08 +0100 Subject: [PATCH 05/29] Move definition of ExecutionStatuses --- src/rust/ide/view/graph-editor/src/lib.rs | 142 +++++++++++----------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index c704e11869..a68fc4fd7a 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -122,77 +122,6 @@ impl Default for Mode { -// ========================= -// === ExecutionStatuses === -// ========================= - -/// [`ExecutionsStatuses`] can be used to collect the execution statuses of all nodes in a graph. It -/// exposes their minimum and maximum running times through its FRP endpoints. The structure needs -/// to be updated whenever a node is added or deleted or changes its execution status. -mod execution_statuses { - use super::*; - use std::cmp::Ordering::Equal; - - ensogl::define_endpoints! { - Output { - min_duration (f32), - max_duration (f32), - } - } - - #[derive(Debug,Clone,CloneRef)] - pub struct ExecutionStatuses { - frp : Frp, - // If performance becomes an issue then we could try to store the durations in efficient - // priority queues instead, one to determine the minimum and one to determine the maximum. - durations : SharedHashMap - } - - impl Deref for ExecutionStatuses { - type Target = Frp; - - fn deref(&self) -> &Self::Target { - &self.frp - } - } - - impl ExecutionStatuses { - pub fn new() -> Self { - let frp = Frp::new(); - let durations = SharedHashMap::new(); - Self {frp,durations} - } - - pub fn set(&self,node:NodeId,status:NodeExecutionStatus) { - match status { - NodeExecutionStatus::Finished {duration} => self.durations.insert(node,duration), - _ => self.durations.remove(&node), - }; - self.update_min_max(); - } - - pub fn remove(&self,node:NodeId) { - self.durations.remove(&node); - self.update_min_max(); - } - - fn update_min_max(&self) { - let durations = self.durations.raw.borrow(); - // We need a custom compare function because `f32` does not implement `Ord`. - let cmp_f32 = |a:&&f32, b:&&f32| a.partial_cmp(&b).unwrap_or(Equal); - - let min = durations.values().min_by(cmp_f32).unwrap_or(&f32::INFINITY); - self.source.min_duration.emit(min); - - let max = durations.values().max_by(cmp_f32).unwrap_or(&0.0); - self.source.max_duration.emit(max); - } - } -} -pub use execution_statuses::ExecutionStatuses; - - - // ================= // === SharedVec === // ================= @@ -1038,6 +967,77 @@ impl Edges { +// ========================= +// === ExecutionStatuses === +// ========================= + +/// [`ExecutionsStatuses`] can be used to collect the execution statuses of all nodes in a graph. It +/// exposes their minimum and maximum running times through its FRP endpoints. The structure needs +/// to be updated whenever a node is added or deleted or changes its execution status. +mod execution_statuses { + use super::*; + use std::cmp::Ordering::Equal; + + ensogl::define_endpoints! { + Output { + min_duration (f32), + max_duration (f32), + } + } + + #[derive(Debug,Clone,CloneRef,Default)] + pub struct ExecutionStatuses { + frp : Frp, + // If performance becomes an issue then we could try to store the durations in efficient + // priority queues instead, one to determine the minimum and one to determine the maximum. + durations : SharedHashMap + } + + impl Deref for ExecutionStatuses { + type Target = Frp; + + fn deref(&self) -> &Self::Target { + &self.frp + } + } + + impl ExecutionStatuses { + pub fn new() -> Self { + let frp = Frp::new(); + let durations = SharedHashMap::new(); + Self {frp,durations} + } + + pub fn set(&self,node:NodeId,status:NodeExecutionStatus) { + match status { + NodeExecutionStatus::Finished {duration} => self.durations.insert(node,duration), + _ => self.durations.remove(&node), + }; + self.update_min_max(); + } + + pub fn remove(&self,node:NodeId) { + self.durations.remove(&node); + self.update_min_max(); + } + + fn update_min_max(&self) { + let durations = self.durations.raw.borrow(); + // We need a custom compare function because `f32` does not implement `Ord`. + let cmp_f32 = |a:&&f32, b:&&f32| a.partial_cmp(&b).unwrap_or(Equal); + + let min = durations.values().min_by(cmp_f32).unwrap_or(&f32::INFINITY); + self.source.min_duration.emit(min); + + let max = durations.values().max_by(cmp_f32).unwrap_or(&0.0); + self.source.max_duration.emit(max); + } + } +} +pub use execution_statuses::ExecutionStatuses; + + + #[derive(Debug,Clone,CloneRef,Default)] struct Visualisations { /// This keeps track of the currently selected visualisation. There should only ever be one From 54004d809fdbd74171b93c726354d5c3e6a86269 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Fri, 7 May 2021 09:18:08 +0100 Subject: [PATCH 06/29] Fix formatting --- .../view/graph-editor/src/component/node/profiling_indicator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs index c896780b2c..5c1b4553d8 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs @@ -191,4 +191,4 @@ impl display::Object for ProfilingIndicator { fn display_object(&self) -> &display::object::Instance { &self.display_object } -} \ No newline at end of file +} From 1214dc72af5ac401a6917fb4d6916e5b366eb35a Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Fri, 7 May 2021 13:45:10 +0100 Subject: [PATCH 07/29] Fix formatting Co-authored-by: Adam Obuchowicz --- src/rust/ide/view/graph-editor/src/component/node.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node.rs b/src/rust/ide/view/graph-editor/src/component/node.rs index 36e7199340..7440f2c927 100644 --- a/src/rust/ide/view/graph-editor/src/component/node.rs +++ b/src/rust/ide/view/graph-editor/src/component/node.rs @@ -396,7 +396,7 @@ pub struct NodeModel { impl NodeModel { /// Constructor. - pub fn new(app:&Application,registry:visualization::Registry) -> Self { + pub fn new(app:&Application, registry:visualization::Registry) -> Self { ensogl::shapes_order_dependencies! { app.display.scene() => { edge::back::corner -> backdrop; From dff8a4fb7428c52f996eefcddbe55bd943a0fdcc Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Fri, 7 May 2021 13:50:16 +0100 Subject: [PATCH 08/29] Fix formatting Co-authored-by: Adam Obuchowicz --- .../graph-editor/src/component/node/profiling_indicator.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs index 5c1b4553d8..1b8f0f3986 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs @@ -126,11 +126,7 @@ impl ProfilingIndicator { }); color.target_alpha <+ visibility.map(|&is_visible| { - if is_visible { - 1.0 - } else { - 0.0 - } + if is_visible { 1.0 } else { 0.0 } }); From e89a093dab37d996f25de4d0e12ce95fc87421c2 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Fri, 7 May 2021 14:22:45 +0100 Subject: [PATCH 09/29] Address some review comments --- docs/product/shortcuts.md | 2 +- .../src/component/node/input/area.rs | 31 +++++++++++-------- .../src/component/node/profiling_indicator.rs | 5 +-- src/rust/ide/view/graph-editor/src/lib.rs | 23 ++++++++------ 4 files changed, 34 insertions(+), 27 deletions(-) diff --git a/docs/product/shortcuts.md b/docs/product/shortcuts.md index 49527fdb4b..24eda05c87 100644 --- a/docs/product/shortcuts.md +++ b/docs/product/shortcuts.md @@ -38,7 +38,7 @@ further investigation. | ctrl+q | Close the application (Linux) | | alt+F4 | Close the application (MacOS, Windows, Linux) | | ctrl+w | Close the application (Windows, Linux) | -| ctrl+p | Toggle profiling mode | +| :warning: ctrl+p | Toggle profiling mode | #### Navigation diff --git a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs index 12a93f7cfa..a0e837b303 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs @@ -603,11 +603,12 @@ impl Area { pointer_style_over <- map4 (&mouse_over,&frp.set_ports_active,&port.tp,&frp.editor_mode, move |_,(_,edge_tp),port_tp,editor_mode| { - let tp = port_tp.as_ref().or_else(||edge_tp.as_ref()); - let color = tp.map(|tp| type_coloring::compute(tp,&styles)); - let color = color.unwrap_or(any_type_sel_color); let color = match editor_mode { - EditorMode::Normal => color, + EditorMode::Normal => { + let tp = port_tp.as_ref().or_else(||edge_tp.as_ref()); + let color = tp.map(|tp| type_coloring::compute(tp,&styles)); + color.unwrap_or(any_type_sel_color) + }, EditorMode::Profiling => any_type_sel_color }; cursor::Style::new_highlight(&port_shape_hover,padded_size,Some(color)) @@ -719,15 +720,19 @@ impl Area { new_viz_color <- all_with3 (&port_tp,&frp.set_connected,&self.editor_mode, f!([styles](port_tp,(is_connected,edge_tp),editor_mode) { - let tp = port_tp.as_ref().or_else(||edge_tp.as_ref()); - let color = select_color(&styles,tp); - let neutral_color_theme = theme::code::types::any::selection; - let neutral_color = styles.get_color(neutral_color_theme); - let color = match editor_mode { - EditorMode::Normal => color, - EditorMode::Profiling => neutral_color.into() - }; - if *is_connected {color} else { color::Lcha::transparent() } + if *is_connected { + match editor_mode { + EditorMode::Normal => { + let tp = port_tp.as_ref().or_else(||edge_tp.as_ref()); + select_color(&styles,tp) + }, + EditorMode::Profiling => { + styles.get_color(theme::code::types::any::selection).into() + } + } + } else { + color::Lcha::transparent() + } } )); viz_color.target <+ new_viz_color; diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs index 5c1b4553d8..45609ae505 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs @@ -119,10 +119,7 @@ impl ProfilingIndicator { // === Visibility === visibility <- all_with(&frp.set_editor_mode,&frp.set_execution_status,|mode,status| { - match (mode,status) { - (EditorMode::Profiling,ExecutionStatus::Finished {..}) => true, - _ => false, - } + matches!((mode,status),(EditorMode::Profiling,ExecutionStatus::Finished {..})) }); color.target_alpha <+ visibility.map(|&is_visible| { diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index a68fc4fd7a..7cc234f0f8 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -17,6 +17,7 @@ #![feature(unboxed_closures)] #![feature(vec_remove_item)] #![feature(weak_into_raw)] +#![feature(matches_macro)] #![warn(missing_copy_implementations)] #![warn(missing_debug_implementations)] @@ -61,7 +62,6 @@ use ensogl::gui::cursor; use ensogl::prelude::*; use ensogl::system::web; use ensogl_theme as theme; - use std::f32; @@ -108,7 +108,9 @@ fn traffic_lights_gap_width() -> f32 { // === Mode === // ============ -#[derive(Debug,Copy,Clone,CloneRef,PartialEq)] +/// Represents the current global mode of the graph editor. In profiling mode, edges should not be +/// colored and profiling information on nodes should become visible. +#[derive(Debug,Copy,Clone,CloneRef,PartialEq,Eq)] pub enum Mode { Normal, Profiling @@ -1931,15 +1933,18 @@ impl GraphEditorModel { fn edge_color(&self, edge_id:EdgeId) -> color::Lcha { // FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape system (#795) let styles = StyleWatch::new(&self.scene().style_sheet); - let edge_type = self.edge_hover_type() - .or_else(|| self.edge_target_type(edge_id)) - .or_else(|| self.edge_source_type(edge_id)); - let opt_color = edge_type.map(|t|type_coloring::compute(&t,&styles)); let neutral_color = color::Lcha::from(styles.get_color(theme::code::types::any::selection)); - let type_color = opt_color.unwrap_or(neutral_color); match self.frp.mode.value() { - Mode::Normal => type_color, - Mode::Profiling => neutral_color + Mode::Normal => { + let edge_type = self.edge_hover_type() + .or_else(|| self.edge_target_type(edge_id)) + .or_else(|| self.edge_source_type(edge_id)); + let opt_color = edge_type.map(|t|type_coloring::compute(&t,&styles)); + opt_color.unwrap_or(neutral_color) + }, + Mode::Profiling => { + color::Lcha::from(neutral_color) + } } } From 9e7e277761c3552dca54cc3e2a71e969e95b0cce Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Fri, 7 May 2021 15:42:06 +0100 Subject: [PATCH 10/29] Remove identical conversion --- src/rust/ide/view/graph-editor/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index 7cc234f0f8..8abef18f6d 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -1939,11 +1939,11 @@ impl GraphEditorModel { let edge_type = self.edge_hover_type() .or_else(|| self.edge_target_type(edge_id)) .or_else(|| self.edge_source_type(edge_id)); - let opt_color = edge_type.map(|t|type_coloring::compute(&t,&styles)); + let opt_color = edge_type.map(|t|type_coloring::compute(&t,&styles)); opt_color.unwrap_or(neutral_color) }, Mode::Profiling => { - color::Lcha::from(neutral_color) + neutral_color } } } From e264d8ff37a23560983bd11726cf28df11be5105 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Tue, 11 May 2021 10:24:15 +0100 Subject: [PATCH 11/29] Disable syntax highlighting in profiling mode --- .../ide/view/graph-editor/src/component/node/input/area.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs index a0e837b303..b3af6b46e2 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs @@ -679,7 +679,12 @@ impl Area { let styles = model.styles.clone_ref(); frp::extend! { port_network - base_color <- frp.tp.map(f!([styles](t) type_coloring::compute_for_code(t.as_ref(),&styles))); + base_color <- all_with(&self.editor_mode,&frp.tp,f!([styles](&mode,t) { + match mode { + EditorMode::Normal => type_coloring::compute_for_code(t.as_ref(),&styles), + EditorMode::Profiling => type_coloring::compute_for_code(None,&styles), + } + })); } if node.children.is_empty() { From cf84b4a40fa2ec6cc752441f79f1c6f64e048230 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Mon, 17 May 2021 00:12:01 +0100 Subject: [PATCH 12/29] Make requested changes --- src/rust/Cargo.lock | 11 ++ .../lib/components/src/toggle_button.rs | 3 +- .../lib/core/src/data/color/space/def.rs | 9 ++ .../lib/core/src/display/object/class.rs | 2 +- .../display/shape/primitive/def/primitive.rs | 35 ++++++ .../ensogl/lib/text/src/component/area.rs | 28 +++-- src/rust/ensogl/lib/theme/src/lib.rs | 12 ++ src/rust/ide/view/graph-editor/Cargo.toml | 2 + .../view/graph-editor/src/component/node.rs | 55 ++++++-- .../src/component/node/input/area.rs | 84 +++++++++---- .../src/component/node/profiling_indicator.rs | 78 ++---------- src/rust/ide/view/graph-editor/src/lib.rs | 119 +++++++++++++----- .../view/graph-editor/src/profiling_icon.rs | 56 +++++++++ src/rust/lib/frp/src/nodes.rs | 99 +++++++++++++-- 14 files changed, 442 insertions(+), 151 deletions(-) create mode 100644 src/rust/ide/view/graph-editor/src/profiling_icon.rs diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index fe0fd11237..b562eb23a0 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -1345,6 +1345,7 @@ version = "0.1.0" dependencies = [ "analytics 0.1.0", "ast 0.1.0", + "bimap 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "enso-args 0.1.0", "enso-frp 0.1.0", "enso-logger 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1359,6 +1360,7 @@ dependencies = [ "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", "nalgebra 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ordered-float 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", "span-tree 0.1.0", @@ -1900,6 +1902,14 @@ dependencies = [ "vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ordered-float" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot" version = "0.9.0" @@ -3368,6 +3378,7 @@ dependencies = [ "checksum openssl 0.10.30 (registry+https://github.com/rust-lang/crates.io-index)" = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-sys 0.9.58 (registry+https://github.com/rust-lang/crates.io-index)" = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de" +"checksum ordered-float 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7" "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum paste 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" diff --git a/src/rust/ensogl/lib/components/src/toggle_button.rs b/src/rust/ensogl/lib/components/src/toggle_button.rs index b7ef74bfe0..2c42e9331e 100644 --- a/src/rust/ensogl/lib/components/src/toggle_button.rs +++ b/src/rust/ensogl/lib/components/src/toggle_button.rs @@ -213,7 +213,7 @@ impl ToggleButton{ // === State === toggle <- any(frp.toggle,icon.mouse_down); - frp.source.state <+ toggle.toggle(); + frp.source.state <+ frp.state.not().sample(&toggle); frp.source.state <+ frp.set_state; @@ -242,6 +242,7 @@ impl ToggleButton{ eval color.value ((color) model.icon.set_color(color.into())); } + frp.set_state.emit(false); color.target_alpha.emit(0.0); self } diff --git a/src/rust/ensogl/lib/core/src/data/color/space/def.rs b/src/rust/ensogl/lib/core/src/data/color/space/def.rs index 67cf25ed23..56439c8c24 100644 --- a/src/rust/ensogl/lib/core/src/data/color/space/def.rs +++ b/src/rust/ensogl/lib/core/src/data/color/space/def.rs @@ -520,6 +520,15 @@ impl Lcha { pub fn to_javascript_string(&self) -> String { Rgba::from(self).to_javascript_string() } + + /// Convert the color to gray by setting chroma to zero. + pub fn desaturate(&self) -> Lcha { + let lightness = self.lightness; + let chroma = 0.0; + let hue = self.hue; + let alpha = self.alpha; + Lcha::new(lightness,chroma,hue,alpha) + } } diff --git a/src/rust/ensogl/lib/core/src/display/object/class.rs b/src/rust/ensogl/lib/core/src/display/object/class.rs index c57931e8c6..6d7e95c5dd 100644 --- a/src/rust/ensogl/lib/core/src/display/object/class.rs +++ b/src/rust/ensogl/lib/core/src/display/object/class.rs @@ -526,7 +526,7 @@ impl Model { // ========== /// Globally unique identifier of a display object. -#[derive(Clone,CloneRef,Copy,Debug,Default,Display,Eq,From,Hash,Into,PartialEq)] +#[derive(Clone,CloneRef,Copy,Debug,Default,Display,Eq,From,Hash,Into,PartialEq,Ord,PartialOrd)] pub struct Id(usize); diff --git a/src/rust/ensogl/lib/core/src/display/shape/primitive/def/primitive.rs b/src/rust/ensogl/lib/core/src/display/shape/primitive/def/primitive.rs index 6e0dc64779..05bd2da5bd 100644 --- a/src/rust/ensogl/lib/core/src/display/shape/primitive/def/primitive.rs +++ b/src/rust/ensogl/lib/core/src/display/shape/primitive/def/primitive.rs @@ -271,6 +271,41 @@ define_sdf_shapes! { float dist = max(abs(position).x*norm.x + position.y*norm.y - height/2.0*norm.y, pos_y); return bound_sdf(dist,bounding_box(width,height/2.0)); } + + + // === Uneven Capsule === + + /// An upright capsule shape with ends of independent width. In other words, the convex hull of + /// two circles where the radius of both circles can be chosen independently. The origin is at + /// the center of the lower circle. + /// + /// # Arguments + /// * `radius_top` - Radius of the top circle. + /// * `radius_bottom` - Radius of the bottom circle. + /// * `inner_height` - Distance between the centers of the two circles. + UnevenCapsule (radius_top:Pixels, radius_bottom:Pixels, inner_height:Pixels) { + position.x = abs(position.x); + float b = (radius_bottom-radius_top) / inner_height; + float a = sqrt(1.0-b*b); + float k = dot(position,vec2(-b,a)); + float dist; + if (k < 0.0) { + dist = length(position) - radius_bottom; + } else if (k > a * inner_height) { + dist = length(position-vec2(0.0,inner_height)) - radius_top; + } else { + dist = dot(position,vec2(a,b)) - radius_bottom; + } + + float max_radius = max(radius_top,radius_bottom); + float min_x = -max_radius; + float max_x = max_radius; + float min_y = -radius_bottom; + float max_y = inner_height + radius_top; + BoundingBox bounds = bounding_box(min_x,max_x,min_y,max_y); + + return bound_sdf(dist,bounds); + } } diff --git a/src/rust/ensogl/lib/text/src/component/area.rs b/src/rust/ensogl/lib/text/src/component/area.rs index df79fd5204..5f1fc5f52b 100644 --- a/src/rust/ensogl/lib/text/src/component/area.rs +++ b/src/rust/ensogl/lib/text/src/component/area.rs @@ -25,7 +25,6 @@ use ensogl_core::display; use ensogl_core::gui::cursor; use ensogl_core::system::gpu::shader::glsl::traits::IntoGlsl; use ensogl_core::system::web::clipboard; -use ensogl_theme as theme; use std::ops::Not; @@ -84,7 +83,7 @@ const BLINK_PERIOD : f32 = pub mod selection { use super::*; ensogl_core::define_shape_system! { - (style:Style, selection:f32, start_time:f32, letter_width:f32) { + (style:Style, selection:f32, start_time:f32, letter_width:f32, color_rgb:Vector3) { let width_abs = Var::::from("abs(input_size.x)"); let height = Var::::from("input_size.y"); let rect_width = width_abs - 2.0 * CURSOR_PADDING; @@ -103,9 +102,7 @@ pub mod selection { let alpha = alpha_weight.mix(blinking_alpha,SELECTION_ALPHA); let shape = Rect((1.px() * rect_width,1.px() * rect_height)); let shape = shape.corners_radius(SELECTION_CORNER_RADIUS.px()); - let color = style.get_color(theme::code::syntax::selection); - let color = format!("srgba({},{},{},{})",color.red.glsl(),color.green.glsl() - ,color.blue.glsl(),alpha.glsl()); + let color = format!("srgba({}.x,{}.y,{}.z,{})",color_rgb,color_rgb,color_rgb,alpha.glsl()); let shape = shape.fill(color); shape.into() } @@ -135,6 +132,7 @@ pub struct Selection { position : DEPRECATED_Animation, width : DEPRECATED_Animation, edit_mode : Rc>, + set_color : frp::Any, } impl Deref for Selection { @@ -155,13 +153,14 @@ impl Selection { let position = DEPRECATED_Animation::new(&network); let width = DEPRECATED_Animation::new(&network); let edit_mode = Rc::new(Cell::new(edit_mode)); + let set_color = network.any_mut::("set_color"); let debug = false; // Change to true to slow-down movement for debug purposes. let spring_factor = if debug { 0.1 } else { 1.5 }; position . update_spring (|spring| spring * spring_factor); width . update_spring (|spring| spring * spring_factor); - Self {logger,display_object,right_side,shape_view,network,position,width,edit_mode} . init() + Self {logger,display_object,right_side,shape_view,network,position,width,edit_mode,set_color} . init() } fn init(self) -> Self { @@ -169,6 +168,7 @@ impl Selection { let view = &self.shape_view; let object = &self.display_object; let right_side = &self.right_side; + let shape_view = &self.shape_view; self.add_child(view); view.add_child(right_side); frp::extend! { network @@ -187,6 +187,7 @@ impl Selection { view.set_position_xy(Vector2(view_x,view_y)); }) ); + eval self.set_color((color) shape_view.color_rgb.set(color.into())); } self } @@ -421,15 +422,17 @@ ensogl_core::define_endpoints! { set_color_bytes (buffer::Range,color::Rgba), set_color_all (color::Rgba), set_default_color (color::Rgba), + set_selection_color (color::Rgb), set_default_text_size (style::Size), set_content (String), } Output { - pointer_style (cursor::Style), - width (f32), - changed (Vec), - content (Text), - hovered (bool), + pointer_style (cursor::Style), + width (f32), + changed (Vec), + content (Text), + hovered (bool), + selection_color (color::Rgb), } } @@ -644,6 +647,7 @@ impl Area { m.buffer.frp.set_color_bytes.emit(*t); m.redraw(false); }); + self.frp.source.selection_color <+ self.frp.set_selection_color; // === Changes === @@ -802,7 +806,9 @@ impl AreaModel { // animation frame. Multiple times, once per cursor. // https://github.com/enso-org/ide/issues/1031 eval_ selection.position.value (model.redraw(true)); + selection.set_color <+ self.frp_endpoints.selection_color; } + selection.set_color.emit(self.frp_endpoints.selection_color.value()); selection } }; diff --git a/src/rust/ensogl/lib/theme/src/lib.rs b/src/rust/ensogl/lib/theme/src/lib.rs index e4c68fc9e9..8797b8216b 100644 --- a/src/rust/ensogl/lib/theme/src/lib.rs +++ b/src/rust/ensogl/lib/theme/src/lib.rs @@ -242,6 +242,12 @@ define_themes! { [light:0, dark:1] disabled = Lcha(0.7,0.0,0.0,1.0) , Lcha(1.0,0.0,0.0,0.2); expected = Lcha(0.7,0.0,0.0,1.0) , Lcha(1.0,0.0,0.0,0.3); selection = Lcha(0.7,0.0,0.125,0.7) , Lcha(0.7,0.0,0.125,0.7); + profiling { + base = Lcha(1.0,0.0,0.0,0.9) , Lcha(0.0,0.0,0.0,0.7); + disabled = Lcha(1.0,0.0,0.0,0.5) , Lcha(0.0,0.0,0.0,0.2); + expected = Lcha(1.0,0.0,0.0,0.5) , Lcha(0.0,0.0,0.0,0.3); + selection = Lcha(1.0,0.0,0.0,1.0) , Lcha(0.0,0.0,0.0,1.0); + } } types { hue_steps = 512.0 , 512.0; @@ -364,6 +370,12 @@ define_themes! { [light:0, dark:1] chroma_factor = 0.8 , 1.0; } } + profiling_button { + non_toggled = graph_editor::node::actions::button::non_toggled , graph_editor::node::actions::button::non_toggled; + toggled = Lcha(0.7,0.5,0.12,1.0) , Lcha(0.7,0.5,0.12,1.0); + hovered = graph_editor::node::actions::button::hovered , graph_editor::node::actions::button::hovered; + toggled_hovered = Lcha(0.55,0.5,0.12,1.0) , Lcha(0.85,0.5,0.12,1.0); + } } widget { list_view { diff --git a/src/rust/ide/view/graph-editor/Cargo.toml b/src/rust/ide/view/graph-editor/Cargo.toml index e77fee6523..6f94a12d63 100644 --- a/src/rust/ide/view/graph-editor/Cargo.toml +++ b/src/rust/ide/view/graph-editor/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] analytics = { version = "0.1.0", path = "../../lib/analytics" } ast = { version = "0.1.0", path = "../../lib/ast/impl" } +bimap = { version = "0.4.0"} enso-args = { version = "0.1.0", path = "../../lib/args" } enso-frp = { version = "0.1.0", path = "../../../lib/frp" } enso-logger = { version = "0.2.2" } @@ -22,6 +23,7 @@ ensogl-text = { version = "0.1.0", path = "../../../ensogl/lib/text" } ensogl-text-msdf-sys = { version = "0.1.0", path = "../../../ensogl/lib/text/msdf-sys" } ensogl-theme = { version = "0.1.0", path = "../../../ensogl/lib/theme" } failure = { version = "0.1.8" } +ordered-float = {version = "1.0"} span-tree = { version = "0.1.0", path = "../../lib/span-tree" } js-sys = { version = "0.3.28" } nalgebra = { version = "0.21.1", features = ["serde-serialize"] } diff --git a/src/rust/ide/view/graph-editor/src/component/node.rs b/src/rust/ide/view/graph-editor/src/component/node.rs index 7440f2c927..1818a8c5fb 100644 --- a/src/rust/ide/view/graph-editor/src/component/node.rs +++ b/src/rust/ide/view/graph-editor/src/component/node.rs @@ -19,7 +19,7 @@ pub use expression::Expression; use crate::prelude::*; -use profiling_indicator::ProfilingIndicator; +use crate::component::node::profiling_indicator::ProfilingIndicator; use crate::Mode as EditorMode; use crate::component::visualization; use crate::tooltip; @@ -624,7 +624,10 @@ impl Node { model.input.set_editor_mode <+ frp.set_editor_mode; model.profiling_indicator.set_editor_mode <+ frp.set_editor_mode; - } + model.vcs_indicator.set_visibility <+ frp.set_editor_mode.map(|&mode| { + !matches!(mode,EditorMode::Profiling {..}) + }); + } // === Visualizations & Errors === @@ -638,9 +641,12 @@ impl Node { frp.source.error <+ frp.set_error; is_error_set <- frp.error.map(|err| err.is_some()); no_error_set <- not(&is_error_set); - error_color_anim.target <+ frp.error.map(f!([style](error) - Self::error_color(error,&style)) - ); + error_color_anim.target <+ all_with(&frp.error,&frp.set_editor_mode,f!([style](error,&mode) + match mode { + EditorMode::Normal => Self::error_color(error,&style), + EditorMode::Profiling => Self::error_color(error,&style).desaturate(), + } + )); eval frp.set_visualization ((t) model.visualization.frp.set_visualization.emit(t)); visualization_enabled_frp <- bool(&frp.disable_visualization,&frp.enable_visualization); @@ -708,8 +714,10 @@ impl Node { model.profiling_indicator.set_max_global_duration <+ frp.set_profiling_max_global_duration; model.profiling_indicator.set_execution_status <+ frp.set_execution_status; + model.input.set_execution_status <+ frp.set_execution_status; } + let bg_color_anim = color::Animation::new(network); frp::extend! { network @@ -717,9 +725,36 @@ impl Node { let bgg = style_frp.get_color(ensogl_theme::graph_editor::node::background); - bg_color <- all_with(&bgg,&frp.set_disabled,f!([model](bgg,disabled) { - model.input.frp.set_disabled(*disabled); - *bgg + let profiling_theme = ensogl_theme::graph_editor::node::profiling::HERE.path(); + let profiling_lightness = style_frp.get_number_or(profiling_theme.sub("lightness"),0.72); + let profiling_chroma = style_frp.get_number_or(profiling_theme.sub("chroma"),0.7); + let profiling_min_hue = style_frp.get_number_or(profiling_theme.sub("min_hue"),0.38); + let profiling_max_hue = style_frp.get_number_or(profiling_theme.sub("max_hue"),0.07); + + profiling_color <- all_with8 + (&frp.set_execution_status,&frp.set_profiling_min_global_duration, + &frp.set_profiling_max_global_duration,&profiling_lightness,&profiling_chroma, + &profiling_min_hue,&profiling_max_hue,&bgg, + |&status,&min,&max,&lightness,&chroma,&min_hue,&max_hue,&bgg| { + match status { + ExecutionStatus::Running => color::Lcha::from(bgg), + ExecutionStatus::Finished {duration} => { + let hue_delta = max_hue - min_hue; + let relative_duration = (duration - min) / (max - min); + let hue = min_hue + relative_duration * hue_delta; + let alpha = 1.0; + color::Lcha::new(lightness,chroma,hue,alpha) + } + } + }); + + bg_color_anim.target <+ all_with4(&bgg,&frp.set_disabled,&frp.set_editor_mode,&profiling_color, + f!([model](bgg,disabled,&mode,profiling_color) { + model.input.frp.set_disabled(*disabled); + match mode { + EditorMode::Normal => color::Lcha::from(*bgg), + EditorMode::Profiling => *profiling_color, + } })); // FIXME [WD]: Uncomment when implementing disabled icon. @@ -734,7 +769,7 @@ impl Node { // model.background.bg_color.set(color::Rgba::from(c).into()) // ); - eval bg_color ((c) model.background.bg_color.set(c.into())); + eval bg_color_anim.value ((c) model.background.bg_color.set(color::Rgba::from(c).into())); // === Tooltip === @@ -761,7 +796,7 @@ impl Node { if let Some(error) = error { let path = match *error.kind { - error::Kind::Panic => error_theme::panic, + error::Kind::Panic => error_theme::panic, error::Kind::Dataflow => error_theme::dataflow, }; style.get_color(path).into() diff --git a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs index b3af6b46e2..5ee8377694 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs @@ -10,6 +10,7 @@ use ensogl::data::color; use ensogl::display::scene::Scene; use ensogl::display::shape::*; use ensogl::display::traits::*; +use ensogl::Animation; use ensogl::display; use ensogl::gui::cursor; use ensogl_text as text; @@ -20,6 +21,7 @@ use text::Text; use crate::Type; use crate::component::type_coloring; use crate::node::input::port; +use crate::node::ExecutionStatus; use crate::node; use crate::Mode as EditorMode; @@ -195,7 +197,8 @@ ensogl::define_endpoints! { /// types are polymorphic. set_ports_active (bool,Option), - set_editor_mode(EditorMode), + set_editor_mode (EditorMode), + set_execution_status (ExecutionStatus), } Output { @@ -322,9 +325,10 @@ impl Deref for Area { impl Area { pub fn new(logger:impl AnyLogger, app:&Application) -> Self { - let model = Rc::new(Model::new(logger,app)); - let frp = Frp::new(); - let network = &frp.network; + let model = Rc::new(Model::new(logger,app)); + let frp = Frp::new(); + let network = &frp.network; + let selection_color = Animation::new(network); frp::extend! { network @@ -395,6 +399,14 @@ impl Area { // === Editor Mode === frp.output.source.editor_mode <+ frp.set_editor_mode; + selection_color.target <+ frp.editor_mode.map(f!([model](&mode) { + let path = match mode { + EditorMode::Normal => theme::code::syntax::selection, + EditorMode::Profiling => theme::code::syntax::profiling::selection, + }; + color::Lch::from(model.styles.get_color(path)) + })); + model.label.set_selection_color <+ selection_color.value.map(|&c| color::Rgb::from(c)); } Self {model,frp} @@ -641,9 +653,6 @@ impl Area { /// this way, rather than delegate it to every port. fn init_port_frp_on_new_expression(&self, expression:&mut Expression) { let model = &self.model; - let selected_color = color::Lcha::from(model.styles.get_color(theme::code::types::selected)); - let disabled_color = color::Lcha::from(model.styles.get_color(theme::code::syntax::disabled)); - let expected_color = color::Lcha::from(model.styles.get_color(theme::code::syntax::expected)); let parent_tp : Option>> = None; expression.root_ref_mut().dfs_with_layer_data(parent_tp,|node,parent_tp| { @@ -679,34 +688,65 @@ impl Area { let styles = model.styles.clone_ref(); frp::extend! { port_network - base_color <- all_with(&self.editor_mode,&frp.tp,f!([styles](&mode,t) { - match mode { - EditorMode::Normal => type_coloring::compute_for_code(t.as_ref(),&styles), - EditorMode::Profiling => type_coloring::compute_for_code(None,&styles), - } - })); + base_color <- all_with3(&self.editor_mode,&self.set_execution_status,&frp.tp, + f!([styles](&mode,&status,t) { + match (mode,status) { + (EditorMode::Normal,_) => + type_coloring::compute_for_code(t.as_ref(),&styles), + (EditorMode::Profiling,ExecutionStatus::Running) => + color::Lcha::from(styles.get_color(theme::code::syntax::base)), + (EditorMode::Profiling,ExecutionStatus::Finished {..}) => + color::Lcha::from(styles.get_color(theme::code::syntax::profiling::base)), + } + }) + ); } if node.children.is_empty() { let is_expected_arg = node.is_expected_argument(); - let label_color = color::Animation::new(port_network); frp::extend! { port_network is_selected <- frp.set_hover || frp.set_parent_connected; - text_color_tgt <- all_with3(&base_color,&is_selected,&self.frp.set_disabled, - move |base_color,is_selected,is_disabled| { - if *is_selected { selected_color } - else if *is_disabled { disabled_color } + text_color_tgt <- all_with5(&is_selected,&self.frp.set_disabled, + &self.editor_mode,&self.set_execution_status,&base_color, + f!([styles](&is_selected,&is_disabled,&mode,&status,&base_color) { + let path = match (mode, status) { + (EditorMode::Profiling, ExecutionStatus::Finished {..}) => + theme::code::syntax::profiling::HERE.path(), + _ => + theme::code::syntax::HERE.path(), + }; + let selected_rgba = styles.get_color(theme::code::types::selected); + let disabled_rgba = styles.get_color(path.sub("disabled")); + let expected_rgba = styles.get_color(path.sub("expected")); + let selected_color = color::Lcha::from(selected_rgba); + let disabled_color = color::Lcha::from(disabled_rgba); + let expected_color = color::Lcha::from(expected_rgba); + if is_selected { selected_color } + else if is_disabled { disabled_color } else if is_expected_arg { expected_color } - else { *base_color } - }); - label_color.target <+ text_color_tgt; + else { base_color } + })); + editing_color <- all_with(&self.editor_mode,&self.set_execution_status, + f!([styles](&mode,&status) { + let path = match (mode,status) { + (EditorMode::Profiling,ExecutionStatus::Finished {..}) => + theme::code::syntax::profiling::base, + _ => + theme::code::syntax::base, + }; + color::Lcha::from(styles.get_color(path)) + })); + // Fixme: `label_color` should be animated, when when we can set text colors + // more efficiently. (See https://github.com/enso-org/ide/issues/1031) + label_color <- self.set_edit_mode.switch(&text_color_tgt,&editing_color); } let index = node.payload.index; let length = node.payload.length; let label = model.label.clone_ref(); frp::extend! { port_network - eval label_color.value ([label](color) { + set_color <- all_with(&label_color,&self.set_edit_mode,|&color, _| color); + eval set_color ([label](color) { let start_bytes = (index as i32).bytes(); let end_bytes = ((index + length) as i32).bytes(); let range = ensogl_text::buffer::Range::from(start_bytes..end_bytes); diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs index 9927193417..010d3f47b6 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs @@ -13,42 +13,11 @@ use ensogl::gui::text; -// ============= -// === Shape === -// ============= - -mod shape { - use super::*; - - pub const WIDTH_OUTER : f32 = 15.0; - pub const WIDTH_INNER : f32 = 10.0; - pub const THICKNESS : f32 = WIDTH_OUTER - WIDTH_INNER; - pub const LABEL_GAP_PADDING : f32 = 5.0; - pub const LABEL_GAP_HEIGHT : f32 = 16.0; - - ensogl::define_shape_system! { - (style:Style,color_rgba:Vector4,label_width:f32) { - let width = Var::::from("input_size.x"); - let height = Var::::from("input_size.y"); - let width = width - node::PADDING.px() * 2.0; - let height = height - node::PADDING.px() * 2.0; - let radius = node::RADIUS.px(); - - let base = Rect((&width,&height)).corners_radius(&radius); - let outer = base.grow(WIDTH_OUTER.px()); - let inner = base.grow(WIDTH_INNER.px()); - let outline = outer - inner; - - let upper_center_y = height / 2.0 + WIDTH_INNER.px() + THICKNESS.px() / 2.0; - let label_gap_width = label_width * 1.px() + LABEL_GAP_PADDING.px() * 2.0; - let label_gap = Rect((&label_gap_width,LABEL_GAP_HEIGHT.px())); - let label_gap = label_gap.corners_radius(LABEL_GAP_PADDING.px()); - let label_gap = label_gap.translate_y(upper_center_y); - - (outline-label_gap).fill(color_rgba).into() - } - } -} +// ================= +// === Constants === +// ================= + +const LABEL_OFFSET_Y: f32 = 20.0; @@ -74,8 +43,6 @@ ensogl::define_endpoints! { #[derive(Clone,CloneRef,Debug)] pub struct ProfilingIndicator { - display_object : display::object::Instance, - shape : shape::View, label : text::Area, frp : Frp } @@ -93,20 +60,9 @@ impl ProfilingIndicator { pub fn new(app: &Application) -> Self { let scene = app.display.scene(); let styles = StyleWatch::new(&scene.style_sheet); - let logger = Logger::new("ProfilingIndicator"); - let display_object = display::object::Instance::new(&logger); - - let shape = shape::View::new(&logger); - display_object.add_child(&shape); - ensogl::shapes_order_dependencies! { - app.display.scene() => { - crate::component::edge::front::corner -> shape; - crate::component::edge::front::line -> shape; - } - } let label = text::Area::new(app); - display_object.add_child(&label); + label.set_position_y(LABEL_OFFSET_Y); label.remove_from_scene_layer_DEPRECATED(&scene.layers.main); label.add_to_scene_layer_DEPRECATED(&scene.layers.label); @@ -149,39 +105,31 @@ impl ProfilingIndicator { } }) ); + label.set_default_color <+ color.value.map(|c| c.into()); + label.set_color_all <+ color.value.map(|c| c.into()); - // === Shape === + // === Position === - eval frp.set_size((size) shape.size.set(*size)); - eval label.width((&width) shape.label_width.set(width)); - eval color.value((&color) shape.color_rgba.set(color::Rgba::from(color).into())); + eval label.width((&width) label.set_position_x(-width/2.0)); - // === Label === + // === Content === - eval frp.set_size([label](size) { - let height = size.y - node::PADDING * 2.0; - let upper_center_y = height / 2.0 + shape::WIDTH_INNER + shape::THICKNESS / 2.0; - label.set_position_y(upper_center_y + text::area::LINE_HEIGHT / 2.0) - }); - eval label.width((&width) label.set_position_x(-width/2.0)); label.set_content <+ frp.set_execution_status.map(|&status| match status { ExecutionStatus::Running => "Running".to_string(), ExecutionStatus::Finished {duration} => format!("{} ms", duration) }); - label.set_default_color <+ color.value.map(|c| c.into()); - label.set_color_all <+ color.value.map(|c| c.into()); } - ProfilingIndicator {display_object,shape,label,frp} + ProfilingIndicator {label,frp} } } impl display::Object for ProfilingIndicator { fn display_object(&self) -> &display::object::Instance { - &self.display_object + &self.label.display_object() } } diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index 8abef18f6d..560d5f9be2 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -34,6 +34,7 @@ pub mod component; pub mod builtin; pub mod data; +mod profiling_icon; use crate::component::node; pub use crate::component::node::ExecutionStatus as NodeExecutionStatus; @@ -59,6 +60,8 @@ use ensogl::display::object::Id; use ensogl::display::shape::StyleWatch; use ensogl::display; use ensogl::gui::cursor; +use ensogl_gui_components::toggle_button; +use ensogl_gui_components::toggle_button::ToggleButton; use ensogl::prelude::*; use ensogl::system::web; use ensogl_theme as theme; @@ -610,7 +613,7 @@ pub struct Node { pub out_edges : SharedHashSet, } -#[derive(Clone,CloneRef,Copy,Debug,Default,Eq,From,Hash,Into,PartialEq)] +#[derive(Clone,CloneRef,Copy,Debug,Default,Eq,From,Hash,Into,PartialEq,Ord,PartialOrd)] pub struct NodeId(pub Id); impl Node { @@ -977,10 +980,16 @@ impl Edges { /// exposes their minimum and maximum running times through its FRP endpoints. The structure needs /// to be updated whenever a node is added or deleted or changes its execution status. mod execution_statuses { + use bimap::BiBTreeMap; + use ordered_float::OrderedFloat; + use super::*; - use std::cmp::Ordering::Equal; ensogl::define_endpoints! { + Input { + set (NodeId, NodeExecutionStatus), + remove (NodeId) + } Output { min_duration (f32), max_duration (f32), @@ -990,9 +999,7 @@ mod execution_statuses { #[derive(Debug,Clone,CloneRef,Default)] pub struct ExecutionStatuses { frp : Frp, - // If performance becomes an issue then we could try to store the durations in efficient - // priority queues instead, one to determine the minimum and one to determine the maximum. - durations : SharedHashMap + durations : Rc>>> } impl Deref for ExecutionStatuses { @@ -1006,38 +1013,44 @@ mod execution_statuses { impl ExecutionStatuses { pub fn new() -> Self { let frp = Frp::new(); - let durations = SharedHashMap::new(); - Self {frp,durations} - } - - pub fn set(&self,node:NodeId,status:NodeExecutionStatus) { - match status { - NodeExecutionStatus::Finished {duration} => self.durations.insert(node,duration), - _ => self.durations.remove(&node), - }; - self.update_min_max(); - } + let durations = Rc::new(RefCell::new(BiBTreeMap::>::new())); + + let network = &frp.network; + frp::extend! { network + min_and_max_from_set <- frp.set.map(f!([durations]((node,status)) { + match status { + NodeExecutionStatus::Finished {duration} => { + durations.borrow_mut().insert(*node,OrderedFloat(*duration)); + }, + _ => { + durations.borrow_mut().remove_by_left(node); + }, + }; + Self::min_and_max(&*durations.borrow()) + })); + + min_and_max_from_remove <- frp.remove.map(f!([durations](node) { + durations.borrow_mut().remove_by_left(&node); + Self::min_and_max(&*durations.borrow()) + })); + + min_and_max <- any(&min_and_max_from_set,&min_and_max_from_remove); + frp.source.min_duration <+ min_and_max._0().on_change(); + frp.source.max_duration <+ min_and_max._1().on_change(); + } - pub fn remove(&self,node:NodeId) { - self.durations.remove(&node); - self.update_min_max(); + Self {frp,durations} } - fn update_min_max(&self) { - let durations = self.durations.raw.borrow(); - // We need a custom compare function because `f32` does not implement `Ord`. - let cmp_f32 = |a:&&f32, b:&&f32| a.partial_cmp(&b).unwrap_or(Equal); - - let min = durations.values().min_by(cmp_f32).unwrap_or(&f32::INFINITY); - self.source.min_duration.emit(min); - - let max = durations.values().max_by(cmp_f32).unwrap_or(&0.0); - self.source.max_duration.emit(max); + fn min_and_max(durations:&BiBTreeMap>) -> (f32,f32) { + let mut durations = durations.right_values().copied(); + let min = durations.next().map(OrderedFloat::into_inner).unwrap_or(f32::INFINITY); + let max = durations.last().map(OrderedFloat::into_inner).unwrap_or(0.0); + (min, max) } } } -pub use execution_statuses::ExecutionStatuses; - +use execution_statuses::ExecutionStatuses; #[derive(Debug,Clone,CloneRef,Default)] @@ -1264,6 +1277,7 @@ impl GraphEditorModelWithNetwork { node.set_profiling_max_global_duration <+ self.model.execution_statuses.max_duration; node.set_profiling_max_global_duration(self.model.execution_statuses.max_duration.value()); } + node.set_editor_mode(self.model.frp.mode.value()); let initial_metadata = visualization::Metadata { preprocessor : node.model.visualization.frp.preprocessor.value() }; @@ -1370,6 +1384,7 @@ pub struct GraphEditorModel { frp : FrpEndpoints, navigator : Navigator, execution_statuses : ExecutionStatuses, + profiling_button : ToggleButton, } @@ -1396,10 +1411,11 @@ impl GraphEditorModel { let navigator = Navigator::new(&scene,&scene.camera()); let tooltip = Tooltip::new(&app); let execution_statuses = ExecutionStatuses::new(); + let profiling_button = ToggleButton::::new(&logger); Self { logger,display_object,app,cursor,nodes,edges,touch_state,frp,breadcrumbs, - vis_registry,visualisations,navigator,tooltip,execution_statuses, + vis_registry,visualisations,navigator,tooltip,execution_statuses,profiling_button, }.init() } @@ -1411,6 +1427,22 @@ impl GraphEditorModel { self.breadcrumbs.set_position_y(y_offset); self.breadcrumbs.gap_width(traffic_lights_gap_width()); self.scene().add_child(&self.tooltip); + + self.add_child(&self.profiling_button); + self.scene().layers.breadcrumbs_background.add_exclusive(&self.profiling_button); + self.profiling_button.set_visibility(true); + self.profiling_button.set_size(Vector2(32.0,32.0)); + + let styles = StyleWatch::new(&self.scene().style_sheet); + let color_scheme = toggle_button::ColorScheme { + non_toggled : Some(styles.get_color(theme::graph_editor::profiling_button::non_toggled).into()), + toggled : Some(styles.get_color(theme::graph_editor::profiling_button::toggled).into()), + hovered : Some(styles.get_color(theme::graph_editor::profiling_button::hovered).into()), + toggled_hovered : Some(styles.get_color(theme::graph_editor::profiling_button::toggled_hovered).into()), + ..default() + }; + self.profiling_button.set_color_scheme(&color_scheme); + self } @@ -1921,7 +1953,9 @@ impl GraphEditorModel { /// Return a color for the edge. /// - /// The algorithm works as follow: + /// In profiling mode, this is just a neutral gray. + /// + /// In normal mode, the algorithm works as follow: /// 1. We query the type of the currently hovered port, if any. /// 2. In case the previous point returns None, we query the edge target type, if any. /// 3. In case the previous point returns None, we query the edge source type, if any. @@ -3222,6 +3256,25 @@ fn new_graph_editor(app:&Application) -> GraphEditor { } + // === Profiling Button === + + frp::extend! { network + out.source.mode <+ model.profiling_button.state.map(|&toggled| { + if toggled { Mode::Profiling } else { Mode::Normal } + }); + + model.profiling_button.set_state <+ out.mode.on_change().map(|&mode| { + matches!(mode,Mode::Profiling) + }); + + eval scene.frp.camera_changed([model,scene](_) { + let screen = scene.camera().screen(); + model.profiling_button.set_position_x(screen.width/2.0 - 16.0); + model.profiling_button.set_position_y(screen.height/2.0 - 16.0); + }); + } + + GraphEditor {model,frp} } diff --git a/src/rust/ide/view/graph-editor/src/profiling_icon.rs b/src/rust/ide/view/graph-editor/src/profiling_icon.rs new file mode 100644 index 0000000000..c074ed7254 --- /dev/null +++ b/src/rust/ide/view/graph-editor/src/profiling_icon.rs @@ -0,0 +1,56 @@ +use crate::prelude::*; + +use ensogl::data::color; +use ensogl::display::shape::*; +use ensogl_gui_components::toggle_button::ColorableShape; + +ensogl::define_shape_system! { + (color_rgba:Vector4) { + let fill_color = Var::::from(color_rgba); + let width = Var::::from("input_size.x"); + let height = Var::::from("input_size.y"); + + let unit = &width * 0.3; + let outer_circle_radius = &unit * 1.0; + let outer_circle_thickness = &unit * 0.33; + let inner_circle_radius = &unit * 0.2; + let needle_radius_inner = &unit * 0.14; + let needle_radius_outer = &unit * 0.09; + let needle_angle = (135.0_f32).to_radians().radians(); + + let base = Circle(&outer_circle_radius); + let circle_gap = Circle(&outer_circle_radius-&outer_circle_thickness); + + // We make the gap a little bit larger than the circle to be sure that we really cover + // everything that we want to cut, even if there are rounding errors or similar + // imprecisions. + let aperture_gap_size = &outer_circle_radius * 1.1; + let aperture_gap = Triangle(&aperture_gap_size*2.0,aperture_gap_size.clone()); + let aperture_gap = aperture_gap.rotate(&needle_angle+180.0_f32.to_radians().radians()); + let aperture_gap = aperture_gap.translate_x(&aperture_gap_size*2.0.sqrt()*0.25); + let aperture_gap = aperture_gap.translate_y(-(&aperture_gap_size*2.0.sqrt()*0.25)); + + let aperture_cap_1 = Circle(&outer_circle_thickness*0.5); + let aperture_cap_1 = aperture_cap_1.translate_x(&outer_circle_radius-&outer_circle_thickness*0.5); + let aperture_cap_2 = Circle(&outer_circle_thickness*0.5); + let aperture_cap_2 = aperture_cap_2.translate_y(-(&outer_circle_radius-&outer_circle_thickness*0.5)); + + let outer_circle = base - circle_gap - aperture_gap + aperture_cap_1 + aperture_cap_2; + + let needle_length = &outer_circle_radius-&needle_radius_outer; + let needle = UnevenCapsule(needle_radius_outer.clone(),needle_radius_inner.clone(),needle_length.clone()); + let needle = needle.rotate(&needle_angle); + + let inner_circle = Circle(&inner_circle_radius); + + let shape = (outer_circle + needle + inner_circle).fill(fill_color); + let hover_area = Rect((&width,&height)).fill(HOVER_COLOR); + (shape + hover_area).into() + } +} + +impl ColorableShape for DynamicShape { + fn set_color(&self, color:color::Rgba) { + self.color_rgba.set(Vector4::new(color.red,color.green,color.blue,color.alpha)); + } +} \ No newline at end of file diff --git a/src/rust/lib/frp/src/nodes.rs b/src/rust/lib/frp/src/nodes.rs index 3ee22f1bb1..560a2c9448 100644 --- a/src/rust/lib/frp/src/nodes.rs +++ b/src/rust/lib/frp/src/nodes.rs @@ -494,10 +494,19 @@ impl Network { /// Specialized version `all_with`. pub fn all_with5 (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, f:F) -> Stream - where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, - T:Data, F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->T { + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T:Data, F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->T { self.register(OwnedAllWith5::new(label,t1,t2,t3,t4,t5,f)) } + + /// Specialized version `all_with`. + pub fn all_with8 + (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, t6:&T6, t7:&T7, t8:&T8, f:F) -> Stream + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, T7:EventOutput, T8:EventOutput, T:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output,&Output,&Output)->T { + self.register(OwnedAllWith8::new(label,t1,t2,t3,t4,t5,t6,t7,t8,f)) + } } @@ -2346,14 +2355,14 @@ pub type OwnedAllWith5 = stream::Node = stream::WeakNode >; impl HasOutput for AllWith5Data -where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, - F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { type Output = Out; } impl OwnedAllWith5 -where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, - F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, function:F) -> Self { let src1 = watch_stream(t1); @@ -2374,8 +2383,8 @@ where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOu } impl stream::EventConsumer for OwnedAllWith5 -where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, - F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { fn on_event(&self, stack:CallStack, _:&T) { let value1 = self.src1.value(); let value2 = self.src2.value(); @@ -2392,3 +2401,77 @@ impl Debug for AllWith5Data { write!(f,"AllWith5Data") } } + + + + +// ================ +// === AllWith8 === +// ================ + +pub struct AllWith8Data +{ src1:watch::Ref, src2:watch::Ref, src3:watch::Ref, src4:watch::Ref + , src5:watch::Ref, src6:watch::Ref, src7:watch::Ref, src8:watch::Ref + , function:F } +pub type OwnedAllWith8 = stream::Node >; +pub type AllWith8 = stream::WeakNode >; + +impl HasOutput for AllWith8Data + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, T7:EventOutput, T8:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output,&Output,&Output)->Out { + type Output = Out; +} + +impl OwnedAllWith8 + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, T7:EventOutput, T8:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output,&Output,&Output)->Out { + /// Constructor. + pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, t6:&T6, t7:&T7, t8:&T8, function:F) -> Self { + let src1 = watch_stream(t1); + let src2 = watch_stream(t2); + let src3 = watch_stream(t3); + let src4 = watch_stream(t4); + let src5 = watch_stream(t5); + let src6 = watch_stream(t6); + let src7 = watch_stream(t7); + let src8 = watch_stream(t8); + let def = AllWith8Data {src1,src2,src3,src4,src5,src6,src7,src8,function}; + let this = Self::construct(label,def); + let weak = this.downgrade(); + t1.register_target(weak.clone_ref().into()); + t2.register_target(weak.clone_ref().into()); + t3.register_target(weak.clone_ref().into()); + t4.register_target(weak.clone_ref().into()); + t5.register_target(weak.clone_ref().into()); + t6.register_target(weak.clone_ref().into()); + t7.register_target(weak.clone_ref().into()); + t8.register_target(weak.into()); + this + } +} + +impl stream::EventConsumer for OwnedAllWith8 + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, T7:EventOutput, T8:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output,&Output,&Output)->Out { + fn on_event(&self, stack:CallStack, _:&T) { + let value1 = self.src1.value(); + let value2 = self.src2.value(); + let value3 = self.src3.value(); + let value4 = self.src4.value(); + let value5 = self.src5.value(); + let value6 = self.src6.value(); + let value7 = self.src7.value(); + let value8 = self.src8.value(); + let out = (self.function)(&value1,&value2,&value3,&value4,&value5,&value6,&value7,&value8); + self.emit_event(stack,&out); + } +} + +impl Debug for AllWith8Data { + fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f,"AllWith5Data") + } +} From 3543f4c3ce84c2bdc8197f4a90fd2f6f31a5bb20 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Mon, 17 May 2021 10:28:08 +0100 Subject: [PATCH 13/29] Fix placement of profiling indicator --- .../view/graph-editor/src/component/node.rs | 1 - .../src/component/node/profiling_indicator.rs | 20 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node.rs b/src/rust/ide/view/graph-editor/src/component/node.rs index 1818a8c5fb..6df63a70b5 100644 --- a/src/rust/ide/view/graph-editor/src/component/node.rs +++ b/src/rust/ide/view/graph-editor/src/component/node.rs @@ -502,7 +502,6 @@ impl NodeModel { self.backdrop.size.set(padded_size); self.background.size.set(padded_size); self.drag_area.size.set(padded_size); - self.profiling_indicator.set_size(padded_size); self.error_indicator.size.set(padded_size); self.vcs_indicator.set_size(padded_size); self.backdrop.mod_position(|t| t.x = width/2.0); diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs index 010d3f47b6..431c8a7b24 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs @@ -17,7 +17,7 @@ use ensogl::gui::text; // === Constants === // ================= -const LABEL_OFFSET_Y: f32 = 20.0; +const LABEL_OFFSET_Y: f32 = 35.0; @@ -27,7 +27,6 @@ const LABEL_OFFSET_Y: f32 = 20.0; ensogl::define_endpoints! { Input { - set_size (Vector2), set_execution_status (ExecutionStatus), set_min_global_duration (f32), set_max_global_duration (f32), @@ -43,8 +42,9 @@ ensogl::define_endpoints! { #[derive(Clone,CloneRef,Debug)] pub struct ProfilingIndicator { - label : text::Area, - frp : Frp + root : display::object::Instance, + label : text::Area, + frp : Frp, } impl Deref for ProfilingIndicator { @@ -58,10 +58,12 @@ impl Deref for ProfilingIndicator { impl ProfilingIndicator { pub fn new(app: &Application) -> Self { - let scene = app.display.scene(); - let styles = StyleWatch::new(&scene.style_sheet); + let scene = app.display.scene(); + let styles = StyleWatch::new(&scene.style_sheet); + let root = display::object::Instance::new(Logger::new("ProfilingIndicator")); let label = text::Area::new(app); + root.add_child(&label); label.set_position_y(LABEL_OFFSET_Y); label.remove_from_scene_layer_DEPRECATED(&scene.layers.main); label.add_to_scene_layer_DEPRECATED(&scene.layers.label); @@ -118,18 +120,18 @@ impl ProfilingIndicator { label.set_content <+ frp.set_execution_status.map(|&status| match status { - ExecutionStatus::Running => "Running".to_string(), + ExecutionStatus::Running => "".to_string(), ExecutionStatus::Finished {duration} => format!("{} ms", duration) }); } - ProfilingIndicator {label,frp} + ProfilingIndicator {root,label,frp} } } impl display::Object for ProfilingIndicator { fn display_object(&self) -> &display::object::Instance { - &self.label.display_object() + &self.root } } From a0c4b7794cb5793040047ebe57be7ff2be8c993d Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Mon, 17 May 2021 11:32:03 +0100 Subject: [PATCH 14/29] Gray out JS visualizations in profiling mode --- src/rust/ensogl/lib/core/src/display/scene/dom.rs | 4 ++++ src/rust/ide/view/graph-editor/src/lib.rs | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/rust/ensogl/lib/core/src/display/scene/dom.rs b/src/rust/ensogl/lib/core/src/display/scene/dom.rs index 308d546782..beed4ff37e 100644 --- a/src/rust/ensogl/lib/core/src/display/scene/dom.rs +++ b/src/rust/ensogl/lib/core/src/display/scene/dom.rs @@ -175,6 +175,10 @@ impl DomScene { self.data.dom.set_style_or_warn("z-index", z.to_string(), &self.logger); } + pub fn set_grayscale(&self, value:f32) { + self.data.dom.set_style_or_warn("filter",format!("grayscale({})",value),&self.logger); + } + /// Creates a new instance of DomSymbol and adds it to parent. pub fn manage(&self, object:&DomSymbol) { let dom = object.dom(); diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index 560d5f9be2..74bae6f4c8 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -48,6 +48,7 @@ use crate::data::enso; use enso_args::ARGS; use enso_frp as frp; +use ensogl::Animation; use ensogl::DEPRECATED_Animation; use ensogl::DEPRECATED_Tween; use ensogl::application::Application; @@ -3240,6 +3241,7 @@ fn new_graph_editor(app:&Application) -> GraphEditor { // === Modes === // ============= + let profiling_mode_transition = Animation::new(network); frp::extend! { network out.source.mode <+ frp.toggle_profiling_mode.map2(&frp.mode,|_,&mode| { match mode { @@ -3248,11 +3250,19 @@ fn new_graph_editor(app:&Application) -> GraphEditor { } }); - eval out.source.mode([model](_) { + eval out.mode([model](_) { for edge_id in model.edges.keys() { model.refresh_edge_color(edge_id); } }); + + profiling_mode_transition.target <+ out.mode.map(|&mode| { + match mode { + Mode::Normal => 0.0, + Mode::Profiling => 1.0, + } + }); + eval profiling_mode_transition.value ((&v) scene.dom.layers.back.set_grayscale(v)); } From 7bd037631311024f67284bf515548a572706c5e1 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Mon, 17 May 2021 12:25:32 +0100 Subject: [PATCH 15/29] Document `set_grayscale` on `DomScene` --- src/js/package-lock.json | 506 ++++++++++++------ .../ensogl/lib/core/src/display/scene/dom.rs | 2 + 2 files changed, 342 insertions(+), 166 deletions(-) diff --git a/src/js/package-lock.json b/src/js/package-lock.json index 8b47573ad1..3b399ff976 100644 --- a/src/js/package-lock.json +++ b/src/js/package-lock.json @@ -19,18 +19,18 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", + "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", "dev": true }, "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", + "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.12.11", + "@babel/helper-validator-identifier": "^7.14.0", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } @@ -1305,9 +1305,9 @@ } }, "@octokit/openapi-types": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-6.0.0.tgz", - "integrity": "sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.0.0.tgz", + "integrity": "sha512-gV/8DJhAL/04zjTI95a7FhQwS6jlEE0W/7xeYAzuArD0KVAVWDLP2f3vi98hs3HLTczxXdRK/mF0tRoQPpolEw==", "dev": true }, "@octokit/plugin-enterprise-rest": { @@ -1364,18 +1364,16 @@ } }, "@octokit/request": { - "version": "5.4.14", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.14.tgz", - "integrity": "sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA==", + "version": "5.4.15", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.15.tgz", + "integrity": "sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag==", "dev": true, "requires": { "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.0.0", "@octokit/types": "^6.7.1", - "deprecation": "^2.0.0", "is-plain-object": "^5.0.0", "node-fetch": "^2.6.1", - "once": "^1.4.0", "universal-user-agent": "^6.0.0" }, "dependencies": { @@ -1451,12 +1449,12 @@ } }, "@octokit/types": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.13.0.tgz", - "integrity": "sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.14.2.tgz", + "integrity": "sha512-wiQtW9ZSy4OvgQ09iQOdyXYNN60GqjCL/UdMsepDr1Gr0QzpW6irIKbH3REuAHXAhxkEk9/F2a3Gcs1P6kW5jA==", "dev": true, "requires": { - "@octokit/openapi-types": "^6.0.0" + "@octokit/openapi-types": "^7.0.0" } }, "@sindresorhus/is": { @@ -1478,9 +1476,9 @@ "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==" }, "@types/fs-extra": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.10.tgz", - "integrity": "sha512-O9T2LLkRDiTlalOBdjEkcnT0MRdT2+wglCl7pJUJ3mkWkR8hX4K+5bg2raQNJcLv4V8zGuTXe7Ud3wSqkTyuyQ==", + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz", + "integrity": "sha512-mZsifGG4QeQ7hlkhO56u7zt/ycBgGxSVsFI/6lGTU34VtwkiqrrSDgw0+ygs8kFGWcXnFQWMrzF2h7TtDFNixA==", "requires": { "@types/node": "*" } @@ -1988,9 +1986,9 @@ } }, "js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "requires": { "argparse": "^2.0.1" } @@ -2534,9 +2532,9 @@ } }, "boolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.3.tgz", - "integrity": "sha512-EqrTKXQX6Z3A2nRmMEIlAIfjQOgFnVO2nqZGpbcsPnYGWBwpFqzlrozU1dy+S2iqfYDLh26ef4KrgTxu9xQrxA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.4.tgz", + "integrity": "sha512-5pyOr+w2LNN72F2mAq6J0ckHUfJYSgRKma7e/wlcMMhgOLV9OI0ERhERYXxUqo+dPyVxcbXKy9n+wg13+LpNnA==", "optional": true }, "boxen": { @@ -2573,9 +2571,9 @@ "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==" }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2883,9 +2881,9 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2929,9 +2927,9 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "requires": { "argparse": "^2.0.1" } @@ -4177,9 +4175,9 @@ } }, "core-js": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.10.0.tgz", - "integrity": "sha512-MQx/7TLgmmDVamSyfE+O+5BHvG1aUGj/gHhLn1wVtm2B5u1eVIPvh7vkfjwWKNCjrTJB8+He99IntSQ1qP+vYQ==", + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.12.1.tgz", + "integrity": "sha512-Ne9DKPHTObRuB09Dru5AjwKjY4cJHVGu+y5f7coGn1E9Grkc3p2iBwE9AI/nJzsE29mQF7oq+mhYYRqOMFN1Bw==", "optional": true }, "core-util-is": { @@ -4717,9 +4715,9 @@ } }, "js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "requires": { "argparse": "^2.0.1" } @@ -4741,9 +4739,9 @@ } }, "dmg-license": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.8.tgz", - "integrity": "sha512-47GOb6b4yVzpovXC34heXElpH++ICg9GuWBeOTaokUNLAoAdWpE4VehudYEEtu96j2jXsgQWYf78nW7r+0Y3eg==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.9.tgz", + "integrity": "sha512-Rq6qMDaDou2+aPN2SYy0x7LDznoJ/XaG6oDcH5wXUp+WRWQMUYE6eM+F+nex+/LSXOp1uw4HLFoed0YbfU8R/Q==", "optional": true, "requires": { "@types/plist": "^3.0.1", @@ -4751,7 +4749,7 @@ "ajv": "^6.10.0", "cli-truncate": "^1.1.0", "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.5", + "iconv-corefoundation": "^1.1.6", "plist": "^3.0.1", "smart-buffer": "^4.0.2", "verror": "^1.10.0" @@ -4803,9 +4801,9 @@ } }, "dotenv": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", - "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==" }, "dotenv-expand": { "version": "5.1.0", @@ -4884,9 +4882,9 @@ }, "dependencies": { "@types/node": { - "version": "12.20.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.7.tgz", - "integrity": "sha512-gWL8VUkg8VRaCAUgG9WmhefMqHmMblxe2rVpMF86nZY/+ZysU+BkAp+3cz03AixWDSSz0ks5WX59yAhv/cDwFA==" + "version": "12.20.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.13.tgz", + "integrity": "sha512-1x8W5OpxPq+T85OUsHRP6BqXeosKmeXRtjoF39STcdf/UWLqUsoehstZKOi0CunhVqHG17AyZgpj20eRVooK6A==" } } }, @@ -4920,9 +4918,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -5010,9 +5008,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -5135,7 +5133,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", - "dev": true, "requires": { "graceful-fs": "^4.1.2", "memory-fs": "^0.5.0", @@ -5146,7 +5143,6 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", - "dev": true, "requires": { "errno": "^0.1.3", "readable-stream": "^2.0.1" @@ -5180,7 +5176,6 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", - "dev": true, "requires": { "prr": "~1.0.1" } @@ -6897,9 +6892,9 @@ } }, "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "hpack.js": { @@ -7033,13 +7028,12 @@ "integrity": "sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA=" }, "iconv-corefoundation": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.5.tgz", - "integrity": "sha512-hI4m7udfV04OcjleOmDaR4gwXnH4xumxN+ZmywHDiKf2CmAzsT9SVYe7Y4pdnQbyZfXwAQyrElykbE5PrPRfmQ==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.6.tgz", + "integrity": "sha512-1NBe55C75bKGZaY9UHxvXG3G0gEp0ziht7quhuFrW3SPgZDw9HI6qvYXRSV5M/Eupyu8ljuJ6Cba+ec15PZ4Xw==", "optional": true, "requires": { - "cli-truncate": "^1.1.0", - "node-addon-api": "^1.6.3" + "cli-truncate": "^1.1.0" } }, "iconv-lite": { @@ -7067,9 +7061,9 @@ "dev": true }, "ignore-walk": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", + "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", "dev": true, "requires": { "minimatch": "^3.0.4" @@ -7315,9 +7309,9 @@ "dev": true }, "is-bigint": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", - "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", "dev": true }, "is-binary-path": { @@ -7329,12 +7323,35 @@ } }, "is-boolean-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", - "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", "dev": true, "requires": { - "call-bind": "^1.0.0" + "call-bind": "^1.0.2" + }, + "dependencies": { + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + } } }, "is-buffer": { @@ -7358,9 +7375,9 @@ } }, "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", "requires": { "has": "^1.0.3" } @@ -7495,9 +7512,9 @@ } }, "is-number-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", - "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", "dev": true }, "is-obj": { @@ -7562,9 +7579,9 @@ } }, "is-ssh": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.2.tgz", - "integrity": "sha512-elEw0/0c2UscLrNG+OAorbP539E3rhliKPg+hDMWN9VwrDXfYK+4PBEykDPfxlYYtQvl84TascnQyobfQLHEhQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.3.tgz", + "integrity": "sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ==", "dev": true, "requires": { "protocols": "^1.1.0" @@ -7577,9 +7594,9 @@ "dev": true }, "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", "dev": true }, "is-symbol": { @@ -7853,9 +7870,9 @@ } }, "lazy-val": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz", - "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==" }, "lerna": { "version": "3.22.1", @@ -8042,9 +8059,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -8321,9 +8338,9 @@ }, "dependencies": { "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "normalize-package-data": { @@ -8704,9 +8721,9 @@ } }, "mocha": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.2.tgz", - "integrity": "sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", "requires": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", @@ -8908,9 +8925,9 @@ } }, "mock-fs": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.13.0.tgz", - "integrity": "sha512-DD0vOdofJdoaRNtnWcrXe6RQbpHkPPmtqGq14uRX0F8ZKJ5nv89CVTYl/BZdppDxBDaV0hl75htg3abpEWlPZA==" + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==" }, "modify-values": { "version": "1.0.1", @@ -9034,9 +9051,9 @@ "dev": true }, "node-abi": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.21.0.tgz", - "integrity": "sha512-smhrivuPqEM3H5LmnY3KU6HfYv0u4QklgAxfFyRNujKUzbUcYZ+Jc2EhukB9SRcD2VpqhxM7n/MIcp1Ua1/JMg==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.26.0.tgz", + "integrity": "sha512-ag/Vos/mXXpWLLAYWsAoQdgS+gW7IwvgMLOgqopm/DbzAjazLltzgzpVMsFlgmo9TzG5hGXeaBZx2AI731RIsQ==", "requires": { "semver": "^5.4.1" }, @@ -9049,10 +9066,9 @@ } }, "node-addon-api": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", - "optional": true + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz", + "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==" }, "node-fetch": { "version": "2.6.1", @@ -9240,9 +9256,9 @@ "dev": true }, "npm-bundled": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", - "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", "dev": true, "requires": { "npm-normalize-package-bin": "^1.0.1" @@ -9545,19 +9561,27 @@ "dev": true }, "is-regex": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", - "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", "dev": true, "requires": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.2" + }, + "dependencies": { + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true + } } }, "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", "dev": true }, "string.prototype.trimend": { @@ -10111,9 +10135,9 @@ "dev": true }, "prebuild-install": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.1.tgz", - "integrity": "sha512-M+cKwofFlHa5VpTWub7GLg5RLcunYIcLqtY5pKcls/u7xaAb8FrXZ520qY8rkpYy5xw90tYCyMO0MP5ggzR3Sw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.2.tgz", + "integrity": "sha512-PzYWIKZeP+967WuKYXlTOhYBgGOvTRSfaKI89XnfJ0ansRAH7hDU45X+K+FZeI1Wb/7p/NnuctPH3g0IqKUuSQ==", "requires": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", @@ -10232,8 +10256,7 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" }, "psl": { "version": "1.8.0", @@ -11208,11 +11231,6 @@ "yallist": "^4.0.0" } }, - "node-addon-api": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz", - "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==" - }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -11266,9 +11284,9 @@ } }, "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", "dev": true } } @@ -11642,9 +11660,9 @@ } }, "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==" + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.8.tgz", + "integrity": "sha512-NDgA96EnaLSvtbM7trJj+t1LUR3pirkDCcz9nOUlPb5DMBGsH7oES6C3hs3j7R9oHEa1EMvReS/BUAIT5Tcr0g==" }, "spdy": { "version": "4.0.2", @@ -12031,8 +12049,7 @@ "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" }, "tar": { "version": "6.1.0", @@ -12114,12 +12131,38 @@ "dev": true }, "temp-file": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.7.tgz", - "integrity": "sha512-9tBJKt7GZAQt/Rg0QzVWA8Am8c1EFl+CAv04/aBVqlx5oyfQ508sFIABshQ0xbZu6mBrFLWIUXO/bbLYghW70g==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", "requires": { "async-exit-hook": "^2.0.1", - "fs-extra": "^8.1.0" + "fs-extra": "^10.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + } } }, "temp-write": { @@ -12427,6 +12470,145 @@ "utf8-byte-length": "^1.0.1" } }, + "ts-loader": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.2.0.tgz", + "integrity": "sha512-ebXBFrNyMSmbWgjnb3WBloUBK+VSx1xckaXsMXxlZRDqce/OPdYBVN5efB0W3V0defq0Gcy4YuzvPGqRgjj85A==", + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^4.0.0", + "loader-utils": "^2.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "picomatch": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", + "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==" + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -12492,9 +12674,9 @@ "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==" }, "uglify-js": { - "version": "3.13.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.3.tgz", - "integrity": "sha512-otIc7O9LyxpUcQoXzj2hL4LPWKklO6LJWoJUzNa8A17Xgi4fOeDC8FBDOLHnC/Slo1CQgsZMcM6as0M76BZaig==", + "version": "3.13.6", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.6.tgz", + "integrity": "sha512-rRprLwl8RVaS+Qvx3Wh5hPfPBn9++G6xkGlUupya0s5aDmNjI7z3lnRLB3u7sN4OmbB0pWgzhM9BEJyiWAwtAA==", "dev": true, "optional": true }, @@ -12685,9 +12867,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13860,20 +14042,12 @@ "requires": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" - }, - "dependencies": { - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" - } } }, "xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "optional": true + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" }, "xmldom": { "version": "0.5.0", @@ -13958,9 +14132,9 @@ } }, "y18n": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.7.tgz", - "integrity": "sha512-oOhslryvNcA1lB9WYr+M6TMyLkLg81Dgmyb48ZDU0lvR+5bmNDTMz7iobM1QXooaLhbbrcHrlNaABhI6Vo6StQ==" + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yargs-parser": { "version": "20.2.7", diff --git a/src/rust/ensogl/lib/core/src/display/scene/dom.rs b/src/rust/ensogl/lib/core/src/display/scene/dom.rs index beed4ff37e..0c33686fbe 100644 --- a/src/rust/ensogl/lib/core/src/display/scene/dom.rs +++ b/src/rust/ensogl/lib/core/src/display/scene/dom.rs @@ -175,6 +175,8 @@ impl DomScene { self.data.dom.set_style_or_warn("z-index", z.to_string(), &self.logger); } + /// Sets the CSS property `filter: grayscale({value})` on this element. A value of 0.0 displays + /// the element normally. A value of 1.0 will make the element completely gray. pub fn set_grayscale(&self, value:f32) { self.data.dom.set_style_or_warn("filter",format!("grayscale({})",value),&self.logger); } From 030fa5649d8a94f0bb3145544d779cd4841a6373 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Mon, 17 May 2021 13:12:49 +0100 Subject: [PATCH 16/29] Solve linting errors --- src/rust/ide/view/graph-editor/src/profiling_icon.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/profiling_icon.rs b/src/rust/ide/view/graph-editor/src/profiling_icon.rs index c074ed7254..36355b9f18 100644 --- a/src/rust/ide/view/graph-editor/src/profiling_icon.rs +++ b/src/rust/ide/view/graph-editor/src/profiling_icon.rs @@ -26,7 +26,7 @@ ensogl::define_shape_system! { // imprecisions. let aperture_gap_size = &outer_circle_radius * 1.1; let aperture_gap = Triangle(&aperture_gap_size*2.0,aperture_gap_size.clone()); - let aperture_gap = aperture_gap.rotate(&needle_angle+180.0_f32.to_radians().radians()); + let aperture_gap = aperture_gap.rotate(needle_angle+180.0_f32.to_radians().radians()); let aperture_gap = aperture_gap.translate_x(&aperture_gap_size*2.0.sqrt()*0.25); let aperture_gap = aperture_gap.translate_y(-(&aperture_gap_size*2.0.sqrt()*0.25)); @@ -38,7 +38,7 @@ ensogl::define_shape_system! { let outer_circle = base - circle_gap - aperture_gap + aperture_cap_1 + aperture_cap_2; let needle_length = &outer_circle_radius-&needle_radius_outer; - let needle = UnevenCapsule(needle_radius_outer.clone(),needle_radius_inner.clone(),needle_length.clone()); + let needle = UnevenCapsule(needle_radius_outer,needle_radius_inner,needle_length); let needle = needle.rotate(&needle_angle); let inner_circle = Circle(&inner_circle_radius); From da1bc9882c8d72605eddae376bb4297d27b97a73 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Thu, 20 May 2021 13:53:48 +0100 Subject: [PATCH 17/29] Make some of the requested changes --- docs/product/shortcuts.md | 3 +- src/js/package-lock.json | 506 ++++++------------ .../lib/core/src/data/color/space/def.rs | 11 +- .../ensogl/lib/core/src/display/scene/dom.rs | 2 +- .../display/shape/primitive/def/primitive.rs | 16 +- .../ensogl/lib/text/src/component/area.rs | 6 +- src/rust/ensogl/lib/theme/src/lib.rs | 14 +- .../ide/view/graph-editor/src/component.rs | 2 + .../view/graph-editor/src/component/node.rs | 100 ++-- .../src/component/node/input/area.rs | 39 +- .../src/component/node/output/port.rs | 12 +- .../src/component/node/profiling.rs | 222 ++++++++ .../src/component/node/profiling_indicator.rs | 137 ----- .../graph-editor/src/component/profiling.rs | 173 ++++++ src/rust/ide/view/graph-editor/src/display.rs | 0 src/rust/ide/view/graph-editor/src/lib.rs | 169 ++---- .../ide/view/graph-editor/src/profiling.rs | 73 +++ .../view/graph-editor/src/profiling_icon.rs | 56 -- .../ide/view/src/debug_scenes/interface.rs | 14 +- src/rust/lib/frp/src/nodes.rs | 69 ++- 20 files changed, 810 insertions(+), 814 deletions(-) create mode 100644 src/rust/ide/view/graph-editor/src/component/node/profiling.rs delete mode 100644 src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs create mode 100644 src/rust/ide/view/graph-editor/src/component/profiling.rs create mode 100644 src/rust/ide/view/graph-editor/src/display.rs create mode 100644 src/rust/ide/view/graph-editor/src/profiling.rs delete mode 100644 src/rust/ide/view/graph-editor/src/profiling_icon.rs diff --git a/docs/product/shortcuts.md b/docs/product/shortcuts.md index 3c0fb2b474..c599c10aca 100644 --- a/docs/product/shortcuts.md +++ b/docs/product/shortcuts.md @@ -38,7 +38,7 @@ further investigation. | ctrl+q | Close the application (Linux) | | alt+F4 | Close the application (MacOS, Windows, Linux) | | ctrl+w | Close the application (Windows, Linux) | -| :warning: ctrl+p | Toggle profiling mode | +| :warning: ctrl+p | Toggle profiling mode | #### Navigation @@ -108,7 +108,6 @@ further investigation. | meta + z | Zoom into selection if available in visualization. | - #### Debug | Shortcut | Action | | -------- | ------ | diff --git a/src/js/package-lock.json b/src/js/package-lock.json index 3b399ff976..8b47573ad1 100644 --- a/src/js/package-lock.json +++ b/src/js/package-lock.json @@ -19,18 +19,18 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", "dev": true }, "@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", + "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.0", + "@babel/helper-validator-identifier": "^7.12.11", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } @@ -1305,9 +1305,9 @@ } }, "@octokit/openapi-types": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.0.0.tgz", - "integrity": "sha512-gV/8DJhAL/04zjTI95a7FhQwS6jlEE0W/7xeYAzuArD0KVAVWDLP2f3vi98hs3HLTczxXdRK/mF0tRoQPpolEw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-6.0.0.tgz", + "integrity": "sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ==", "dev": true }, "@octokit/plugin-enterprise-rest": { @@ -1364,16 +1364,18 @@ } }, "@octokit/request": { - "version": "5.4.15", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.15.tgz", - "integrity": "sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag==", + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.14.tgz", + "integrity": "sha512-VkmtacOIQp9daSnBmDI92xNIeLuSRDOIuplp/CJomkvzt7M18NXgG044Cx/LFKLgjKt9T2tZR6AtJayba9GTSA==", "dev": true, "requires": { "@octokit/endpoint": "^6.0.1", "@octokit/request-error": "^2.0.0", "@octokit/types": "^6.7.1", + "deprecation": "^2.0.0", "is-plain-object": "^5.0.0", "node-fetch": "^2.6.1", + "once": "^1.4.0", "universal-user-agent": "^6.0.0" }, "dependencies": { @@ -1449,12 +1451,12 @@ } }, "@octokit/types": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.14.2.tgz", - "integrity": "sha512-wiQtW9ZSy4OvgQ09iQOdyXYNN60GqjCL/UdMsepDr1Gr0QzpW6irIKbH3REuAHXAhxkEk9/F2a3Gcs1P6kW5jA==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.13.0.tgz", + "integrity": "sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA==", "dev": true, "requires": { - "@octokit/openapi-types": "^7.0.0" + "@octokit/openapi-types": "^6.0.0" } }, "@sindresorhus/is": { @@ -1476,9 +1478,9 @@ "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==" }, "@types/fs-extra": { - "version": "9.0.11", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz", - "integrity": "sha512-mZsifGG4QeQ7hlkhO56u7zt/ycBgGxSVsFI/6lGTU34VtwkiqrrSDgw0+ygs8kFGWcXnFQWMrzF2h7TtDFNixA==", + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.10.tgz", + "integrity": "sha512-O9T2LLkRDiTlalOBdjEkcnT0MRdT2+wglCl7pJUJ3mkWkR8hX4K+5bg2raQNJcLv4V8zGuTXe7Ud3wSqkTyuyQ==", "requires": { "@types/node": "*" } @@ -1986,9 +1988,9 @@ } }, "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", "requires": { "argparse": "^2.0.1" } @@ -2532,9 +2534,9 @@ } }, "boolean": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.4.tgz", - "integrity": "sha512-5pyOr+w2LNN72F2mAq6J0ckHUfJYSgRKma7e/wlcMMhgOLV9OI0ERhERYXxUqo+dPyVxcbXKy9n+wg13+LpNnA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.3.tgz", + "integrity": "sha512-EqrTKXQX6Z3A2nRmMEIlAIfjQOgFnVO2nqZGpbcsPnYGWBwpFqzlrozU1dy+S2iqfYDLh26ef4KrgTxu9xQrxA==", "optional": true }, "boxen": { @@ -2571,9 +2573,9 @@ "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==" }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2881,9 +2883,9 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2927,9 +2929,9 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", "requires": { "argparse": "^2.0.1" } @@ -4175,9 +4177,9 @@ } }, "core-js": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.12.1.tgz", - "integrity": "sha512-Ne9DKPHTObRuB09Dru5AjwKjY4cJHVGu+y5f7coGn1E9Grkc3p2iBwE9AI/nJzsE29mQF7oq+mhYYRqOMFN1Bw==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.10.0.tgz", + "integrity": "sha512-MQx/7TLgmmDVamSyfE+O+5BHvG1aUGj/gHhLn1wVtm2B5u1eVIPvh7vkfjwWKNCjrTJB8+He99IntSQ1qP+vYQ==", "optional": true }, "core-util-is": { @@ -4715,9 +4717,9 @@ } }, "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", "requires": { "argparse": "^2.0.1" } @@ -4739,9 +4741,9 @@ } }, "dmg-license": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.9.tgz", - "integrity": "sha512-Rq6qMDaDou2+aPN2SYy0x7LDznoJ/XaG6oDcH5wXUp+WRWQMUYE6eM+F+nex+/LSXOp1uw4HLFoed0YbfU8R/Q==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.8.tgz", + "integrity": "sha512-47GOb6b4yVzpovXC34heXElpH++ICg9GuWBeOTaokUNLAoAdWpE4VehudYEEtu96j2jXsgQWYf78nW7r+0Y3eg==", "optional": true, "requires": { "@types/plist": "^3.0.1", @@ -4749,7 +4751,7 @@ "ajv": "^6.10.0", "cli-truncate": "^1.1.0", "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.6", + "iconv-corefoundation": "^1.1.5", "plist": "^3.0.1", "smart-buffer": "^4.0.2", "verror": "^1.10.0" @@ -4801,9 +4803,9 @@ } }, "dotenv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", - "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==" + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" }, "dotenv-expand": { "version": "5.1.0", @@ -4882,9 +4884,9 @@ }, "dependencies": { "@types/node": { - "version": "12.20.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.13.tgz", - "integrity": "sha512-1x8W5OpxPq+T85OUsHRP6BqXeosKmeXRtjoF39STcdf/UWLqUsoehstZKOi0CunhVqHG17AyZgpj20eRVooK6A==" + "version": "12.20.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.7.tgz", + "integrity": "sha512-gWL8VUkg8VRaCAUgG9WmhefMqHmMblxe2rVpMF86nZY/+ZysU+BkAp+3cz03AixWDSSz0ks5WX59yAhv/cDwFA==" } } }, @@ -4918,9 +4920,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -5008,9 +5010,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -5133,6 +5135,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", + "dev": true, "requires": { "graceful-fs": "^4.1.2", "memory-fs": "^0.5.0", @@ -5143,6 +5146,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, "requires": { "errno": "^0.1.3", "readable-stream": "^2.0.1" @@ -5176,6 +5180,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, "requires": { "prr": "~1.0.1" } @@ -6892,9 +6897,9 @@ } }, "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "dev": true }, "hpack.js": { @@ -7028,12 +7033,13 @@ "integrity": "sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA=" }, "iconv-corefoundation": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.6.tgz", - "integrity": "sha512-1NBe55C75bKGZaY9UHxvXG3G0gEp0ziht7quhuFrW3SPgZDw9HI6qvYXRSV5M/Eupyu8ljuJ6Cba+ec15PZ4Xw==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.5.tgz", + "integrity": "sha512-hI4m7udfV04OcjleOmDaR4gwXnH4xumxN+ZmywHDiKf2CmAzsT9SVYe7Y4pdnQbyZfXwAQyrElykbE5PrPRfmQ==", "optional": true, "requires": { - "cli-truncate": "^1.1.0" + "cli-truncate": "^1.1.0", + "node-addon-api": "^1.6.3" } }, "iconv-lite": { @@ -7061,9 +7067,9 @@ "dev": true }, "ignore-walk": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", - "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", "dev": true, "requires": { "minimatch": "^3.0.4" @@ -7309,9 +7315,9 @@ "dev": true }, "is-bigint": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", - "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", "dev": true }, "is-binary-path": { @@ -7323,35 +7329,12 @@ } }, "is-boolean-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", - "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", "dev": true, "requires": { - "call-bind": "^1.0.2" - }, - "dependencies": { - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - } + "call-bind": "^1.0.0" } }, "is-buffer": { @@ -7375,9 +7358,9 @@ } }, "is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", "requires": { "has": "^1.0.3" } @@ -7512,9 +7495,9 @@ } }, "is-number-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", - "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", "dev": true }, "is-obj": { @@ -7579,9 +7562,9 @@ } }, "is-ssh": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.3.tgz", - "integrity": "sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.2.tgz", + "integrity": "sha512-elEw0/0c2UscLrNG+OAorbP539E3rhliKPg+hDMWN9VwrDXfYK+4PBEykDPfxlYYtQvl84TascnQyobfQLHEhQ==", "dev": true, "requires": { "protocols": "^1.1.0" @@ -7594,9 +7577,9 @@ "dev": true }, "is-string": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", - "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", "dev": true }, "is-symbol": { @@ -7870,9 +7853,9 @@ } }, "lazy-val": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", - "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz", + "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==" }, "lerna": { "version": "3.22.1", @@ -8059,9 +8042,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -8338,9 +8321,9 @@ }, "dependencies": { "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "dev": true }, "normalize-package-data": { @@ -8721,9 +8704,9 @@ } }, "mocha": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", - "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.3.2.tgz", + "integrity": "sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg==", "requires": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", @@ -8925,9 +8908,9 @@ } }, "mock-fs": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", - "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==" + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.13.0.tgz", + "integrity": "sha512-DD0vOdofJdoaRNtnWcrXe6RQbpHkPPmtqGq14uRX0F8ZKJ5nv89CVTYl/BZdppDxBDaV0hl75htg3abpEWlPZA==" }, "modify-values": { "version": "1.0.1", @@ -9051,9 +9034,9 @@ "dev": true }, "node-abi": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.26.0.tgz", - "integrity": "sha512-ag/Vos/mXXpWLLAYWsAoQdgS+gW7IwvgMLOgqopm/DbzAjazLltzgzpVMsFlgmo9TzG5hGXeaBZx2AI731RIsQ==", + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.21.0.tgz", + "integrity": "sha512-smhrivuPqEM3H5LmnY3KU6HfYv0u4QklgAxfFyRNujKUzbUcYZ+Jc2EhukB9SRcD2VpqhxM7n/MIcp1Ua1/JMg==", "requires": { "semver": "^5.4.1" }, @@ -9066,9 +9049,10 @@ } }, "node-addon-api": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz", - "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==" + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "optional": true }, "node-fetch": { "version": "2.6.1", @@ -9256,9 +9240,9 @@ "dev": true }, "npm-bundled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", "dev": true, "requires": { "npm-normalize-package-bin": "^1.0.1" @@ -9561,27 +9545,19 @@ "dev": true }, "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", "dev": true, "requires": { "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" - }, - "dependencies": { - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - } + "has-symbols": "^1.0.1" } }, "object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", "dev": true }, "string.prototype.trimend": { @@ -10135,9 +10111,9 @@ "dev": true }, "prebuild-install": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.2.tgz", - "integrity": "sha512-PzYWIKZeP+967WuKYXlTOhYBgGOvTRSfaKI89XnfJ0ansRAH7hDU45X+K+FZeI1Wb/7p/NnuctPH3g0IqKUuSQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.1.tgz", + "integrity": "sha512-M+cKwofFlHa5VpTWub7GLg5RLcunYIcLqtY5pKcls/u7xaAb8FrXZ520qY8rkpYy5xw90tYCyMO0MP5ggzR3Sw==", "requires": { "detect-libc": "^1.0.3", "expand-template": "^2.0.3", @@ -10256,7 +10232,8 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true }, "psl": { "version": "1.8.0", @@ -11231,6 +11208,11 @@ "yallist": "^4.0.0" } }, + "node-addon-api": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.1.0.tgz", + "integrity": "sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==" + }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -11284,9 +11266,9 @@ } }, "object-inspect": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", "dev": true } } @@ -11660,9 +11642,9 @@ } }, "spdx-license-ids": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.8.tgz", - "integrity": "sha512-NDgA96EnaLSvtbM7trJj+t1LUR3pirkDCcz9nOUlPb5DMBGsH7oES6C3hs3j7R9oHEa1EMvReS/BUAIT5Tcr0g==" + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==" }, "spdy": { "version": "4.0.2", @@ -12049,7 +12031,8 @@ "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true }, "tar": { "version": "6.1.0", @@ -12131,38 +12114,12 @@ "dev": true }, "temp-file": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", - "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.7.tgz", + "integrity": "sha512-9tBJKt7GZAQt/Rg0QzVWA8Am8c1EFl+CAv04/aBVqlx5oyfQ508sFIABshQ0xbZu6mBrFLWIUXO/bbLYghW70g==", "requires": { "async-exit-hook": "^2.0.1", - "fs-extra": "^10.0.0" - }, - "dependencies": { - "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - } + "fs-extra": "^8.1.0" } }, "temp-write": { @@ -12470,145 +12427,6 @@ "utf8-byte-length": "^1.0.1" } }, - "ts-loader": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.2.0.tgz", - "integrity": "sha512-ebXBFrNyMSmbWgjnb3WBloUBK+VSx1xckaXsMXxlZRDqce/OPdYBVN5efB0W3V0defq0Gcy4YuzvPGqRgjj85A==", - "requires": { - "chalk": "^4.1.0", - "enhanced-resolve": "^4.0.0", - "loader-utils": "^2.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } - }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==" - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -12674,9 +12492,9 @@ "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==" }, "uglify-js": { - "version": "3.13.6", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.6.tgz", - "integrity": "sha512-rRprLwl8RVaS+Qvx3Wh5hPfPBn9++G6xkGlUupya0s5aDmNjI7z3lnRLB3u7sN4OmbB0pWgzhM9BEJyiWAwtAA==", + "version": "3.13.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.3.tgz", + "integrity": "sha512-otIc7O9LyxpUcQoXzj2hL4LPWKklO6LJWoJUzNa8A17Xgi4fOeDC8FBDOLHnC/Slo1CQgsZMcM6as0M76BZaig==", "dev": true, "optional": true }, @@ -12867,9 +12685,9 @@ } }, "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -14042,12 +13860,20 @@ "requires": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" + }, + "dependencies": { + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + } } }, "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "optional": true }, "xmldom": { "version": "0.5.0", @@ -14132,9 +13958,9 @@ } }, "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.7.tgz", + "integrity": "sha512-oOhslryvNcA1lB9WYr+M6TMyLkLg81Dgmyb48ZDU0lvR+5bmNDTMz7iobM1QXooaLhbbrcHrlNaABhI6Vo6StQ==" }, "yargs-parser": { "version": "20.2.7", diff --git a/src/rust/ensogl/lib/core/src/data/color/space/def.rs b/src/rust/ensogl/lib/core/src/data/color/space/def.rs index 56439c8c24..0731ad9bc6 100644 --- a/src/rust/ensogl/lib/core/src/data/color/space/def.rs +++ b/src/rust/ensogl/lib/core/src/data/color/space/def.rs @@ -521,13 +521,10 @@ impl Lcha { Rgba::from(self).to_javascript_string() } - /// Convert the color to gray by setting chroma to zero. - pub fn desaturate(&self) -> Lcha { - let lightness = self.lightness; - let chroma = 0.0; - let hue = self.hue; - let alpha = self.alpha; - Lcha::new(lightness,chroma,hue,alpha) + /// Convert the color to grayscale by setting chroma to zero. + pub fn to_grayscale(mut self) -> Lcha { + self.data.opaque.chroma = 0.0; + self } } diff --git a/src/rust/ensogl/lib/core/src/display/scene/dom.rs b/src/rust/ensogl/lib/core/src/display/scene/dom.rs index 0c33686fbe..6408b45912 100644 --- a/src/rust/ensogl/lib/core/src/display/scene/dom.rs +++ b/src/rust/ensogl/lib/core/src/display/scene/dom.rs @@ -177,7 +177,7 @@ impl DomScene { /// Sets the CSS property `filter: grayscale({value})` on this element. A value of 0.0 displays /// the element normally. A value of 1.0 will make the element completely gray. - pub fn set_grayscale(&self, value:f32) { + pub fn filter_grayscale(&self, value:f32) { self.data.dom.set_style_or_warn("filter",format!("grayscale({})",value),&self.logger); } diff --git a/src/rust/ensogl/lib/core/src/display/shape/primitive/def/primitive.rs b/src/rust/ensogl/lib/core/src/display/shape/primitive/def/primitive.rs index 05bd2da5bd..3aa69f7e1c 100644 --- a/src/rust/ensogl/lib/core/src/display/shape/primitive/def/primitive.rs +++ b/src/rust/ensogl/lib/core/src/display/shape/primitive/def/primitive.rs @@ -285,9 +285,9 @@ define_sdf_shapes! { /// * `inner_height` - Distance between the centers of the two circles. UnevenCapsule (radius_top:Pixels, radius_bottom:Pixels, inner_height:Pixels) { position.x = abs(position.x); - float b = (radius_bottom-radius_top) / inner_height; - float a = sqrt(1.0-b*b); - float k = dot(position,vec2(-b,a)); + float b = (radius_bottom-radius_top) / inner_height; + float a = sqrt(1.0-b*b); + float k = dot(position,vec2(-b,a)); float dist; if (k < 0.0) { dist = length(position) - radius_bottom; @@ -297,11 +297,11 @@ define_sdf_shapes! { dist = dot(position,vec2(a,b)) - radius_bottom; } - float max_radius = max(radius_top,radius_bottom); - float min_x = -max_radius; - float max_x = max_radius; - float min_y = -radius_bottom; - float max_y = inner_height + radius_top; + float max_radius = max(radius_top,radius_bottom); + float min_x = -max_radius; + float max_x = max_radius; + float min_y = -radius_bottom; + float max_y = inner_height + radius_top; BoundingBox bounds = bounding_box(min_x,max_x,min_y,max_y); return bound_sdf(dist,bounds); diff --git a/src/rust/ensogl/lib/text/src/component/area.rs b/src/rust/ensogl/lib/text/src/component/area.rs index 5f1fc5f52b..f0ce1e8992 100644 --- a/src/rust/ensogl/lib/text/src/component/area.rs +++ b/src/rust/ensogl/lib/text/src/component/area.rs @@ -102,7 +102,8 @@ pub mod selection { let alpha = alpha_weight.mix(blinking_alpha,SELECTION_ALPHA); let shape = Rect((1.px() * rect_width,1.px() * rect_height)); let shape = shape.corners_radius(SELECTION_CORNER_RADIUS.px()); - let color = format!("srgba({}.x,{}.y,{}.z,{})",color_rgb,color_rgb,color_rgb,alpha.glsl()); + let color = format!("srgba({}.x,{}.y,{}.z,{})",color_rgb,color_rgb + ,color_rgb,alpha.glsl()); let shape = shape.fill(color); shape.into() } @@ -160,7 +161,8 @@ impl Selection { position . update_spring (|spring| spring * spring_factor); width . update_spring (|spring| spring * spring_factor); - Self {logger,display_object,right_side,shape_view,network,position,width,edit_mode,set_color} . init() + Self {logger,display_object,right_side,shape_view,network,position,width,edit_mode + ,set_color}.init() } fn init(self) -> Self { diff --git a/src/rust/ensogl/lib/theme/src/lib.rs b/src/rust/ensogl/lib/theme/src/lib.rs index 1905b41dad..814b363ecd 100644 --- a/src/rust/ensogl/lib/theme/src/lib.rs +++ b/src/rust/ensogl/lib/theme/src/lib.rs @@ -315,10 +315,10 @@ define_themes! { [light:0, dark:1] stripe_angle = 45.0 , 45.0; } profiling { - lightness = code::types::lightness , code::types::lightness; - chroma = code::types::chroma , code::types::chroma; - min_hue = 0.38 , 0.38; - max_hue = 0.07 , 0.07; + lightness = code::types::lightness , code::types::lightness; + chroma = code::types::chroma , code::types::chroma; + min_time_hue = 0.38 , 0.38; + max_time_hue = 0.07 , 0.07; } type_label { offset_y = -23.0, -23.0; @@ -377,9 +377,11 @@ define_themes! { [light:0, dark:1] } } profiling_button { - non_toggled = graph_editor::node::actions::button::non_toggled , graph_editor::node::actions::button::non_toggled; + non_toggled = graph_editor::node::actions::button::non_toggled + ,graph_editor::node::actions::button::non_toggled; toggled = Lcha(0.7,0.5,0.12,1.0) , Lcha(0.7,0.5,0.12,1.0); - hovered = graph_editor::node::actions::button::hovered , graph_editor::node::actions::button::hovered; + hovered = graph_editor::node::actions::button::hovered + ,graph_editor::node::actions::button::hovered; toggled_hovered = Lcha(0.55,0.5,0.12,1.0) , Lcha(0.85,0.5,0.12,1.0); } } diff --git a/src/rust/ide/view/graph-editor/src/component.rs b/src/rust/ide/view/graph-editor/src/component.rs index 991bfd8e23..64e90e0921 100644 --- a/src/rust/ide/view/graph-editor/src/component.rs +++ b/src/rust/ide/view/graph-editor/src/component.rs @@ -6,6 +6,8 @@ pub mod node; pub mod tooltip; pub mod type_coloring; pub mod visualization; +#[warn(missing_docs)] +pub mod profiling; pub use breadcrumbs::Breadcrumbs; pub use edge::Edge; diff --git a/src/rust/ide/view/graph-editor/src/component/node.rs b/src/rust/ide/view/graph-editor/src/component/node.rs index 0c7e25be60..0cf6c3a807 100644 --- a/src/rust/ide/view/graph-editor/src/component/node.rs +++ b/src/rust/ide/view/graph-editor/src/component/node.rs @@ -12,14 +12,15 @@ pub mod output; pub mod error; #[deny(missing_docs)] pub mod vcs; -mod profiling_indicator; +#[warn(missing_docs)] +pub mod profiling; pub use error::Error; pub use expression::Expression; use crate::prelude::*; -use crate::component::node::profiling_indicator::ProfilingIndicator; +use crate::component::node::profiling::RunningTimeLabel; use crate::Mode as EditorMode; use crate::component::visualization; use crate::tooltip; @@ -37,6 +38,7 @@ use ensogl::display; use ensogl_gui_components::shadow; use ensogl_text::Text; use ensogl_theme; +use ensogl_theme::graph_editor::node::profiling as profiling_theme; use std::f32::EPSILON; use super::edge; @@ -208,24 +210,6 @@ pub mod error_shape { -// ======================== -// === Execution Status === -// ======================== - -#[derive(Debug,Copy,Clone)] -pub enum ExecutionStatus { - Running, - Finished { duration: f32 } -} - -impl Default for ExecutionStatus { - fn default() -> Self { - ExecutionStatus::Running - } -} - - - // ============== // === Crumbs === // ============== @@ -285,7 +269,7 @@ ensogl::define_endpoints! { set_editor_mode (EditorMode), set_profiling_min_global_duration (f32), set_profiling_max_global_duration (f32), - set_execution_status (ExecutionStatus), + set_profiling_status (profiling::Status), } Output { /// Press event. Emitted when user clicks on non-active part of the node, like its @@ -384,7 +368,7 @@ pub struct NodeModel { pub background : background::View, pub drag_area : drag_area::View, pub error_indicator : error_shape::View, - pub profiling_indicator : ProfilingIndicator, + pub running_time_label : RunningTimeLabel, pub input : input::Area, pub output : output::Area, pub visualization : visualization::Container, @@ -422,14 +406,14 @@ impl NodeModel { let error_indicator_logger = Logger::sub(&logger,"error_indicator"); let error_indicator = error_shape::View::new(&error_indicator_logger); - let profiling_indicator = ProfilingIndicator::new(app); + let running_time_label = RunningTimeLabel::new(app); let backdrop = backdrop::View::new(&main_logger); let background = background::View::new(&main_logger); let drag_area = drag_area::View::new(&drag_logger); let vcs_indicator = vcs::StatusIndicator::new(app); let display_object = display::object::Instance::new(&logger); - display_object.add_child(&profiling_indicator); + display_object.add_child(&running_time_label); display_object.add_child(&drag_area); display_object.add_child(&backdrop); display_object.add_child(&background); @@ -460,7 +444,7 @@ impl NodeModel { let app = app.clone_ref(); Self {app,display_object,logger,backdrop,background,drag_area,output,input,visualization - ,error_visualization,profiling_indicator,action_bar,error_indicator,vcs_indicator,style} + ,error_visualization,running_time_label,action_bar,error_indicator,vcs_indicator,style} .init() } @@ -508,7 +492,7 @@ impl NodeModel { self.background.mod_position(|t| t.x = width/2.0); self.drag_area.mod_position(|t| t.x = width/2.0); - self.profiling_indicator.set_position_x(width/2.0); + self.running_time_label.set_position_x(width/2.0); self.error_indicator.set_position_x(width/2.0); self.vcs_indicator.set_position_x(width/2.0); @@ -602,6 +586,7 @@ impl Node { eval frp.set_expression ((a) model.set_expression(a)); out.source.expression <+ model.input.frp.expression; model.input.set_connected <+ frp.set_input_connected; + model.input.set_disabled <+ frp.set_disabled; model.output.set_expression_visibility <+ frp.set_output_expression_visibility; @@ -622,7 +607,7 @@ impl Node { // === Editor Mode === model.input.set_editor_mode <+ frp.set_editor_mode; - model.profiling_indicator.set_editor_mode <+ frp.set_editor_mode; + model.running_time_label.set_editor_mode <+ frp.set_editor_mode; model.vcs_indicator.set_visibility <+ frp.set_editor_mode.map(|&mode| { !matches!(mode,EditorMode::Profiling {..}) }); @@ -640,12 +625,14 @@ impl Node { frp.source.error <+ frp.set_error; is_error_set <- frp.error.map(|err| err.is_some()); no_error_set <- not(&is_error_set); - error_color_anim.target <+ all_with(&frp.error,&frp.set_editor_mode,f!([style](error,&mode) - match mode { - EditorMode::Normal => Self::error_color(error,&style), - EditorMode::Profiling => Self::error_color(error,&style).desaturate(), - } - )); + error_color_anim.target <+ all_with(&frp.error,&frp.set_editor_mode, + f!([style](error,&mode) + let error_color = Self::error_color(error,&style); + match mode { + EditorMode::Normal => error_color, + EditorMode::Profiling => error_color.to_grayscale(), + } + )); eval frp.set_visualization ((t) model.visualization.frp.set_visualization.emit(t)); visualization_enabled_frp <- bool(&frp.disable_visualization,&frp.enable_visualization); @@ -708,12 +695,12 @@ impl Node { // === Profiling Indicator === frp::extend! { network - model.profiling_indicator.set_min_global_duration + model.running_time_label.set_min_global_duration <+ frp.set_profiling_min_global_duration; - model.profiling_indicator.set_max_global_duration + model.running_time_label.set_max_global_duration <+ frp.set_profiling_max_global_duration; - model.profiling_indicator.set_execution_status <+ frp.set_execution_status; - model.input.set_execution_status <+ frp.set_execution_status; + model.running_time_label.set_status <+ frp.set_profiling_status; + model.input.set_profiling_status <+ frp.set_profiling_status; } let bg_color_anim = color::Animation::new(network); @@ -724,37 +711,33 @@ impl Node { let bgg = style_frp.get_color(ensogl_theme::graph_editor::node::background); - let profiling_theme = ensogl_theme::graph_editor::node::profiling::HERE.path(); - let profiling_lightness = style_frp.get_number_or(profiling_theme.sub("lightness"),0.72); - let profiling_chroma = style_frp.get_number_or(profiling_theme.sub("chroma"),0.7); - let profiling_min_hue = style_frp.get_number_or(profiling_theme.sub("min_hue"),0.38); - let profiling_max_hue = style_frp.get_number_or(profiling_theme.sub("max_hue"),0.07); + let profiling_lightness = style_frp.get_number_or(profiling_theme::lightness,0.7); + let profiling_chroma = style_frp.get_number_or(profiling_theme::chroma,0.7); + let profiling_min_hue = style_frp.get_number_or(profiling_theme::min_time_hue,0.4); + let profiling_max_hue = style_frp.get_number_or(profiling_theme::max_time_hue,0.1); profiling_color <- all_with8 - (&frp.set_execution_status,&frp.set_profiling_min_global_duration, + (&frp.set_profiling_status,&frp.set_profiling_min_global_duration, &frp.set_profiling_max_global_duration,&profiling_lightness,&profiling_chroma, &profiling_min_hue,&profiling_max_hue,&bgg, - |&status,&min,&max,&lightness,&chroma,&min_hue,&max_hue,&bgg| { + |&status,&min,&max,&lightness,&chroma,&min_time_hue,&max_time_hue,&bgg| { match status { - ExecutionStatus::Running => color::Lcha::from(bgg), - ExecutionStatus::Finished {duration} => { - let hue_delta = max_hue - min_hue; - let relative_duration = (duration - min) / (max - min); - let hue = min_hue + relative_duration * hue_delta; - let alpha = 1.0; - color::Lcha::new(lightness,chroma,hue,alpha) + profiling::Status::Running => color::Lcha::from(bgg), + profiling::Status::Finished {..} => { + let theme = profiling::Theme {lightness,chroma,min_time_hue + ,max_time_hue}; + status.display_color(min,max,theme).with_alpha(1.0) } } }); - bg_color_anim.target <+ all_with4(&bgg,&frp.set_disabled,&frp.set_editor_mode,&profiling_color, - f!([model](bgg,disabled,&mode,profiling_color) { - model.input.frp.set_disabled(*disabled); + bg_color_anim.target <+ all_with3(&bgg,&frp.set_editor_mode,&profiling_color, + |bgg,&mode,&profiling_color| { match mode { EditorMode::Normal => color::Lcha::from(*bgg), - EditorMode::Profiling => *profiling_color, + EditorMode::Profiling => profiling_color, } - })); + }); // FIXME [WD]: Uncomment when implementing disabled icon. // bg_color <- frp.set_disabled.map(f!([model,style](disabled) { @@ -768,7 +751,8 @@ impl Node { // model.background.bg_color.set(color::Rgba::from(c).into()) // ); - eval bg_color_anim.value ((c) model.background.bg_color.set(color::Rgba::from(c).into())); + eval bg_color_anim.value ((c) + model.background.bg_color.set(color::Rgba::from(c).into())); // === Tooltip === @@ -780,7 +764,7 @@ impl Node { frp.source.tooltip <+ model.output.frp.tooltip.gate_not(&block_tooltip); - // === Output Label === + // === Type Labels === model.output.set_type_label_visibility <+ visualization_visible.not().and(&no_error_set); diff --git a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs index 5ee8377694..a47f2969e8 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs @@ -21,7 +21,7 @@ use text::Text; use crate::Type; use crate::component::type_coloring; use crate::node::input::port; -use crate::node::ExecutionStatus; +use crate::node::profiling; use crate::node; use crate::Mode as EditorMode; @@ -198,7 +198,7 @@ ensogl::define_endpoints! { set_ports_active (bool,Option), set_editor_mode (EditorMode), - set_execution_status (ExecutionStatus), + set_profiling_status (profiling::Status), } Output { @@ -398,6 +398,7 @@ impl Area { // === Editor Mode === + frp.output.source.editor_mode <+ frp.set_editor_mode; selection_color.target <+ frp.editor_mode.map(f!([model](&mode) { let path = match mode { @@ -688,15 +689,16 @@ impl Area { let styles = model.styles.clone_ref(); frp::extend! { port_network - base_color <- all_with3(&self.editor_mode,&self.set_execution_status,&frp.tp, + base_color <- all_with3(&self.editor_mode,&self.set_profiling_status,&frp.tp, f!([styles](&mode,&status,t) { + use theme::code::syntax; match (mode,status) { - (EditorMode::Normal,_) => + (EditorMode::Normal, _) => type_coloring::compute_for_code(t.as_ref(),&styles), - (EditorMode::Profiling,ExecutionStatus::Running) => - color::Lcha::from(styles.get_color(theme::code::syntax::base)), - (EditorMode::Profiling,ExecutionStatus::Finished {..}) => - color::Lcha::from(styles.get_color(theme::code::syntax::profiling::base)), + (EditorMode::Profiling, profiling::Status::Running) => + color::Lcha::from(styles.get_color(syntax::base)), + (EditorMode::Profiling, profiling::Status::Finished {..}) => + color::Lcha::from(styles.get_color(syntax::profiling::base)), } }) ); @@ -707,10 +709,10 @@ impl Area { frp::extend! { port_network is_selected <- frp.set_hover || frp.set_parent_connected; text_color_tgt <- all_with5(&is_selected,&self.frp.set_disabled, - &self.editor_mode,&self.set_execution_status,&base_color, + &self.editor_mode,&self.set_profiling_status,&base_color, f!([styles](&is_selected,&is_disabled,&mode,&status,&base_color) { let path = match (mode, status) { - (EditorMode::Profiling, ExecutionStatus::Finished {..}) => + (EditorMode::Profiling, profiling::Status::Finished {..}) => theme::code::syntax::profiling::HERE.path(), _ => theme::code::syntax::HERE.path(), @@ -726,13 +728,14 @@ impl Area { else if is_expected_arg { expected_color } else { base_color } })); - editing_color <- all_with(&self.editor_mode,&self.set_execution_status, + editing_color <- all_with(&self.editor_mode,&self.set_profiling_status, f!([styles](&mode,&status) { - let path = match (mode,status) { - (EditorMode::Profiling,ExecutionStatus::Finished {..}) => - theme::code::syntax::profiling::base, - _ => - theme::code::syntax::base, + use theme::code::syntax; + let is_profiled = mode.is_profiling() && status.is_finished(); + let path = if is_profiled { + syntax::profiling::base + } else { + syntax::base }; color::Lcha::from(styles.get_color(path)) })); @@ -763,8 +766,8 @@ impl Area { frp::extend! { port_network port_tp <- all(&frp.set_hover,&frp.tp)._1(); new_viz_color <- all_with3 - (&port_tp,&frp.set_connected,&self.editor_mode, - f!([styles](port_tp,(is_connected,edge_tp),editor_mode) { + (&port_tp,&frp.set_connected,&self.editor_mode + ,f!([styles](port_tp,(is_connected,edge_tp),editor_mode) { if *is_connected { match editor_mode { EditorMode::Normal => { diff --git a/src/rust/ide/view/graph-editor/src/component/node/output/port.rs b/src/rust/ide/view/graph-editor/src/component/node/output/port.rs index 150fc821eb..41dc60e9e8 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/output/port.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/output/port.rs @@ -62,10 +62,6 @@ const SHOW_TYPE_AS_LABEL : bool = true; /// ╰──────────────────────────────╯ ▼ (node_size / 2) + PORT_SIZE /// ◄──────────────────────────────► /// width = node_width + PORT_SIZE - - - - /// ``` /// /// The corners are rounded with the `radius = inner_radius + port_area_size`. The shape also @@ -555,9 +551,11 @@ impl Model { // === Type Label === - type_label_visibility <- frp.on_hover.and(&frp.set_type_label_visibility); - type_label_opacity.target <+ type_label_visibility.on_true().constant(PORT_OPACITY_HOVERED); - type_label_opacity.target <+ type_label_visibility.on_false().constant(0.0); + type_label_visibility <- frp.on_hover.and(&frp.set_type_label_visibility); + on_type_label_visible <- type_label_visibility.on_true(); + type_label_opacity.target <+ on_type_label_visible.constant(PORT_OPACITY_HOVERED); + type_label_opacity.target <+ type_label_visibility.on_false().constant(0.0); + type_label_color <- all_with(&color.value,&type_label_opacity.value, |color,&opacity| color.opaque.with_alpha(opacity).into()); type_label.set_color_all <+ type_label_color; diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs new file mode 100644 index 0000000000..affb53ff9c --- /dev/null +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs @@ -0,0 +1,222 @@ +//! Provides [`Status`] to represent a node's execution status, [`Status::display_color`] to express +//! that status as a color and [`RunningTimeLabel`] to display a node's execution status. + +use crate::prelude::*; + +use crate::Mode as EditorMode; + +use enso_frp as frp; +use ensogl::application::Application; +use ensogl::data::color; +use ensogl::display::shape::*; +use ensogl::display; +use ensogl::gui::text; +use ensogl_theme::graph_editor::node::profiling as theme_path; + + + +// ================= +// === Constants === +// ================= + +const LABEL_OFFSET_Y: f32 = 35.0; + + + +// ============== +// === Status === +// ============== + +/// Describes whether the source code in a node is currently running or already finished. If it is +/// finished then the status contains the number of milliseconds that it took to run the code. +#[derive(Debug,Copy,Clone)] +pub enum Status { + /// The node's code is still running. + Running, + /// The node finished execution. + Finished { + /// How many milliseconds the node took to execute. + duration: f32, + } +} + +impl Default for Status { + fn default() -> Self { + Status::Running + } +} + +impl Status { + /// Returns `true` if the node is still running. + pub fn is_running(self) -> bool { + matches!(self,Status::Running) + } + + /// Returns `true` if the node finished execution. + pub fn is_finished(self) -> bool { + matches!(self,Status::Finished {..}) + } +} + + + +// ============= +// === Color === +// ============= + +/// A theme that determines how we express the running time of a node (compared to other nodes on +/// the stage) in a color. The color's lightness and chroma in LCh color space are directly taken +/// from the theme. The chroma will be `min_time_hue` for the node with the shortest running time, +/// `max_time_hue` for the node with the longest running time and linearly interpolated in-between +/// depending on the relative running, time for all other nodes. +#[derive(Debug,Copy,Clone,Default)] +pub struct Theme { + /// The lightness for all running times. + pub lightness : f32, + /// The chroma for all running times. + pub chroma : f32, + /// The hue for the minimum running time. + pub min_time_hue : f32, + /// The hue for the maximum running time. + pub max_time_hue : f32, +} + +impl Status { + /// Expresses the profiling status as a color, depending on the minimum and maximum running + /// time of any node on the stage and a [`Theme`] that allows to tweak how the colors are + /// chosen. A node that is still running will be treated like finished node with the current + /// maximum execution time. + pub fn display_color + (self, min_global_duration: f32, max_global_duration: f32, theme: Theme) -> color::Lch { + let duration = match self { + Status::Running => max_global_duration, + Status::Finished {duration} => duration, + }; + let duration_delta = max_global_duration - min_global_duration; + let hue_delta = theme.max_time_hue - theme.min_time_hue; + let relative_duration = if duration_delta != 0.0 { + (duration - min_global_duration) / duration_delta + } else { + 0.0 + }; + let relative_hue = relative_duration; + let hue = theme.min_time_hue + relative_hue * hue_delta; + color::Lch::new(theme.lightness, theme.chroma, hue) + } +} + + + +// ============ +// === Frp === +// ============ + +ensogl::define_endpoints! { + Input { + set_status (Status), + set_min_global_duration (f32), + set_max_global_duration (f32), + set_editor_mode (EditorMode), + } +} + + + +// ========================== +// === Running Time Label === +// ========================== + +/// A `display::Object` providing a label for nodes that displays the node's running time in +/// profiling mode after the node finished execution. The node's execution status has to be provided +/// through `set_status`, the diplay mode through `set_editor_mode`, the minimum and maximum running +/// time of any node on the stage through `set_min_global_duration` and `set_max_global_duration`. +/// The color of the label will reflect the status and be determined by [`Status::display_color`]. +/// The necessary theme will be taken from the application's style sheet. The origin of the label, +/// as a `display::Object` should be placed on the node's center. +#[derive(Clone,CloneRef,Debug)] +pub struct RunningTimeLabel { + root : display::object::Instance, + label : text::Area, + frp : Frp, + styles : StyleWatchFrp, +} + +impl Deref for RunningTimeLabel { + type Target = Frp; + + fn deref(&self) -> &Self::Target { + &self.frp + } +} + +impl RunningTimeLabel { + /// Constructs a `RunningTimeLabel` for the given application. + pub fn new(app: &Application) -> Self { + let scene = app.display.scene(); + let root = display::object::Instance::new(Logger::new("ProfilingIndicator")); + + let label = text::Area::new(app); + root.add_child(&label); + label.set_position_y(LABEL_OFFSET_Y); + label.remove_from_scene_layer_DEPRECATED(&scene.layers.main); + label.add_to_scene_layer_DEPRECATED(&scene.layers.label); + + let styles = StyleWatchFrp::new(&scene.style_sheet); + let lightness = styles.get_number_or(theme_path::lightness,0.5); + let chroma = styles.get_number_or(theme_path::chroma,1.0); + let min_time_hue = styles.get_number_or(theme_path::min_time_hue,0.4); + let max_time_hue = styles.get_number_or(theme_path::max_time_hue,0.1); + + let frp = Frp::new(); + let network = &frp.network; + let color = color::Animation::new(network); + + frp::extend! { network + + // === Visibility === + + visibility <- all_with(&frp.set_editor_mode,&frp.set_status,|mode,status| { + matches!((mode,status),(EditorMode::Profiling,Status::Finished {..})) + }); + + color.target_alpha <+ visibility.map(|&is_visible| { + if is_visible { 1.0 } else { 0.0 } + }); + + + // === Color === + + theme <- all_with4(&lightness,&chroma,&min_time_hue,&max_time_hue, + |&lightness,&chroma,&min_time_hue,&max_time_hue| + Theme {lightness,chroma,max_time_hue,min_time_hue}); + color.target_color <+ all_with4 + (&frp.set_status,&frp.set_min_global_duration,&frp.set_max_global_duration,&theme, + |&status,&min,&max,&theme| status.display_color(min,max,theme) + ); + label.set_default_color <+ color.value.map(|c| c.into()); + label.set_color_all <+ color.value.map(|c| c.into()); + + + // === Position === + + eval label.width((&width) label.set_position_x(-width/2.0)); + + + // === Content === + + label.set_content <+ frp.set_status.map(|&status| + match status { + Status::Running => "".to_string(), + Status::Finished {duration} => format!("{} ms", duration) + }); + } + + RunningTimeLabel {root,label,frp,styles} + } +} + +impl display::Object for RunningTimeLabel { + fn display_object(&self) -> &display::object::Instance { + &self.root + } +} diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs deleted file mode 100644 index 431c8a7b24..0000000000 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling_indicator.rs +++ /dev/null @@ -1,137 +0,0 @@ -use crate::prelude::*; - -use crate::Mode as EditorMode; -use crate::component::node; -use node::ExecutionStatus; - -use enso_frp as frp; -use ensogl::application::Application; -use ensogl::data::color; -use ensogl::display::shape::*; -use ensogl::display; -use ensogl::gui::text; - - - -// ================= -// === Constants === -// ================= - -const LABEL_OFFSET_Y: f32 = 35.0; - - - -// ============ -// === Frp === -// ============ - -ensogl::define_endpoints! { - Input { - set_execution_status (ExecutionStatus), - set_min_global_duration (f32), - set_max_global_duration (f32), - set_editor_mode (EditorMode), - } -} - - - -// =========================== -// === Profiling Indicator === -// =========================== - -#[derive(Clone,CloneRef,Debug)] -pub struct ProfilingIndicator { - root : display::object::Instance, - label : text::Area, - frp : Frp, -} - -impl Deref for ProfilingIndicator { - type Target = Frp; - - fn deref(&self) -> &Self::Target { - &self.frp - } -} - - -impl ProfilingIndicator { - pub fn new(app: &Application) -> Self { - let scene = app.display.scene(); - let styles = StyleWatch::new(&scene.style_sheet); - let root = display::object::Instance::new(Logger::new("ProfilingIndicator")); - - let label = text::Area::new(app); - root.add_child(&label); - label.set_position_y(LABEL_OFFSET_Y); - label.remove_from_scene_layer_DEPRECATED(&scene.layers.main); - label.add_to_scene_layer_DEPRECATED(&scene.layers.label); - - let frp = Frp::new(); - let network = &frp.network; - let color = color::Animation::new(network); - - frp::extend! { network - - // === Visibility === - - visibility <- all_with(&frp.set_editor_mode,&frp.set_execution_status,|mode,status| { - matches!((mode,status),(EditorMode::Profiling,ExecutionStatus::Finished {..})) - }); - - color.target_alpha <+ visibility.map(|&is_visible| { - if is_visible { 1.0 } else { 0.0 } - }); - - - // === Color === - - color.target_color <+ all_with3 - (&frp.set_execution_status,&frp.set_min_global_duration, - &frp.set_max_global_duration,f!([styles](&status,&min,&max) { - let theme = ensogl_theme::graph_editor::node::profiling::HERE.path(); - let lightness = styles.get_number(theme.sub("lightness")); - let chroma = styles.get_number(theme.sub("chroma")); - let min_hue = styles.get_number(theme.sub("min_hue")); - let max_hue = styles.get_number(theme.sub("max_hue")); - let hue_delta = max_hue - min_hue; - let running_color = color::Lch::new(lightness,chroma,max_hue); - match status { - ExecutionStatus::Running => running_color, - ExecutionStatus::Finished {duration} => { - let relative_duration = (duration - min) / (max - min); - let hue = min_hue + relative_duration * hue_delta; - color::Lch::new(lightness,chroma,hue) - } - } - }) - ); - label.set_default_color <+ color.value.map(|c| c.into()); - label.set_color_all <+ color.value.map(|c| c.into()); - - - // === Position === - - eval label.width((&width) label.set_position_x(-width/2.0)); - - - // === Content === - - label.set_content <+ frp.set_execution_status.map(|&status| - match status { - ExecutionStatus::Running => "".to_string(), - ExecutionStatus::Finished {duration} => format!("{} ms", duration) - }); - } - - ProfilingIndicator {root,label,frp} - } -} - - -impl display::Object for ProfilingIndicator { - fn display_object(&self) -> &display::object::Instance { - &self.root - } -} diff --git a/src/rust/ide/view/graph-editor/src/component/profiling.rs b/src/rust/ide/view/graph-editor/src/component/profiling.rs new file mode 100644 index 0000000000..f4bd710aa1 --- /dev/null +++ b/src/rust/ide/view/graph-editor/src/component/profiling.rs @@ -0,0 +1,173 @@ +//! Profides a button that can be used to toggle the editor's profiling mode. + +use crate::prelude::*; + +use enso_frp as frp; +use ensogl::application::Application; +use ensogl::data::color; +use ensogl::display::shape::*; +use ensogl::display; +use ensogl_gui_components::toggle_button::ToggleButton; +use ensogl_gui_components::toggle_button; + + +// ============ +// === Icon === +// ============ + +mod icon { + use super::*; + use ensogl_gui_components::toggle_button::ColorableShape; + + ensogl::define_shape_system! { + (color_rgba:Vector4) { + let fill_color = Var::::from(color_rgba); + let width = Var::::from("input_size.x"); + let height = Var::::from("input_size.y"); + + let unit = &width * 0.3; + let outer_circle_radius = &unit * 1.0; + let outer_circle_thickness = &unit * 0.33; + let inner_circle_radius = &unit * 0.2; + let needle_radius_inner = &unit * 0.14; + let needle_radius_outer = &unit * 0.09; + let needle_angle = (135.0_f32).to_radians().radians(); + + let base = Circle(&outer_circle_radius); + let circle_gap = Circle(&outer_circle_radius-&outer_circle_thickness); + + // We make the gap a little bit larger than the circle to be sure that we really cover + // everything that we want to cut, even if there are rounding errors or similar + // imprecisions. + let aperture_gap_size = &outer_circle_radius * 1.1; + let aperture_gap = Triangle(&aperture_gap_size*2.0,aperture_gap_size.clone()); + let aperture_gap = aperture_gap.rotate(needle_angle+180.0_f32.to_radians().radians()); + let aperture_gap = aperture_gap.translate_x(&aperture_gap_size*2.0.sqrt()*0.25); + let aperture_gap = aperture_gap.translate_y(-(&aperture_gap_size*2.0.sqrt()*0.25)); + + let aperture_cap_1 = Circle(&outer_circle_thickness*0.5); + let aperture_cap_1 = aperture_cap_1.translate_x(&outer_circle_radius-&outer_circle_thickness*0.5); + let aperture_cap_2 = Circle(&outer_circle_thickness*0.5); + let aperture_cap_2 = aperture_cap_2.translate_y(-(&outer_circle_radius-&outer_circle_thickness*0.5)); + + let outer_circle = base - circle_gap - aperture_gap + aperture_cap_1 + aperture_cap_2; + + let needle_length = &outer_circle_radius-&needle_radius_outer; + let needle = UnevenCapsule(needle_radius_outer,needle_radius_inner,needle_length); + let needle = needle.rotate(&needle_angle); + + let inner_circle = Circle(&inner_circle_radius); + + let shape = (outer_circle + needle + inner_circle).fill(fill_color); + let hover_area = Rect((&width,&height)).fill(HOVER_COLOR); + (shape + hover_area).into() + } + } + + impl ColorableShape for DynamicShape { + fn set_color(&self, color: color::Rgba) { + self.color_rgba.set(Vector4::new(color.red, color.green, color.blue, color.alpha)); + } + } +} + + + +// ============ +// === Frp === +// ============ + +ensogl::define_endpoints! { + Input { + set_mode (crate::Mode), + } + Output { + mode (crate::Mode), + } +} + + + +// ======================= +// === ProfilingButton === +// ======================= + +/// A toggle button that can be used to toggle the graph editor's mode. It positions itself in the +/// upper right corner of the scene. +#[derive(Debug,Clone,CloneRef)] +pub struct Button { + frp : Frp, + button : ToggleButton, + styles : StyleWatchFrp, +} + +impl Deref for Button { + type Target = Frp; + + fn deref(&self) -> &Self::Target { + &self.frp + } +} + +impl Button { + /// Constructs a new button for toggling the editor mode. + pub fn new(app: &Application) -> Button { + let scene = app.display.scene(); + let styles = StyleWatchFrp::new(&scene.style_sheet); + let frp = Frp::new(); + let network = &frp.network; + + let button = ToggleButton::::new(Logger::new("profiling::Button")); + scene.layers.breadcrumbs_background.add_exclusive(&button); + button.set_visibility(true); + button.set_size(Vector2(32.0, 32.0)); + + frp::extend! { network + + // === State === + + frp.source.mode <+ button.state.map(|&toggled| { + if toggled { crate::Mode::Profiling } else { crate::Mode::Normal } + }); + button.set_state <+ frp.set_mode.map(|&mode| { + matches!(mode,crate::Mode::Profiling) + }); + + + // === Position === + + eval scene.frp.camera_changed([button,scene](_) { + let screen = scene.camera().screen(); + button.set_position_x(screen.width/2.0 - 16.0); + button.set_position_y(screen.height/2.0 - 16.0); + }); + + + // === Color === + + use ensogl_theme::graph_editor::profiling_button as button_theme; + let non_toggled_color = styles.get_color(button_theme::non_toggled); + let toggled_color = styles.get_color(button_theme::toggled); + let hovered_color = styles.get_color(button_theme::hovered); + let toggled_hovered_color = styles.get_color(button_theme::toggled_hovered); + button.set_color_scheme <+ all_with4(&non_toggled_color,&toggled_color,&hovered_color + ,&toggled_hovered_color,|&non_toggled,&toggled,&hovered,&toggled_hovered| + toggle_button::ColorScheme { + non_toggled : Some(non_toggled.into()), + toggled : Some(toggled.into()), + hovered : Some(hovered.into()), + toggled_hovered : Some(toggled_hovered.into()), + ..default() + } + ); + } + + Button {frp,button,styles} + } +} + +impl display::Object for Button { + fn display_object(&self) -> &display::object::Instance { + self.button.display_object() + } +} diff --git a/src/rust/ide/view/graph-editor/src/display.rs b/src/rust/ide/view/graph-editor/src/display.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index 11822cfc50..dc5adbf274 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -34,10 +34,10 @@ pub mod component; pub mod builtin; pub mod data; -mod profiling_icon; +mod profiling; use crate::component::node; -pub use crate::component::node::ExecutionStatus as NodeExecutionStatus; +pub use crate::component::node::profiling::Status as NodeProfilingStatus; use crate::component::tooltip::Tooltip; use crate::component::visualization::instance::PreprocessorConfiguration; use crate::component::tooltip; @@ -61,12 +61,9 @@ use ensogl::display::object::Id; use ensogl::display::shape::StyleWatch; use ensogl::display; use ensogl::gui::cursor; -use ensogl_gui_components::toggle_button; -use ensogl_gui_components::toggle_button::ToggleButton; use ensogl::prelude::*; use ensogl::system::web; use ensogl_theme as theme; -use std::f32; @@ -126,6 +123,16 @@ impl Default for Mode { } } +impl Mode { + pub fn is_normal(self) -> bool { + matches!(self,Mode::Normal) + } + + pub fn is_profiling(self) -> bool { + matches!(self,Mode::Profiling) + } +} + // ================= @@ -429,7 +436,7 @@ ensogl::define_endpoints! { /// Indicate whether this node had an error or not. set_node_error_status(NodeId,Option), /// Indicate whether this node has finished execution. - set_node_execution_status(NodeId,NodeExecutionStatus), + set_node_profiling_status(NodeId,node::profiling::Status), // === Visualization === @@ -1002,87 +1009,6 @@ impl Edges { -// ========================= -// === ExecutionStatuses === -// ========================= - -/// [`ExecutionsStatuses`] can be used to collect the execution statuses of all nodes in a graph. It -/// exposes their minimum and maximum running times through its FRP endpoints. The structure needs -/// to be updated whenever a node is added or deleted or changes its execution status. -mod execution_statuses { - use bimap::BiBTreeMap; - use ordered_float::OrderedFloat; - - use super::*; - - ensogl::define_endpoints! { - Input { - set (NodeId, NodeExecutionStatus), - remove (NodeId) - } - Output { - min_duration (f32), - max_duration (f32), - } - } - - #[derive(Debug,Clone,CloneRef,Default)] - pub struct ExecutionStatuses { - frp : Frp, - durations : Rc>>> - } - - impl Deref for ExecutionStatuses { - type Target = Frp; - - fn deref(&self) -> &Self::Target { - &self.frp - } - } - - impl ExecutionStatuses { - pub fn new() -> Self { - let frp = Frp::new(); - let durations = Rc::new(RefCell::new(BiBTreeMap::>::new())); - - let network = &frp.network; - frp::extend! { network - min_and_max_from_set <- frp.set.map(f!([durations]((node,status)) { - match status { - NodeExecutionStatus::Finished {duration} => { - durations.borrow_mut().insert(*node,OrderedFloat(*duration)); - }, - _ => { - durations.borrow_mut().remove_by_left(node); - }, - }; - Self::min_and_max(&*durations.borrow()) - })); - - min_and_max_from_remove <- frp.remove.map(f!([durations](node) { - durations.borrow_mut().remove_by_left(&node); - Self::min_and_max(&*durations.borrow()) - })); - - min_and_max <- any(&min_and_max_from_set,&min_and_max_from_remove); - frp.source.min_duration <+ min_and_max._0().on_change(); - frp.source.max_duration <+ min_and_max._1().on_change(); - } - - Self {frp,durations} - } - - fn min_and_max(durations:&BiBTreeMap>) -> (f32,f32) { - let mut durations = durations.right_values().copied(); - let min = durations.next().map(OrderedFloat::into_inner).unwrap_or(f32::INFINITY); - let max = durations.last().map(OrderedFloat::into_inner).unwrap_or(0.0); - (min, max) - } - } -} -use execution_statuses::ExecutionStatuses; - - #[derive(Debug,Clone,CloneRef,Default)] struct Visualisations { /// This keeps track of the currently selected visualisation. There should only ever be one @@ -1302,10 +1228,12 @@ impl GraphEditorModelWithNetwork { // === Profiling === - node.set_profiling_min_global_duration <+ self.model.execution_statuses.min_duration; - node.set_profiling_min_global_duration(self.model.execution_statuses.min_duration.value()); - node.set_profiling_max_global_duration <+ self.model.execution_statuses.max_duration; - node.set_profiling_max_global_duration(self.model.execution_statuses.max_duration.value()); + let profiling_min_duration = &self.model.profiling_statuses.min_duration; + node.set_profiling_min_global_duration <+ self.model.profiling_statuses.min_duration; + node.set_profiling_min_global_duration(profiling_min_duration.value()); + let profiling_max_duration = &self.model.profiling_statuses.max_duration; + node.set_profiling_max_global_duration <+ self.model.profiling_statuses.max_duration; + node.set_profiling_max_global_duration(profiling_max_duration.value()); } node.set_editor_mode(self.model.frp.mode.value()); let initial_metadata = visualization::Metadata { @@ -1413,8 +1341,8 @@ pub struct GraphEditorModel { visualisations : Visualisations, frp : FrpEndpoints, navigator : Navigator, - execution_statuses : ExecutionStatuses, - profiling_button : ToggleButton, + profiling_statuses : profiling::Statuses, + profiling_button : component::profiling::Button, } @@ -1440,12 +1368,12 @@ impl GraphEditorModel { let frp = frp.output.clone_ref(); let navigator = Navigator::new(&scene,&scene.camera()); let tooltip = Tooltip::new(&app); - let execution_statuses = ExecutionStatuses::new(); - let profiling_button = ToggleButton::::new(&logger); + let profiling_statuses = profiling::Statuses::new(); + let profiling_button = component::profiling::Button::new(&app); Self { logger,display_object,app,cursor,nodes,edges,touch_state,frp,breadcrumbs, - vis_registry,visualisations,navigator,tooltip,execution_statuses,profiling_button, + vis_registry,visualisations,navigator,tooltip,profiling_statuses,profiling_button, }.init() } @@ -1457,22 +1385,7 @@ impl GraphEditorModel { self.breadcrumbs.set_position_y(y_offset); self.breadcrumbs.gap_width(traffic_lights_gap_width()); self.scene().add_child(&self.tooltip); - self.add_child(&self.profiling_button); - self.scene().layers.breadcrumbs_background.add_exclusive(&self.profiling_button); - self.profiling_button.set_visibility(true); - self.profiling_button.set_size(Vector2(32.0,32.0)); - - let styles = StyleWatch::new(&self.scene().style_sheet); - let color_scheme = toggle_button::ColorScheme { - non_toggled : Some(styles.get_color(theme::graph_editor::profiling_button::non_toggled).into()), - toggled : Some(styles.get_color(theme::graph_editor::profiling_button::toggled).into()), - hovered : Some(styles.get_color(theme::graph_editor::profiling_button::hovered).into()), - toggled_hovered : Some(styles.get_color(theme::graph_editor::profiling_button::toggled_hovered).into()), - ..default() - }; - self.profiling_button.set_color_scheme(&color_scheme); - self } @@ -2768,10 +2681,10 @@ fn new_graph_editor(app:&Application) -> GraphEditor { frp::extend! { network - eval inputs.set_node_execution_status([model]((node_id,status)) { + eval inputs.set_node_profiling_status([model]((node_id,status)) { if let Some(node) = model.nodes.get_cloned_ref(node_id) { - model.execution_statuses.set(*node_id,*status); - node.set_execution_status(status); + model.profiling_statuses.set(*node_id,*status); + node.set_profiling_status(status); } }); @@ -3193,7 +3106,7 @@ fn new_graph_editor(app:&Application) -> GraphEditor { eval out.node_selected ((id) model.select_node(id)); eval out.node_deselected ((id) model.deselect_node(id)); eval out.node_removed ((id) model.remove_node(id)); - model.execution_statuses.remove <+ out.node_removed; + model.profiling_statuses.remove <+ out.node_removed; out.source.on_visualization_select <+ out.node_removed.map(|&id| Switch::Off(id)); eval inputs.set_node_expression (((id,expr)) model.set_node_expression(id,expr)); @@ -3278,10 +3191,13 @@ fn new_graph_editor(app:&Application) -> GraphEditor { out.source.mode <+ frp.toggle_profiling_mode.map2(&frp.mode,|_,&mode| { match mode { Mode::Profiling => Mode::Normal, - _ => Mode::Profiling, + Mode::Normal => Mode::Profiling, } }); + out.source.mode <+ model.profiling_button.mode; + model.profiling_button.set_mode <+ out.mode.on_change(); + eval out.mode([model](_) { for edge_id in model.edges.keys() { model.refresh_edge_color(edge_id); @@ -3294,26 +3210,7 @@ fn new_graph_editor(app:&Application) -> GraphEditor { Mode::Profiling => 1.0, } }); - eval profiling_mode_transition.value ((&v) scene.dom.layers.back.set_grayscale(v)); - } - - - // === Profiling Button === - - frp::extend! { network - out.source.mode <+ model.profiling_button.state.map(|&toggled| { - if toggled { Mode::Profiling } else { Mode::Normal } - }); - - model.profiling_button.set_state <+ out.mode.on_change().map(|&mode| { - matches!(mode,Mode::Profiling) - }); - - eval scene.frp.camera_changed([model,scene](_) { - let screen = scene.camera().screen(); - model.profiling_button.set_position_x(screen.width/2.0 - 16.0); - model.profiling_button.set_position_y(screen.height/2.0 - 16.0); - }); + eval profiling_mode_transition.value ((&v) scene.dom.layers.back.filter_grayscale(v)); } diff --git a/src/rust/ide/view/graph-editor/src/profiling.rs b/src/rust/ide/view/graph-editor/src/profiling.rs new file mode 100644 index 0000000000..ca6ac283af --- /dev/null +++ b/src/rust/ide/view/graph-editor/src/profiling.rs @@ -0,0 +1,73 @@ +//! [`ProfilingStatuses`] can be used to collect the profiling statuses of all nodes in a graph. It +//! exposes their minimum and maximum running times through its FRP endpoints. The structure needs +//! to be updated whenever a node is added or deleted or changes its profiling status. + +use bimap::BiBTreeMap; +use ordered_float::OrderedFloat; + +use super::*; + +ensogl::define_endpoints! { + Input { + set (NodeId,node::profiling::Status), + remove (NodeId) + } + Output { + min_duration (f32), + max_duration (f32), + } +} + +#[derive(Debug,Clone,CloneRef,Default)] +pub struct Statuses { + frp : Frp, + durations : Rc>>> +} + +impl Deref for Statuses { + type Target = Frp; + + fn deref(&self) -> &Self::Target { + &self.frp + } +} + +impl Statuses { + pub fn new() -> Self { + let frp = Frp::new(); + let durations = Rc::new(RefCell::new(BiBTreeMap::>::new())); + + let network = &frp.network; + frp::extend! { network + min_and_max_from_set <- frp.set.map(f!([durations]((node,status)) { + match status { + node::profiling::Status::Finished {duration} => { + durations.borrow_mut().insert(*node,OrderedFloat(*duration)); + }, + _ => { + durations.borrow_mut().remove_by_left(node); + }, + }; + Self::min_and_max(&*durations.borrow()) + })); + + min_and_max_from_remove <- frp.remove.map(f!([durations](node) { + durations.borrow_mut().remove_by_left(&node); + Self::min_and_max(&*durations.borrow()) + })); + + min_and_max <- any(&min_and_max_from_set,&min_and_max_from_remove); + frp.source.min_duration <+ min_and_max._0().on_change(); + frp.source.max_duration <+ min_and_max._1().on_change(); + } + + Self {frp,durations} + } + + fn min_and_max(durations:&BiBTreeMap>) -> (f32,f32) { + let mut durations = durations.right_values().copied(); + let min = durations.next().map(OrderedFloat::into_inner).unwrap_or(std::f32::INFINITY); + let max = durations.last().map(OrderedFloat::into_inner).unwrap_or(0.0); + (min, max) + } +} diff --git a/src/rust/ide/view/graph-editor/src/profiling_icon.rs b/src/rust/ide/view/graph-editor/src/profiling_icon.rs deleted file mode 100644 index 36355b9f18..0000000000 --- a/src/rust/ide/view/graph-editor/src/profiling_icon.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::prelude::*; - -use ensogl::data::color; -use ensogl::display::shape::*; -use ensogl_gui_components::toggle_button::ColorableShape; - -ensogl::define_shape_system! { - (color_rgba:Vector4) { - let fill_color = Var::::from(color_rgba); - let width = Var::::from("input_size.x"); - let height = Var::::from("input_size.y"); - - let unit = &width * 0.3; - let outer_circle_radius = &unit * 1.0; - let outer_circle_thickness = &unit * 0.33; - let inner_circle_radius = &unit * 0.2; - let needle_radius_inner = &unit * 0.14; - let needle_radius_outer = &unit * 0.09; - let needle_angle = (135.0_f32).to_radians().radians(); - - let base = Circle(&outer_circle_radius); - let circle_gap = Circle(&outer_circle_radius-&outer_circle_thickness); - - // We make the gap a little bit larger than the circle to be sure that we really cover - // everything that we want to cut, even if there are rounding errors or similar - // imprecisions. - let aperture_gap_size = &outer_circle_radius * 1.1; - let aperture_gap = Triangle(&aperture_gap_size*2.0,aperture_gap_size.clone()); - let aperture_gap = aperture_gap.rotate(needle_angle+180.0_f32.to_radians().radians()); - let aperture_gap = aperture_gap.translate_x(&aperture_gap_size*2.0.sqrt()*0.25); - let aperture_gap = aperture_gap.translate_y(-(&aperture_gap_size*2.0.sqrt()*0.25)); - - let aperture_cap_1 = Circle(&outer_circle_thickness*0.5); - let aperture_cap_1 = aperture_cap_1.translate_x(&outer_circle_radius-&outer_circle_thickness*0.5); - let aperture_cap_2 = Circle(&outer_circle_thickness*0.5); - let aperture_cap_2 = aperture_cap_2.translate_y(-(&outer_circle_radius-&outer_circle_thickness*0.5)); - - let outer_circle = base - circle_gap - aperture_gap + aperture_cap_1 + aperture_cap_2; - - let needle_length = &outer_circle_radius-&needle_radius_outer; - let needle = UnevenCapsule(needle_radius_outer,needle_radius_inner,needle_length); - let needle = needle.rotate(&needle_angle); - - let inner_circle = Circle(&inner_circle_radius); - - let shape = (outer_circle + needle + inner_circle).fill(fill_color); - let hover_area = Rect((&width,&height)).fill(HOVER_COLOR); - (shape + hover_area).into() - } -} - -impl ColorableShape for DynamicShape { - fn set_color(&self, color:color::Rgba) { - self.color_rgba.set(Vector4::new(color.red,color.green,color.blue,color.alpha)); - } -} \ No newline at end of file diff --git a/src/rust/ide/view/src/debug_scenes/interface.rs b/src/rust/ide/view/src/debug_scenes/interface.rs index a85f14c507..8cd6b8ddb2 100644 --- a/src/rust/ide/view/src/debug_scenes/interface.rs +++ b/src/rust/ide/view/src/debug_scenes/interface.rs @@ -8,7 +8,7 @@ use crate::prelude::*; use crate::graph_editor; use crate::graph_editor::GraphEditor; -use crate::graph_editor::NodeExecutionStatus; +use crate::graph_editor::NodeProfilingStatus; use crate::graph_editor::Type; use crate::project; use crate::status_bar; @@ -196,12 +196,12 @@ fn init(app:&Application) { // === Profiling === - let node1_status = NodeExecutionStatus::Finished { duration: 400.0 }; - graph_editor.set_node_execution_status(node1_id, node1_status); - let node2_status = NodeExecutionStatus::Finished { duration: 300.0 }; - graph_editor.set_node_execution_status(node2_id, node2_status); - let node3_status = NodeExecutionStatus::Finished { duration: 200.0 }; - graph_editor.set_node_execution_status(node3_id, node3_status); + let node1_status = NodeProfilingStatus::Finished { duration: 400.0 }; + graph_editor.set_node_profiling_status(node1_id, node1_status); + let node2_status = NodeProfilingStatus::Finished { duration: 300.0 }; + graph_editor.set_node_profiling_status(node2_id, node2_status); + let node3_status = NodeProfilingStatus::Finished { duration: 200.0 }; + graph_editor.set_node_profiling_status(node3_id, node3_status); // let tgt_type = dummy_type_generator.get_dummy_type(); diff --git a/src/rust/lib/frp/src/nodes.rs b/src/rust/lib/frp/src/nodes.rs index 560a2c9448..8c23ad58ce 100644 --- a/src/rust/lib/frp/src/nodes.rs +++ b/src/rust/lib/frp/src/nodes.rs @@ -494,17 +494,19 @@ impl Network { /// Specialized version `all_with`. pub fn all_with5 (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, f:F) -> Stream - where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, - T:Data, F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->T { + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T:Data, F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->T { self.register(OwnedAllWith5::new(label,t1,t2,t3,t4,t5,f)) } /// Specialized version `all_with`. pub fn all_with8 - (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, t6:&T6, t7:&T7, t8:&T8, f:F) -> Stream - where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, - T6:EventOutput, T7:EventOutput, T8:EventOutput, T:Data, - F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output,&Output,&Output)->T { + (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, t6:&T6, t7:&T7, t8:&T8, f:F) + -> Stream + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, T7:EventOutput, T8:EventOutput, T:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output + ,&Output,&Output)->T { self.register(OwnedAllWith8::new(label,t1,t2,t3,t4,t5,t6,t7,t8,f)) } } @@ -2355,14 +2357,14 @@ pub type OwnedAllWith5 = stream::Node = stream::WeakNode >; impl HasOutput for AllWith5Data - where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, - F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { +where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { type Output = Out; } impl OwnedAllWith5 - where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, - F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { +where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, function:F) -> Self { let src1 = watch_stream(t1); @@ -2383,8 +2385,8 @@ impl OwnedAllWith5 } impl stream::EventConsumer for OwnedAllWith5 - where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, - F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { +where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output)->Out { fn on_event(&self, stack:CallStack, _:&T) { let value1 = self.src1.value(); let value2 = self.src2.value(); @@ -2413,22 +2415,28 @@ pub struct AllWith8Data { src1:watch::Ref, src2:watch::Ref, src3:watch::Ref, src4:watch::Ref , src5:watch::Ref, src6:watch::Ref, src7:watch::Ref, src8:watch::Ref , function:F } -pub type OwnedAllWith8 = stream::Node >; -pub type AllWith8 = stream::WeakNode >; +pub type OwnedAllWith8 = + stream::Node >; +pub type AllWith8 = + stream::WeakNode >; impl HasOutput for AllWith8Data - where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, - T6:EventOutput, T7:EventOutput, T8:EventOutput, Out:Data, - F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output,&Output,&Output)->Out { +where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, T7:EventOutput, T8:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output + ,&Output,&Output)->Out { type Output = Out; } impl OwnedAllWith8 - where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, - T6:EventOutput, T7:EventOutput, T8:EventOutput, Out:Data, - F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output,&Output,&Output)->Out { +where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, T7:EventOutput, T8:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output + ,&Output,&Output)->Out { /// Constructor. - pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, t6:&T6, t7:&T7, t8:&T8, function:F) -> Self { + pub fn new + (label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, t6:&T6, t7:&T7, t8:&T8, function:F) + -> Self { let src1 = watch_stream(t1); let src2 = watch_stream(t2); let src3 = watch_stream(t3); @@ -2437,9 +2445,9 @@ impl OwnedAllWith8 let src6 = watch_stream(t6); let src7 = watch_stream(t7); let src8 = watch_stream(t8); - let def = AllWith8Data {src1,src2,src3,src4,src5,src6,src7,src8,function}; - let this = Self::construct(label,def); - let weak = this.downgrade(); + let def = AllWith8Data {src1,src2,src3,src4,src5,src6,src7,src8,function}; + let this = Self::construct(label,def); + let weak = this.downgrade(); t1.register_target(weak.clone_ref().into()); t2.register_target(weak.clone_ref().into()); t3.register_target(weak.clone_ref().into()); @@ -2452,10 +2460,12 @@ impl OwnedAllWith8 } } -impl stream::EventConsumer for OwnedAllWith8 - where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, - T6:EventOutput, T7:EventOutput, T8:EventOutput, Out:Data, - F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output,&Output,&Output)->Out { +impl stream::EventConsumer +for OwnedAllWith8 +where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, T7:EventOutput, T8:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output + ,&Output,&Output)->Out { fn on_event(&self, stack:CallStack, _:&T) { let value1 = self.src1.value(); let value2 = self.src2.value(); @@ -2465,7 +2475,8 @@ impl stream::EventConsumer for OwnedAllWith8 let value6 = self.src6.value(); let value7 = self.src7.value(); let value8 = self.src8.value(); - let out = (self.function)(&value1,&value2,&value3,&value4,&value5,&value6,&value7,&value8); + + let out = (self.function)(&value1,&value2,&value3,&value4,&value5,&value6,&value7,&value8); self.emit_event(stack,&out); } } From c3cd76ae75a6337e3b7a20307edc19267a2c41e9 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Tue, 25 May 2021 14:07:22 +0100 Subject: [PATCH 18/29] Make requested changes --- src/rust/ensogl/lib/text/src/component.rs | 3 + .../ensogl/lib/text/src/component/area.rs | 184 +--------------- .../lib/text/src/component/selection.rs | 196 +++++++++++++++++ .../view/graph-editor/src/component/node.rs | 54 ++--- .../src/component/node/input/area.rs | 197 +++++++++--------- .../src/component/node/output/area.rs | 22 +- .../src/component/node/output/port.rs | 24 ++- .../src/component/node/profiling.rs | 109 ++++++---- .../graph-editor/src/component/profiling.rs | 84 +++++--- src/rust/ide/view/graph-editor/src/display.rs | 0 src/rust/ide/view/graph-editor/src/lib.rs | 149 ++++++------- .../ide/view/graph-editor/src/profiling.rs | 26 ++- src/rust/ide/view/graph-editor/src/view.rs | 43 ++++ .../ide/view/src/debug_scenes/interface.rs | 6 +- src/rust/lib/frp/src/nodes.rs | 78 ++++++- 15 files changed, 699 insertions(+), 476 deletions(-) create mode 100644 src/rust/ensogl/lib/text/src/component/selection.rs delete mode 100644 src/rust/ide/view/graph-editor/src/display.rs create mode 100644 src/rust/ide/view/graph-editor/src/view.rs diff --git a/src/rust/ensogl/lib/text/src/component.rs b/src/rust/ensogl/lib/text/src/component.rs index 8e4a34adc4..4f1159eb05 100644 --- a/src/rust/ensogl/lib/text/src/component.rs +++ b/src/rust/ensogl/lib/text/src/component.rs @@ -1,5 +1,8 @@ //! Visual components implementation. pub mod area; +#[warn(missing_docs)] +mod selection; pub use area::Area; +use selection::Selection; diff --git a/src/rust/ensogl/lib/text/src/component/area.rs b/src/rust/ensogl/lib/text/src/component/area.rs index f0ce1e8992..adaded31fc 100644 --- a/src/rust/ensogl/lib/text/src/component/area.rs +++ b/src/rust/ensogl/lib/text/src/component/area.rs @@ -12,6 +12,8 @@ use crate::typeface::glyph::Glyph; use crate::typeface::glyph; use crate::typeface::pen; use crate::typeface; +use crate::component::selection; +use crate::component::Selection; use enso_frp as frp; use enso_frp::io::keyboard::Key; @@ -23,7 +25,6 @@ use ensogl_core::data::color; use ensogl_core::display::shape::*; use ensogl_core::display; use ensogl_core::gui::cursor; -use ensogl_core::system::gpu::shader::glsl::traits::IntoGlsl; use ensogl_core::system::web::clipboard; use std::ops::Not; @@ -36,179 +37,7 @@ use std::ops::Not; /// Record separator ASCII code. Used for separating of copied strings. It is defined as the `\RS` /// escape code (`x1E`) (https://en.wikipedia.org/wiki/ASCII). pub const RECORD_SEPARATOR : &str = "\x1E"; - - - -// ============== -// === Cursor === -// ============== - const LINE_VERTICAL_OFFSET : f32 = 4.0; // Set manually. May depend on font. To be improved. -const CURSOR_PADDING : f32 = 4.0; -const CURSOR_WIDTH : f32 = 2.0; -const CURSOR_ALPHA : f32 = 0.8; -const CURSORS_SPACING : f32 = 1.0; -const SELECTION_ALPHA : f32 = 0.3; -const SELECTION_CORNER_RADIUS : f32 = 2.0; -const BLINK_SLOPE_IN_DURATION : f32 = 200.0; -const BLINK_SLOPE_OUT_DURATION : f32 = 200.0; -const BLINK_ON_DURATION : f32 = 300.0; -const BLINK_OFF_DURATION : f32 = 300.0; -const BLINK_PERIOD : f32 = - BLINK_SLOPE_IN_DURATION + BLINK_SLOPE_OUT_DURATION + BLINK_ON_DURATION + BLINK_OFF_DURATION; - - -/// Text cursor and selection shape definition. If the shape is narrow, it is considered a cursor, -/// and thus, it blinks. -/// -/// ## Blinking Implementation -/// -/// The blinking alpha is a time-dependent function which starts as a fully opaque value and -/// changes periodically. The `start_time` parameter is set to the current time after each cursor -/// operation, which makes cursor visible during typing and after position change. -/// -/// ```compile_fail -/// | -/// | on off -/// | <------> <-------> -/// | --------. .--------. .-... -/// | \ / \ / -/// | '---------' '---------' -/// | <-> <-> -/// | slope_out slope_in -/// | time -/// |--------------------------------------------------> -/// start time -/// ``` -pub mod selection { - use super::*; - ensogl_core::define_shape_system! { - (style:Style, selection:f32, start_time:f32, letter_width:f32, color_rgb:Vector3) { - let width_abs = Var::::from("abs(input_size.x)"); - let height = Var::::from("input_size.y"); - let rect_width = width_abs - 2.0 * CURSOR_PADDING; - let rect_height = height - 2.0 * CURSOR_PADDING; - let time = Var::::from("input_time"); - let one = Var::::from(1.0); - let time = time - start_time; - let on_time = BLINK_ON_DURATION + BLINK_SLOPE_OUT_DURATION; - let off_time = on_time + BLINK_OFF_DURATION; - let sampler = time % BLINK_PERIOD; - let slope_out = sampler.smoothstep(BLINK_ON_DURATION,on_time); - let slope_in = sampler.smoothstep(off_time,BLINK_PERIOD); - let blinking_alpha = (one - slope_out + slope_in) * CURSOR_ALPHA; - let sel_width = &rect_width - CURSOR_WIDTH; - let alpha_weight = sel_width.smoothstep(0.0,letter_width); - let alpha = alpha_weight.mix(blinking_alpha,SELECTION_ALPHA); - let shape = Rect((1.px() * rect_width,1.px() * rect_height)); - let shape = shape.corners_radius(SELECTION_CORNER_RADIUS.px()); - let color = format!("srgba({}.x,{}.y,{}.z,{})",color_rgb,color_rgb - ,color_rgb,alpha.glsl()); - let shape = shape.fill(color); - shape.into() - } - } -} - - - -// ================= -// === Selection === -// ================= - -/// Visual representation of text cursor and text selection. -/// -/// ## Implementation Notes -/// Selection contains a `right_side` display object which is always placed on its right side. It is -/// used for smooth glyph animation. For example, after several glyphs were selected and removed, -/// the selection will gradually shrink. Making all following glyphs children of the `right_side` -/// object will make the following glyphs animate while the selection is shrinking. -#[derive(Clone,CloneRef,Debug)] -pub struct Selection { - logger : Logger, - display_object : display::object::Instance, - right_side : display::object::Instance, - shape_view : selection::View, - network : frp::Network, - position : DEPRECATED_Animation, - width : DEPRECATED_Animation, - edit_mode : Rc>, - set_color : frp::Any, -} - -impl Deref for Selection { - type Target = selection::View; - fn deref(&self) -> &Self::Target { - &self.shape_view - } -} - -impl Selection { - /// Constructor. - pub fn new(logger:impl AnyLogger, edit_mode:bool) -> Self { - let logger = Logger::sub(logger,"selection"); - let display_object = display::object::Instance::new(&logger); - let right_side = display::object::Instance::new(&logger); - let network = frp::Network::new("text_selection"); - let shape_view = selection::View::new(&logger); - let position = DEPRECATED_Animation::new(&network); - let width = DEPRECATED_Animation::new(&network); - let edit_mode = Rc::new(Cell::new(edit_mode)); - let set_color = network.any_mut::("set_color"); - let debug = false; // Change to true to slow-down movement for debug purposes. - let spring_factor = if debug { 0.1 } else { 1.5 }; - - position . update_spring (|spring| spring * spring_factor); - width . update_spring (|spring| spring * spring_factor); - - Self {logger,display_object,right_side,shape_view,network,position,width,edit_mode - ,set_color}.init() - } - - fn init(self) -> Self { - let network = &self.network; - let view = &self.shape_view; - let object = &self.display_object; - let right_side = &self.right_side; - let shape_view = &self.shape_view; - self.add_child(view); - view.add_child(right_side); - frp::extend! { network - _eval <- all_with(&self.position.value,&self.width.value, - f!([view,object,right_side](p,width){ - let side = width.signum(); - let abs_width = width.abs(); - let width = max(CURSOR_WIDTH, abs_width - CURSORS_SPACING); - let view_width = CURSOR_PADDING * 2.0 + width; - let view_height = CURSOR_PADDING * 2.0 + LINE_HEIGHT; - let view_x = (abs_width/2.0) * side; - let view_y = 0.0; - object.set_position_xy(*p); - right_side.set_position_x(abs_width/2.0); - view.size.set(Vector2(view_width,view_height)); - view.set_position_xy(Vector2(view_x,view_y)); - }) - ); - eval self.set_color((color) shape_view.color_rgb.set(color.into())); - } - self - } - - fn flip_sides(&self) { - let width = self.width.target_value(); - self.position.set_value(self.position.value() + Vector2(width,0.0)); - self.position.set_target_value(self.position.target_value() + Vector2(width,0.0)); - - self.width.set_value(-self.width.value()); - self.width.set_target_value(-self.width.target_value()); - } -} - -impl display::Object for Selection { - fn display_object(&self) -> &display::object::Instance { - &self.display_object - } -} @@ -693,7 +522,8 @@ impl Area { fn symbols(&self) -> SmallVec<[display::Symbol;1]> { let text_symbol = self.data.glyph_system.sprite_system().symbol.clone_ref(); - let selection_system = self.data.app.display.scene().shapes.shape_system(PhantomData::); + let shapes = &self.data.app.display.scene().shapes; + let selection_system = shapes.shape_system(PhantomData::); let _selection_symbol = selection_system.shape_system.symbol.clone_ref(); //TODO[ao] we cannot move selection symbol, as it is global for all the text areas. SmallVec::from_buf([text_symbol,/*selection_symbol*/]) @@ -743,7 +573,7 @@ impl AreaModel { // FIXME[WD]: These settings should be managed wiser. They should be set up during // initialization of the shape system, not for every area creation. To be improved during // refactoring of the architecture some day. - let shape_system = scene.shapes.shape_system(PhantomData::); + let shape_system = scene.shapes.shape_system(PhantomData::); let symbol = &shape_system.shape_system.sprite_system.symbol; shape_system.shape_system.set_pointer_events(false); @@ -808,9 +638,9 @@ impl AreaModel { // animation frame. Multiple times, once per cursor. // https://github.com/enso-org/ide/issues/1031 eval_ selection.position.value (model.redraw(true)); - selection.set_color <+ self.frp_endpoints.selection_color; + selection.frp.set_color <+ self.frp_endpoints.selection_color; } - selection.set_color.emit(self.frp_endpoints.selection_color.value()); + selection.frp.set_color.emit(self.frp_endpoints.selection_color.value()); selection } }; diff --git a/src/rust/ensogl/lib/text/src/component/selection.rs b/src/rust/ensogl/lib/text/src/component/selection.rs new file mode 100644 index 0000000000..2940157e7a --- /dev/null +++ b/src/rust/ensogl/lib/text/src/component/selection.rs @@ -0,0 +1,196 @@ +//! Provides a text cursor and selection component. + +use crate::prelude::*; + +use enso_frp as frp; +use ensogl_core::DEPRECATED_Animation; +use ensogl_core::data::color; +use ensogl_core::display::shape::*; +use ensogl_core::display; +use ensogl_core::system::gpu::shader::glsl::traits::IntoGlsl; + + + +// ============== +// === Cursor === +// ============== + +const CURSOR_PADDING : f32 = 4.0; +const CURSOR_WIDTH : f32 = 2.0; +const CURSOR_ALPHA : f32 = 0.8; +const CURSORS_SPACING : f32 = 1.0; +const SELECTION_ALPHA : f32 = 0.3; +const SELECTION_CORNER_RADIUS : f32 = 2.0; +const BLINK_SLOPE_IN_DURATION : f32 = 200.0; +const BLINK_SLOPE_OUT_DURATION : f32 = 200.0; +const BLINK_ON_DURATION : f32 = 300.0; +const BLINK_OFF_DURATION : f32 = 300.0; +const BLINK_PERIOD : f32 = + BLINK_SLOPE_IN_DURATION + BLINK_SLOPE_OUT_DURATION + BLINK_ON_DURATION + BLINK_OFF_DURATION; + + + +/// Text cursor and selection shape definition. If the shape is narrow, it is considered a cursor, +/// and thus, it blinks. +/// +/// ## Blinking Implementation +/// +/// The blinking alpha is a time-dependent function which starts as a fully opaque value and +/// changes periodically. The `start_time` parameter is set to the current time after each cursor +/// operation, which makes cursor visible during typing and after position change. +/// +/// ```compile_fail +/// | +/// | on off +/// | <------> <-------> +/// | --------. .--------. .-... +/// | \ / \ / +/// | '---------' '---------' +/// | <-> <-> +/// | slope_out slope_in +/// | time +/// |--------------------------------------------------> +/// start time +/// ``` +pub mod shape { + use super::*; + + ensogl_core::define_shape_system! { + (style:Style, selection:f32, start_time:f32, letter_width:f32, color_rgb:Vector3) { + let width_abs = Var::::from("abs(input_size.x)"); + let height = Var::::from("input_size.y"); + let rect_width = width_abs - 2.0 * CURSOR_PADDING; + let rect_height = height - 2.0 * CURSOR_PADDING; + let time = Var::::from("input_time"); + let one = Var::::from(1.0); + let time = time - start_time; + let on_time = BLINK_ON_DURATION + BLINK_SLOPE_OUT_DURATION; + let off_time = on_time + BLINK_OFF_DURATION; + let sampler = time % BLINK_PERIOD; + let slope_out = sampler.smoothstep(BLINK_ON_DURATION,on_time); + let slope_in = sampler.smoothstep(off_time,BLINK_PERIOD); + let blinking_alpha = (one - slope_out + slope_in) * CURSOR_ALPHA; + let sel_width = &rect_width - CURSOR_WIDTH; + let alpha_weight = sel_width.smoothstep(0.0,letter_width); + let alpha = alpha_weight.mix(blinking_alpha,SELECTION_ALPHA); + let shape = Rect((1.px() * rect_width,1.px() * rect_height)); + let shape = shape.corners_radius(SELECTION_CORNER_RADIUS.px()); + let color = format!("srgba({}.x,{}.y,{}.z,{})",color_rgb,color_rgb + ,color_rgb,alpha.glsl()); + let shape = shape.fill(color); + shape.into() + } + } +} + + + +// =========== +// === FRP === +// =========== + +ensogl_core::define_endpoints! { + Input { + set_color (color::Rgb), + } +} + + + +// ================= +// === Selection === +// ================= + +/// Visual representation of text cursor and text selection. +/// +/// ## Implementation Notes +/// Selection contains a `right_side` display object which is always placed on its right side. It is +/// used for smooth glyph animation. For example, after several glyphs were selected and removed, +/// the selection will gradually shrink. Making all following glyphs children of the `right_side` +/// object will make the following glyphs animate while the selection is shrinking. +#[derive(Clone,CloneRef,Debug)] +pub struct Selection { + logger : Logger, + display_object : display::object::Instance, + pub right_side : display::object::Instance, + shape_view : shape::View, + pub network : frp::Network, + pub position : DEPRECATED_Animation, + pub width : DEPRECATED_Animation, + pub edit_mode : Rc>, + pub frp : Frp, +} + +impl Deref for Selection { + type Target = shape::View; + fn deref(&self) -> &Self::Target { + &self.shape_view + } +} + +impl Selection { + /// Constructor. + pub fn new(logger:impl AnyLogger, edit_mode:bool) -> Self { + let logger = Logger::sub(logger,"selection"); + let display_object = display::object::Instance::new(&logger); + let right_side = display::object::Instance::new(&logger); + let network = frp::Network::new("text_selection"); + let shape_view = shape::View::new(&logger); + let position = DEPRECATED_Animation::new(&network); + let width = DEPRECATED_Animation::new(&network); + let edit_mode = Rc::new(Cell::new(edit_mode)); + let frp = Frp::new(); + let debug = false; // Change to true to slow-down movement for debug purposes. + let spring_factor = if debug { 0.1 } else { 1.5 }; + + position . update_spring (|spring| spring * spring_factor); + width . update_spring (|spring| spring * spring_factor); + + Self {logger,display_object,right_side,shape_view,network,position,width,edit_mode,frp} + .init() + } + + fn init(self) -> Self { + let network = &self.network; + let view = &self.shape_view; + let object = &self.display_object; + let right_side = &self.right_side; + let shape_view = &self.shape_view; + self.add_child(view); + view.add_child(right_side); + frp::extend! { network + _eval <- all_with(&self.position.value,&self.width.value, + f!([view,object,right_side](p,width){ + let side = width.signum(); + let abs_width = width.abs(); + let width = max(CURSOR_WIDTH, abs_width - CURSORS_SPACING); + let view_width = CURSOR_PADDING * 2.0 + width; + let view_height = CURSOR_PADDING * 2.0 + crate::component::area::LINE_HEIGHT; + let view_x = (abs_width/2.0) * side; + let view_y = 0.0; + object.set_position_xy(*p); + right_side.set_position_x(abs_width/2.0); + view.size.set(Vector2(view_width,view_height)); + view.set_position_xy(Vector2(view_x,view_y)); + }) + ); + eval self.frp.set_color((color) shape_view.color_rgb.set(color.into())); + } + self + } + + pub fn flip_sides(&self) { + let width = self.width.target_value(); + self.position.set_value(self.position.value() + Vector2(width,0.0)); + self.position.set_target_value(self.position.target_value() + Vector2(width,0.0)); + + self.width.set_value(-self.width.value()); + self.width.set_target_value(-self.width.target_value()); + } +} + +impl display::Object for Selection { + fn display_object(&self) -> &display::object::Instance { + &self.display_object + } +} diff --git a/src/rust/ide/view/graph-editor/src/component/node.rs b/src/rust/ide/view/graph-editor/src/component/node.rs index 0cf6c3a807..c95844c9aa 100644 --- a/src/rust/ide/view/graph-editor/src/component/node.rs +++ b/src/rust/ide/view/graph-editor/src/component/node.rs @@ -21,7 +21,7 @@ pub use expression::Expression; use crate::prelude::*; use crate::component::node::profiling::RunningTimeLabel; -use crate::Mode as EditorMode; +use crate::view; use crate::component::visualization; use crate::tooltip; use crate::Type; @@ -38,7 +38,6 @@ use ensogl::display; use ensogl_gui_components::shadow; use ensogl_text::Text; use ensogl_theme; -use ensogl_theme::graph_editor::node::profiling as profiling_theme; use std::f32::EPSILON; use super::edge; @@ -266,7 +265,7 @@ ensogl::define_endpoints! { set_vcs_status (Option), /// Indicate whether preview visualisations should be delayed or immediate. quick_preview_vis (bool), - set_editor_mode (EditorMode), + set_view_mode (view::Mode), set_profiling_min_global_duration (f32), set_profiling_max_global_duration (f32), set_profiling_status (profiling::Status), @@ -491,8 +490,6 @@ impl NodeModel { self.backdrop.mod_position(|t| t.x = width/2.0); self.background.mod_position(|t| t.x = width/2.0); self.drag_area.mod_position(|t| t.x = width/2.0); - - self.running_time_label.set_position_x(width/2.0); self.error_indicator.set_position_x(width/2.0); self.vcs_indicator.set_position_x(width/2.0); @@ -604,12 +601,13 @@ impl Node { eval out.hover ((t) action_bar.set_visibility(t)); - // === Editor Mode === + // === View Mode === - model.input.set_editor_mode <+ frp.set_editor_mode; - model.running_time_label.set_editor_mode <+ frp.set_editor_mode; - model.vcs_indicator.set_visibility <+ frp.set_editor_mode.map(|&mode| { - !matches!(mode,EditorMode::Profiling {..}) + model.input.set_view_mode <+ frp.set_view_mode; + model.output.set_view_mode <+ frp.set_view_mode; + model.running_time_label.set_view_mode <+ frp.set_view_mode; + model.vcs_indicator.set_visibility <+ frp.set_view_mode.map(|&mode| { + !matches!(mode,view::Mode::Profiling {..}) }); } @@ -625,12 +623,12 @@ impl Node { frp.source.error <+ frp.set_error; is_error_set <- frp.error.map(|err| err.is_some()); no_error_set <- not(&is_error_set); - error_color_anim.target <+ all_with(&frp.error,&frp.set_editor_mode, + error_color_anim.target <+ all_with(&frp.error,&frp.set_view_mode, f!([style](error,&mode) let error_color = Self::error_color(error,&style); match mode { - EditorMode::Normal => error_color, - EditorMode::Profiling => error_color.to_grayscale(), + view::Mode::Normal => error_color, + view::Mode::Profiling => error_color.to_grayscale(), } )); @@ -710,32 +708,24 @@ impl Node { // === Color Handling === let bgg = style_frp.get_color(ensogl_theme::graph_editor::node::background); + let profiling_theme = profiling::Theme::from_styles(&style_frp,&network); - let profiling_lightness = style_frp.get_number_or(profiling_theme::lightness,0.7); - let profiling_chroma = style_frp.get_number_or(profiling_theme::chroma,0.7); - let profiling_min_hue = style_frp.get_number_or(profiling_theme::min_time_hue,0.4); - let profiling_max_hue = style_frp.get_number_or(profiling_theme::max_time_hue,0.1); - - profiling_color <- all_with8 + profiling_color <- all_with5 (&frp.set_profiling_status,&frp.set_profiling_min_global_duration, - &frp.set_profiling_max_global_duration,&profiling_lightness,&profiling_chroma, - &profiling_min_hue,&profiling_max_hue,&bgg, - |&status,&min,&max,&lightness,&chroma,&min_time_hue,&max_time_hue,&bgg| { - match status { - profiling::Status::Running => color::Lcha::from(bgg), - profiling::Status::Finished {..} => { - let theme = profiling::Theme {lightness,chroma,min_time_hue - ,max_time_hue}; - status.display_color(min,max,theme).with_alpha(1.0) - } + &frp.set_profiling_max_global_duration,&profiling_theme,&bgg, + |&status,&min,&max,&theme,&bgg| { + if status.is_finished() { + status.display_color(min,max,theme).with_alpha(1.0) + } else { + color::Lcha::from(bgg) } }); - bg_color_anim.target <+ all_with3(&bgg,&frp.set_editor_mode,&profiling_color, + bg_color_anim.target <+ all_with3(&bgg,&frp.set_view_mode,&profiling_color, |bgg,&mode,&profiling_color| { match mode { - EditorMode::Normal => color::Lcha::from(*bgg), - EditorMode::Profiling => profiling_color, + view::Mode::Normal => color::Lcha::from(*bgg), + view::Mode::Profiling => profiling_color, } }); diff --git a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs index a47f2969e8..5dac18bb01 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs @@ -23,7 +23,7 @@ use crate::component::type_coloring; use crate::node::input::port; use crate::node::profiling; use crate::node; -use crate::Mode as EditorMode; +use crate::view; @@ -197,7 +197,7 @@ ensogl::define_endpoints! { /// types are polymorphic. set_ports_active (bool,Option), - set_editor_mode (EditorMode), + set_view_mode (view::Mode), set_profiling_status (profiling::Status), } @@ -212,7 +212,7 @@ ensogl::define_endpoints! { on_port_hover (Switch), on_port_type_change (Crumbs,Option), on_background_press (), - editor_mode (EditorMode), + view_mode (view::Mode), } } @@ -228,6 +228,7 @@ pub struct Model { expression : RefCell, id_crumbs_map : RefCell>, styles : StyleWatch, + styles_frp : StyleWatchFrp, } impl Model { @@ -242,10 +243,12 @@ impl Model { let id_crumbs_map = default(); let expression = default(); let styles = StyleWatch::new(&app.display.scene().style_sheet); + let styles_frp = StyleWatchFrp::new(&app.display.scene().style_sheet); display_object.add_child(&label); display_object.add_child(&ports); ports.add_child(&header); - Self {logger,display_object,ports,header,label,app,expression,id_crumbs_map,styles}.init() + Self {logger,display_object,ports,header,label,app,expression,id_crumbs_map,styles + ,styles_frp}.init() } fn init(self) -> Self { @@ -397,16 +400,21 @@ impl Area { eval frp.set_expression_usage_type (((a,b)) model.set_expression_usage_type(a,b)); - // === Editor Mode === + // === View Mode === - frp.output.source.editor_mode <+ frp.set_editor_mode; - selection_color.target <+ frp.editor_mode.map(f!([model](&mode) { - let path = match mode { - EditorMode::Normal => theme::code::syntax::selection, - EditorMode::Profiling => theme::code::syntax::profiling::selection, - }; - color::Lch::from(model.styles.get_color(path)) - })); + frp.output.source.view_mode <+ frp.set_view_mode; + + in_profiling_mode <- frp.view_mode.map(|m| m.is_profiling()); + finished <- frp.set_profiling_status.map(|s| s.is_finished()); + profiled <- in_profiling_mode && finished; + + use theme::code::syntax; + let std_selection_color = model.styles_frp.get_color(syntax::selection); + let profiled_selection_color = model.styles_frp.get_color(syntax::profiling::selection); + + selection_color_rgba <- profiled.switch(&std_selection_color,&profiled_selection_color); + + selection_color.target <+ selection_color_rgba.map(|c| color::Lcha::from(c)); model.label.set_selection_color <+ selection_color.value.map(|&c| color::Rgb::from(c)); } @@ -557,8 +565,10 @@ impl Area { } // FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape system (#795) - let styles = StyleWatch::new(&self.model.app.display.scene().style_sheet); - let any_type_sel_color = color::Lcha::from(styles.get_color(theme::code::types::any::selection)); + let style_sheet = &self.model.app.display.scene().style_sheet; + let styles = StyleWatch::new(style_sheet); + let styles_frp = StyleWatchFrp::new(style_sheet); + let any_type_sel_color = styles_frp.get_color(theme::code::types::any::selection); let crumbs = port.crumbs.clone_ref(); let port_network = &port.network; let frp = &self.frp.output; @@ -613,25 +623,29 @@ impl Area { let port_shape_hover = port_shape.hover.clone_ref(); pointer_style_out <- mouse_out.map(|_| default()); - pointer_style_over <- map4 - (&mouse_over,&frp.set_ports_active,&port.tp,&frp.editor_mode, - move |_,(_,edge_tp),port_tp,editor_mode| { - let color = match editor_mode { - EditorMode::Normal => { - let tp = port_tp.as_ref().or_else(||edge_tp.as_ref()); - let color = tp.map(|tp| type_coloring::compute(tp,&styles)); - color.unwrap_or(any_type_sel_color) - }, - EditorMode::Profiling => any_type_sel_color - }; - cursor::Style::new_highlight(&port_shape_hover,padded_size,Some(color)) - } + + init_color <- source::<()>(); + any_type_sel_color <- all_with(&any_type_sel_color,&init_color, + |c,_| color::Lcha::from(c)); + tp <- all_with(&port.tp,&frp.set_ports_active, + |tp,(_,edge_tp)| tp.clone().or_else(||edge_tp.clone())); + tp_color <- tp.map( + f!([styles](tp) tp.map_ref(|tp| type_coloring::compute(tp,&styles)))); + tp_color <- all_with(&tp_color,&any_type_sel_color, + |tp_color,any_type_sel_color| tp_color.unwrap_or(*any_type_sel_color)); + in_profiling_mode <- frp.view_mode.map(|m| matches!(m,view::Mode::Profiling)); + pointer_color_over <- in_profiling_mode.switch(&tp_color,&any_type_sel_color); + pointer_style_over <- pointer_color_over.map(move |color| + cursor::Style::new_highlight(&port_shape_hover,padded_size,Some(color)) ); + pointer_style_over <- pointer_style_over.sample(&mouse_over); + pointer_style_hover <- any(pointer_style_over,pointer_style_out); pointer_styles <- all[pointer_style_hover,self.model.label.pointer_style]; pointer_style <- pointer_styles.fold(); self.frp.output.source.pointer_style <+ pointer_style; } + init_color.emit(()); port_shape.display_object().clone_ref() }; @@ -687,61 +701,49 @@ impl Area { // === Code Coloring === - let styles = model.styles.clone_ref(); - frp::extend! { port_network - base_color <- all_with3(&self.editor_mode,&self.set_profiling_status,&frp.tp, - f!([styles](&mode,&status,t) { - use theme::code::syntax; - match (mode,status) { - (EditorMode::Normal, _) => - type_coloring::compute_for_code(t.as_ref(),&styles), - (EditorMode::Profiling, profiling::Status::Running) => - color::Lcha::from(styles.get_color(syntax::base)), - (EditorMode::Profiling, profiling::Status::Finished {..}) => - color::Lcha::from(styles.get_color(syntax::profiling::base)), - } - }) - ); - } + let styles = model.styles.clone_ref(); + let styles_frp = model.styles_frp.clone_ref(); if node.children.is_empty() { let is_expected_arg = node.is_expected_argument(); + + use theme::code::syntax; + let selected_color = styles_frp.get_color(theme::code::types::selected); + let std_base_color = styles_frp.get_color(syntax::base); + let std_disabled_color = styles_frp.get_color(syntax::disabled); + let std_expected_color = styles_frp.get_color(syntax::expected); + let std_editing_color = styles_frp.get_color(syntax::base); + let profiled_base_color = styles_frp.get_color(syntax::profiling::base); + let profiled_disabled_color = styles_frp.get_color(syntax::profiling::disabled); + let profiled_expected_color = styles_frp.get_color(syntax::profiling::expected); + let profiled_editing_color = styles_frp.get_color(syntax::profiling::base); + frp::extend! { port_network - is_selected <- frp.set_hover || frp.set_parent_connected; - text_color_tgt <- all_with5(&is_selected,&self.frp.set_disabled, - &self.editor_mode,&self.set_profiling_status,&base_color, - f!([styles](&is_selected,&is_disabled,&mode,&status,&base_color) { - let path = match (mode, status) { - (EditorMode::Profiling, profiling::Status::Finished {..}) => - theme::code::syntax::profiling::HERE.path(), - _ => - theme::code::syntax::HERE.path(), - }; - let selected_rgba = styles.get_color(theme::code::types::selected); - let disabled_rgba = styles.get_color(path.sub("disabled")); - let expected_rgba = styles.get_color(path.sub("expected")); - let selected_color = color::Lcha::from(selected_rgba); - let disabled_color = color::Lcha::from(disabled_rgba); - let expected_color = color::Lcha::from(expected_rgba); - if is_selected { selected_color } - else if is_disabled { disabled_color } - else if is_expected_arg { expected_color } - else { base_color } - })); - editing_color <- all_with(&self.editor_mode,&self.set_profiling_status, - f!([styles](&mode,&status) { - use theme::code::syntax; - let is_profiled = mode.is_profiling() && status.is_finished(); - let path = if is_profiled { - syntax::profiling::base - } else { - syntax::base - }; - color::Lcha::from(styles.get_color(path)) - })); + in_profiling_mode <- self.view_mode.map(|m| m.is_profiling()); + finished <- self.set_profiling_status.map(|s| s.is_finished()); + profiled <- in_profiling_mode && finished; + selected <- frp.set_hover || frp.set_parent_connected; + + profiling_color <- finished.switch(&std_base_color,&profiled_base_color); + normal_color <- frp.tp.map(f!([styles](t) + color::Rgba::from(type_coloring::compute_for_code(t.as_ref(),&styles)))); + base_color <- in_profiling_mode.switch(&normal_color,&profiling_color); + + disabled_color <- profiled.switch(&std_disabled_color,&profiled_disabled_color); + expected_color <- profiled.switch(&std_expected_color,&profiled_expected_color); + editing_color <- profiled.switch(&std_editing_color,&profiled_editing_color); // Fixme: `label_color` should be animated, when when we can set text colors // more efficiently. (See https://github.com/enso-org/ide/issues/1031) - label_color <- self.set_edit_mode.switch(&text_color_tgt,&editing_color); + label_color <- all_with8(&self.set_edit_mode,&selected,&self.frp.set_disabled + ,&editing_color,&selected_color,&disabled_color,&expected_color,&base_color + ,move |&editing,&selected,&disabled,&editing_color,&selected_color + ,&disabled_color,&expected_color,&base_color| { + if editing { color::Lcha::from(editing_color) } + else if selected { color::Lcha::from(selected_color) } + else if disabled { color::Lcha::from(disabled_color) } + else if is_expected_arg { color::Lcha::from(expected_color) } + else { color::Lcha::from(base_color) } + }); } let index = node.payload.index; @@ -761,29 +763,28 @@ impl Area { // === Highlight Coloring === - let viz_color = color::Animation::new(port_network); if let Some(port_shape) = &node.payload.shape { + let viz_color = color::Animation::new(port_network); + let any_type_sel_color = styles_frp.get_color(theme::code::types::any::selection); + frp::extend! { port_network - port_tp <- all(&frp.set_hover,&frp.tp)._1(); - new_viz_color <- all_with3 - (&port_tp,&frp.set_connected,&self.editor_mode - ,f!([styles](port_tp,(is_connected,edge_tp),editor_mode) { - if *is_connected { - match editor_mode { - EditorMode::Normal => { - let tp = port_tp.as_ref().or_else(||edge_tp.as_ref()); - select_color(&styles,tp) - }, - EditorMode::Profiling => { - styles.get_color(theme::code::types::any::selection).into() - } - } - } else { - color::Lcha::transparent() - } - } - )); - viz_color.target <+ new_viz_color; + normal_viz_color <- all_with(&frp.tp,&frp.set_connected, + f!([styles](port_tp,(_,edge_tp)) { + let tp = port_tp.as_ref().or_else(||edge_tp.as_ref()); + select_color(&styles,tp) + })); + init_color <- source::<()>(); + profiling_viz_color <- all_with(&any_type_sel_color,&init_color, + |c,_| color::Lcha::from(c)); + profiling <- self.view_mode.map(|m| m.is_profiling()); + connected_viz_color <- profiling.switch(&normal_viz_color,&profiling_viz_color); + is_connected <- frp.set_connected.map(|(is_connected,_)| *is_connected); + transparent <- init_color.constant(color::Lcha::transparent()); + viz_color_target <- is_connected.switch(&transparent,&connected_viz_color); + + init_color.emit(()); + + viz_color.target <+ viz_color_target; eval viz_color.value ((t) port_shape.viz.color.set(color::Rgba::from(t).into()) ); diff --git a/src/rust/ide/view/graph-editor/src/component/node/output/area.rs b/src/rust/ide/view/graph-editor/src/component/node/output/area.rs index 97f5845318..b9e76822a8 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/output/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/output/area.rs @@ -9,6 +9,7 @@ use ensogl::animation::hysteretic::HystereticAnimation; use ensogl::application::Application; use ensogl::data::color; use ensogl::display::shape::StyleWatch; +use ensogl::display::shape::StyleWatchFrp; use ensogl::display; use ensogl_text as text; use ensogl_theme as theme; @@ -19,6 +20,7 @@ use crate::component::node::input; use crate::component::node::output::port; use crate::component::node; use crate::tooltip; +use crate::view; use enso_args::ARGS; @@ -123,6 +125,7 @@ ensogl::define_endpoints! { set_expression (node::Expression), set_expression_visibility (bool), set_type_label_visibility (bool), + set_view_mode (view::Mode), /// Set the expression USAGE type. This is not the definition type, which can be set with /// `set_expression` instead. In case the usage type is set to None, ports still may be @@ -153,6 +156,7 @@ pub struct Model { id_crumbs_map : RefCell>, port_count : Cell, styles : StyleWatch, + styles_frp : StyleWatchFrp, frp : FrpEndpoints, } @@ -168,11 +172,12 @@ impl Model { let expression = default(); let port_count = default(); let styles = StyleWatch::new(&app.display.scene().style_sheet); + let styles_frp = StyleWatchFrp::new(&app.display.scene().style_sheet); let frp = frp.output.clone_ref(); display_object.add_child(&label); display_object.add_child(&ports); - Self {logger,display_object,ports,app,label,expression,id_crumbs_map,port_count,styles,frp} - .init() + Self {logger,display_object,ports,app,label,expression,id_crumbs_map,port_count,styles + ,styles_frp,frp}.init() } fn init(self) -> Self { @@ -300,17 +305,20 @@ impl Model { let crumbs = port.crumbs.clone_ref(); let logger = &self.logger; let (port_shape,port_frp) = port.payload_mut() - .init_shape(logger,&self.app,&self.styles,port_index,port_count); + .init_shape(logger,&self.app,&self.styles,&self.styles_frp,port_index + ,port_count); let port_network = &port_frp.network; frp::extend! { port_network self.frp.source.on_port_hover <+ port_frp.on_hover.map (f!([crumbs](t) Switch::new(crumbs.clone(),*t))); self.frp.source.on_port_press <+ port_frp.on_press.constant(crumbs.clone()); - port_frp.set_size_multiplier <+ self.frp.port_size_multiplier; + + port_frp.set_size_multiplier <+ self.frp.port_size_multiplier; self.frp.source.on_port_type_change <+ port_frp.tp.map(move |t|(crumbs.clone(),t.clone())); - port_frp.set_type_label_visibility <+ self.frp.type_label_visibility; - self.frp.source.tooltip <+ port_frp.tooltip; + port_frp.set_type_label_visibility <+ self.frp.type_label_visibility; + self.frp.source.tooltip <+ port_frp.tooltip; + port_frp.set_view_mode <+ self.frp.set_view_mode; } port_frp.set_type_label_visibility.emit(self.frp.type_label_visibility.value()); @@ -423,6 +431,8 @@ impl Area { port_hover <- frp.on_port_hover.map(|t| t.is_on()); frp.source.body_hover <+ frp.set_hover || port_hover; expr_vis <- frp.body_hover || frp.set_expression_visibility; + in_normal_mode <- frp.set_view_mode.map(|m| m.is_normal()); + expr_vis <- expr_vis && in_normal_mode; label_alpha_tgt <- expr_vis.map(move |t| if *t {label_vis_alpha} else {0.0} ); label_color.target_alpha <+ label_alpha_tgt; label_color_on_change <- label_color.value.sample(&frp.set_expression); diff --git a/src/rust/ide/view/graph-editor/src/component/node/output/port.rs b/src/rust/ide/view/graph-editor/src/component/node/output/port.rs index 41dc60e9e8..5e69fab082 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/output/port.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/output/port.rs @@ -6,6 +6,7 @@ use crate::tooltip::Placement; use crate::Type; use crate::component::node; use crate::component::type_coloring; +use crate::view; use enso_frp as frp; use ensogl::Animation; @@ -17,6 +18,7 @@ use ensogl::display::shape::PixelDistance; use ensogl::display::shape::Pixels; use ensogl::display::shape::Rect; use ensogl::display::shape::StyleWatch; +use ensogl::display::shape::StyleWatchFrp; use ensogl::display::shape::Var; use ensogl::display::shape::primitive::def::class::ShapeOps; use ensogl::display; @@ -416,6 +418,7 @@ ensogl::define_endpoints! { set_usage_type (Option), set_type_label_visibility (bool), set_size (Vector2), + set_view_mode (view::Mode), } Output { @@ -445,6 +448,7 @@ impl Model { , logger : impl AnyLogger , app : &Application , styles : &StyleWatch + , styles_frp : &StyleWatchFrp , port_index : usize , port_count : usize ) -> (display::object::Instance,Frp) { @@ -475,11 +479,16 @@ impl Model { self.port_count = max(port_count, 1); self.port_index = port_index; - self.init_frp(&shape,&type_label,styles); + self.init_frp(&shape,&type_label,styles,styles_frp); (display_object,self.frp.as_ref().unwrap().clone_ref()) } - fn init_frp(&mut self,shape:&PortShapeView,type_label:&text::Area,styles:&StyleWatch) { + fn init_frp + ( &mut self + , shape:&PortShapeView + , type_label:&text::Area + , styles:&StyleWatch + , styles_frp:&StyleWatchFrp) { let frp = Frp::new(); let network = &frp.network; let events = shape.events(); @@ -532,8 +541,14 @@ impl Model { |usage_tp,def_tp| usage_tp.clone().or_else(|| def_tp.clone()) ); - color_tgt <- frp.tp.map(f!([styles](t) type_coloring::compute_for_selection(t.as_ref(),&styles))); - color.target <+ color_tgt; + normal_color <- frp.tp.map(f!([styles](t) + type_coloring::compute_for_selection(t.as_ref(),&styles))); + init_color <- source::<()>(); + let profiling_color = styles_frp.get_color(ensogl_theme::code::types::any::selection); + profiling_color <- all_with(&profiling_color,&init_color,|c,_|color::Lcha::from(c)); + in_profiling_mode <- frp.set_view_mode.map(|mode| mode.is_profiling()); + color_tgt <- in_profiling_mode.switch(&normal_color,&profiling_color); + color.target <+ color_tgt; eval color.value ((t) shape.set_color(t.into())); full_type_timer.start <+ frp.on_hover.on_true(); @@ -545,6 +560,7 @@ impl Model { }) }); } + init_color.emit(()); if SHOW_TYPE_AS_LABEL { frp::extend! { network diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs index affb53ff9c..575b817046 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs @@ -3,7 +3,7 @@ use crate::prelude::*; -use crate::Mode as EditorMode; +use crate::view; use enso_frp as frp; use ensogl::application::Application; @@ -11,15 +11,6 @@ use ensogl::data::color; use ensogl::display::shape::*; use ensogl::display; use ensogl::gui::text; -use ensogl_theme::graph_editor::node::profiling as theme_path; - - - -// ================= -// === Constants === -// ================= - -const LABEL_OFFSET_Y: f32 = 35.0; @@ -40,12 +31,6 @@ pub enum Status { } } -impl Default for Status { - fn default() -> Self { - Status::Running - } -} - impl Status { /// Returns `true` if the node is still running. pub fn is_running(self) -> bool { @@ -58,6 +43,37 @@ impl Status { } } +impl Default for Status { + fn default() -> Self { + Status::Running + } +} + +impl Display for Status { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + Status::Running => { + write!(f, "") + } + Status::Finished {duration} => { + let milliseconds = duration; + let seconds = milliseconds / 1000.0; + let minutes = seconds / 60.0; + let hours = minutes / 60.0; + if hours >= 1.0 { + write!(f, "{:.1} h", hours) + } else if minutes >= 1.0 { + write!(f, "{:.1} m", minutes) + } else if seconds >= 1.0 { + write!(f, "{:.1} s", seconds) + } else { + write!(f, "{:.0} ms", milliseconds) + } + } + } + } +} + // ============= @@ -81,6 +97,29 @@ pub struct Theme { pub max_time_hue : f32, } +impl Theme { + /// Returns a new `Sampler` exposing the profiling theme, as it is defined in `styles` at path + /// `ensogl_theme::graph_editor::node::profiling`. The sampler is registered under `network`. + pub fn from_styles(styles:&StyleWatchFrp,network:&frp::Network) -> frp::Sampler { + use ensogl_theme::graph_editor::node::profiling as theme_path; + let lightness = styles.get_number_or(theme_path::lightness,0.5); + let chroma = styles.get_number_or(theme_path::chroma,1.0); + let min_time_hue = styles.get_number_or(theme_path::min_time_hue,0.4); + let max_time_hue = styles.get_number_or(theme_path::max_time_hue,0.1); + + frp::extend! { network + init_theme <- source::<()>(); + theme <- all_with5(&lightness,&chroma,&min_time_hue,&max_time_hue,&init_theme + ,|&lightness,&chroma,&min_time_hue,&max_time_hue,_| + Theme {lightness,chroma,max_time_hue,min_time_hue}); + theme_sampler <- theme.sampler(); + } + + init_theme.emit(()); + theme_sampler + } +} + impl Status { /// Expresses the profiling status as a color, depending on the minimum and maximum running /// time of any node on the stage and a [`Theme`] that allows to tweak how the colors are @@ -89,18 +128,18 @@ impl Status { pub fn display_color (self, min_global_duration: f32, max_global_duration: f32, theme: Theme) -> color::Lch { let duration = match self { - Status::Running => max_global_duration, + Status::Running => max_global_duration, Status::Finished {duration} => duration, }; - let duration_delta = max_global_duration - min_global_duration; - let hue_delta = theme.max_time_hue - theme.min_time_hue; + let duration_delta = max_global_duration - min_global_duration; + let hue_delta = theme.max_time_hue - theme.min_time_hue; let relative_duration = if duration_delta != 0.0 { (duration - min_global_duration) / duration_delta } else { 0.0 }; let relative_hue = relative_duration; - let hue = theme.min_time_hue + relative_hue * hue_delta; + let hue = theme.min_time_hue + relative_hue * hue_delta; color::Lch::new(theme.lightness, theme.chroma, hue) } } @@ -116,7 +155,7 @@ ensogl::define_endpoints! { set_status (Status), set_min_global_duration (f32), set_max_global_duration (f32), - set_editor_mode (EditorMode), + set_view_mode (view::Mode), } } @@ -128,7 +167,7 @@ ensogl::define_endpoints! { /// A `display::Object` providing a label for nodes that displays the node's running time in /// profiling mode after the node finished execution. The node's execution status has to be provided -/// through `set_status`, the diplay mode through `set_editor_mode`, the minimum and maximum running +/// through `set_status`, the view mode through `set_view_mode`, the minimum and maximum running /// time of any node on the stage through `set_min_global_duration` and `set_max_global_duration`. /// The color of the label will reflect the status and be determined by [`Status::display_color`]. /// The necessary theme will be taken from the application's style sheet. The origin of the label, @@ -157,16 +196,10 @@ impl RunningTimeLabel { let label = text::Area::new(app); root.add_child(&label); - label.set_position_y(LABEL_OFFSET_Y); + label.set_position_y(crate::component::node::input::area::TEXT_SIZE/2.0); label.remove_from_scene_layer_DEPRECATED(&scene.layers.main); label.add_to_scene_layer_DEPRECATED(&scene.layers.label); - let styles = StyleWatchFrp::new(&scene.style_sheet); - let lightness = styles.get_number_or(theme_path::lightness,0.5); - let chroma = styles.get_number_or(theme_path::chroma,1.0); - let min_time_hue = styles.get_number_or(theme_path::min_time_hue,0.4); - let max_time_hue = styles.get_number_or(theme_path::max_time_hue,0.1); - let frp = Frp::new(); let network = &frp.network; let color = color::Animation::new(network); @@ -175,8 +208,8 @@ impl RunningTimeLabel { // === Visibility === - visibility <- all_with(&frp.set_editor_mode,&frp.set_status,|mode,status| { - matches!((mode,status),(EditorMode::Profiling,Status::Finished {..})) + visibility <- all_with(&frp.set_view_mode,&frp.set_status,|mode,status| { + matches!((mode,status),(view::Mode::Profiling,Status::Finished {..})) }); color.target_alpha <+ visibility.map(|&is_visible| { @@ -186,9 +219,8 @@ impl RunningTimeLabel { // === Color === - theme <- all_with4(&lightness,&chroma,&min_time_hue,&max_time_hue, - |&lightness,&chroma,&min_time_hue,&max_time_hue| - Theme {lightness,chroma,max_time_hue,min_time_hue}); + let styles = StyleWatchFrp::new(&scene.style_sheet); + let theme = Theme::from_styles(&styles,&network); color.target_color <+ all_with4 (&frp.set_status,&frp.set_min_global_duration,&frp.set_max_global_duration,&theme, |&status,&min,&max,&theme| status.display_color(min,max,theme) @@ -199,16 +231,13 @@ impl RunningTimeLabel { // === Position === - eval label.width((&width) label.set_position_x(-width/2.0)); + let x_offset = crate::component::node::input::area::TEXT_OFFSET; + eval label.width((&width) label.set_position_x(-width-x_offset)); // === Content === - label.set_content <+ frp.set_status.map(|&status| - match status { - Status::Running => "".to_string(), - Status::Finished {duration} => format!("{} ms", duration) - }); + label.set_content <+ frp.set_status.map(|status| status.to_string()); } RunningTimeLabel {root,label,frp,styles} diff --git a/src/rust/ide/view/graph-editor/src/component/profiling.rs b/src/rust/ide/view/graph-editor/src/component/profiling.rs index f4bd710aa1..cbd818ae91 100644 --- a/src/rust/ide/view/graph-editor/src/component/profiling.rs +++ b/src/rust/ide/view/graph-editor/src/component/profiling.rs @@ -1,7 +1,9 @@ -//! Profides a button that can be used to toggle the editor's profiling mode. +//! Provides a button that can be used to toggle the editor's profiling mode. use crate::prelude::*; +use crate::view; + use enso_frp as frp; use ensogl::application::Application; use ensogl::data::color; @@ -11,10 +13,17 @@ use ensogl_gui_components::toggle_button::ToggleButton; use ensogl_gui_components::toggle_button; + // ============ // === Icon === // ============ +/// Defines an icon as described here: +/// https://github.com/enso-org/ide/pull/1546#issuecomment-838169795 +/// +/// It consists of a *circle outline* with an *aperture* in the lower right quadrant. The edges +/// of the aperture have rounded *caps*. In the center is an *inner circle* with a *needle* +/// pointing to the lower right. mod icon { use super::*; use ensogl_gui_components::toggle_button::ColorableShape; @@ -25,40 +34,62 @@ mod icon { let width = Var::::from("input_size.x"); let height = Var::::from("input_size.y"); + + // === Measurements === + let unit = &width * 0.3; let outer_circle_radius = &unit * 1.0; let outer_circle_thickness = &unit * 0.33; let inner_circle_radius = &unit * 0.2; + let needle_angle = (135.0_f32).to_radians().radians(); let needle_radius_inner = &unit * 0.14; let needle_radius_outer = &unit * 0.09; - let needle_angle = (135.0_f32).to_radians().radians(); + let needle_length = &outer_circle_radius-&needle_radius_outer; + let aperture_cap_1_x = &outer_circle_radius-&outer_circle_thickness*0.5; + let aperture_cap_2_y = -(&outer_circle_radius-&outer_circle_thickness*0.5); + + + // === Circle Outline === - let base = Circle(&outer_circle_radius); - let circle_gap = Circle(&outer_circle_radius-&outer_circle_thickness); + let circle = Circle(&outer_circle_radius); + let gap = Circle(&outer_circle_radius-&outer_circle_thickness); + let circle_outline = circle - gap; + + + // === Aperture === + + // To produce the aperture, we cut a triangular gap from the outline and use small + // circular caps to round off the edges. // We make the gap a little bit larger than the circle to be sure that we really cover - // everything that we want to cut, even if there are rounding errors or similar + // everything that we want to cut, even if there are rounding errors or other // imprecisions. - let aperture_gap_size = &outer_circle_radius * 1.1; - let aperture_gap = Triangle(&aperture_gap_size*2.0,aperture_gap_size.clone()); - let aperture_gap = aperture_gap.rotate(needle_angle+180.0_f32.to_radians().radians()); - let aperture_gap = aperture_gap.translate_x(&aperture_gap_size*2.0.sqrt()*0.25); - let aperture_gap = aperture_gap.translate_y(-(&aperture_gap_size*2.0.sqrt()*0.25)); + let aperture_gap_size = &outer_circle_radius * 1.1; + let aperture_gap_angle = needle_angle+180.0_f32.to_radians().radians(); + + let aperture_gap = Triangle(&aperture_gap_size*2.0,aperture_gap_size.clone()); + let aperture_gap = aperture_gap.rotate(aperture_gap_angle); + let aperture_gap = aperture_gap.translate_x(&aperture_gap_size*2.0.sqrt()*0.25); + let aperture_gap = aperture_gap.translate_y(-&aperture_gap_size*2.0.sqrt()*0.25); let aperture_cap_1 = Circle(&outer_circle_thickness*0.5); - let aperture_cap_1 = aperture_cap_1.translate_x(&outer_circle_radius-&outer_circle_thickness*0.5); + let aperture_cap_1 = aperture_cap_1.translate_x(aperture_cap_1_x); let aperture_cap_2 = Circle(&outer_circle_thickness*0.5); - let aperture_cap_2 = aperture_cap_2.translate_y(-(&outer_circle_radius-&outer_circle_thickness*0.5)); + let aperture_cap_2 = aperture_cap_2.translate_y(aperture_cap_2_y); - let outer_circle = base - circle_gap - aperture_gap + aperture_cap_1 + aperture_cap_2; + let circle_outline = circle_outline - aperture_gap + aperture_cap_1 + aperture_cap_2; - let needle_length = &outer_circle_radius-&needle_radius_outer; - let needle = UnevenCapsule(needle_radius_outer,needle_radius_inner,needle_length); - let needle = needle.rotate(&needle_angle); + // === Needle === + + let needle = UnevenCapsule(needle_radius_outer,needle_radius_inner,needle_length); + let needle = needle.rotate(&needle_angle); let inner_circle = Circle(&inner_circle_radius); - let shape = (outer_circle + needle + inner_circle).fill(fill_color); + + // === Composition === + + let shape = (circle_outline + needle + inner_circle).fill(fill_color); let hover_area = Rect((&width,&height)).fill(HOVER_COLOR); (shape + hover_area).into() } @@ -79,10 +110,10 @@ mod icon { ensogl::define_endpoints! { Input { - set_mode (crate::Mode), + set_mode (view::Mode), } Output { - mode (crate::Mode), + mode (view::Mode), } } @@ -110,7 +141,7 @@ impl Deref for Button { } impl Button { - /// Constructs a new button for toggling the editor mode. + /// Constructs a new button for toggling the editor's view mode. pub fn new(app: &Application) -> Button { let scene = app.display.scene(); let styles = StyleWatchFrp::new(&scene.style_sheet); @@ -127,11 +158,9 @@ impl Button { // === State === frp.source.mode <+ button.state.map(|&toggled| { - if toggled { crate::Mode::Profiling } else { crate::Mode::Normal } - }); - button.set_state <+ frp.set_mode.map(|&mode| { - matches!(mode,crate::Mode::Profiling) + if toggled { view::Mode::Profiling } else { view::Mode::Normal } }); + button.set_state <+ frp.set_mode.map(|&mode| mode.is_profiling()); // === Position === @@ -150,8 +179,10 @@ impl Button { let toggled_color = styles.get_color(button_theme::toggled); let hovered_color = styles.get_color(button_theme::hovered); let toggled_hovered_color = styles.get_color(button_theme::toggled_hovered); - button.set_color_scheme <+ all_with4(&non_toggled_color,&toggled_color,&hovered_color - ,&toggled_hovered_color,|&non_toggled,&toggled,&hovered,&toggled_hovered| + init_color_scheme <- source::<()>(); + button.set_color_scheme <+ all_with5(&non_toggled_color,&toggled_color,&hovered_color + ,&toggled_hovered_color,&init_color_scheme + ,|&non_toggled,&toggled,&hovered,&toggled_hovered,_| toggle_button::ColorScheme { non_toggled : Some(non_toggled.into()), toggled : Some(toggled.into()), @@ -162,6 +193,7 @@ impl Button { ); } + init_color_scheme.emit(()); Button {frp,button,styles} } } diff --git a/src/rust/ide/view/graph-editor/src/display.rs b/src/rust/ide/view/graph-editor/src/display.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index dc5adbf274..4d3269c2f5 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -34,10 +34,13 @@ pub mod component; pub mod builtin; pub mod data; -mod profiling; +#[warn(missing_docs)] +pub mod profiling; +#[warn(missing_docs)] +pub mod view; use crate::component::node; -pub use crate::component::node::profiling::Status as NodeProfilingStatus; +pub use crate::node::profiling::Status as NodeProfilingStatus; use crate::component::tooltip::Tooltip; use crate::component::visualization::instance::PreprocessorConfiguration; use crate::component::tooltip; @@ -59,6 +62,7 @@ use ensogl::display::Scene; use ensogl::display::navigation::navigator::Navigator; use ensogl::display::object::Id; use ensogl::display::shape::StyleWatch; +use ensogl::display::shape::StyleWatchFrp; use ensogl::display; use ensogl::gui::cursor; use ensogl::prelude::*; @@ -105,36 +109,6 @@ fn traffic_lights_gap_width() -> f32 { -// ============ -// === Mode === -// ============ - -/// Represents the current global mode of the graph editor. In profiling mode, edges should not be -/// colored and profiling information on nodes should become visible. -#[derive(Debug,Copy,Clone,CloneRef,PartialEq,Eq)] -pub enum Mode { - Normal, - Profiling -} - -impl Default for Mode { - fn default() -> Self { - Mode::Normal - } -} - -impl Mode { - pub fn is_normal(self) -> bool { - matches!(self,Mode::Normal) - } - - pub fn is_profiling(self) -> bool { - matches!(self,Mode::Profiling) - } -} - - - // ================= // === SharedVec === // ================= @@ -594,7 +568,7 @@ ensogl::define_endpoints! { node_being_edited (Option), node_editing (bool), - mode (Mode), + mode (view::Mode), navigator_active (bool), } @@ -1126,8 +1100,9 @@ impl GraphEditorModelWithNetwork { let node_id = node.id(); self.add_child(&node); - let touch = &self.touch_state; - let model = &self.model; + let touch = &self.touch_state; + let model = &self.model; + let styles_frp = StyleWatchFrp::new(&model.scene().style_sheet); let NodeCreationContext {pointer_style,tooltip_update,output_press,input_press,output} = ctx; @@ -1162,13 +1137,15 @@ impl GraphEditorModelWithNetwork { model.frp.source.hover_node_output.emit(output); }); - eval node.model.input.frp.on_port_type_change(((crumbs,_)) - model.with_input_edge_id(node_id,crumbs,|id| model.refresh_edge_color(id)) - ); + let neutral_color = styles_frp.get_color(theme::code::types::any::selection); - eval node.model.output.frp.on_port_type_change(((crumbs,_)) - model.with_output_edge_id(node_id,crumbs,|id| model.refresh_edge_color(id)) - ); + _eval <- all_with(&node.model.input.frp.on_port_type_change,&neutral_color, + f!(((crumbs,_),neutral_color) + model.with_input_edge_id(node_id,crumbs,|id| model.refresh_edge_color(id,neutral_color.into())))); + + _eval <- all_with(&node.model.input.frp.on_port_type_change,&neutral_color, + f!(((crumbs,_),neutral_color) + model.with_output_edge_id(node_id,crumbs,|id| model.refresh_edge_color(id,neutral_color.into())))); eval node.frp.expression((t) output.source.node_expression_set.emit((node_id,t.into()))); @@ -1223,19 +1200,19 @@ impl GraphEditorModelWithNetwork { // === Mode === - node.set_editor_mode <+ self.model.frp.mode; + node.set_view_mode <+ self.model.frp.mode; // === Profiling === - let profiling_min_duration = &self.model.profiling_statuses.min_duration; + let profiling_min_duration = &self.model.profiling_statuses.min_duration; node.set_profiling_min_global_duration <+ self.model.profiling_statuses.min_duration; node.set_profiling_min_global_duration(profiling_min_duration.value()); - let profiling_max_duration = &self.model.profiling_statuses.max_duration; + let profiling_max_duration = &self.model.profiling_statuses.max_duration; node.set_profiling_max_global_duration <+ self.model.profiling_statuses.max_duration; node.set_profiling_max_global_duration(profiling_max_duration.value()); } - node.set_editor_mode(self.model.frp.mode.value()); + node.set_view_mode(self.model.frp.mode.value()); let initial_metadata = visualization::Metadata { preprocessor : node.model.visualization.frp.preprocessor.value() }; @@ -1749,13 +1726,19 @@ impl GraphEditorModel { }; } - pub fn refresh_edge_color(&self, edge_id:EdgeId) { + pub fn refresh_edge_color(&self, edge_id:EdgeId, neutral_color:color::Lcha) { if let Some(edge) = self.edges.get_cloned_ref(&edge_id) { - let color = self.edge_color(edge_id); + let color = self.edge_color(edge_id, neutral_color); edge.view.frp.set_color.emit(color); }; } + fn refresh_all_edge_colors(&self, neutral_color:color::Lcha) { + for edge_id in self.edges.keys() { + self.refresh_edge_color(edge_id, neutral_color); + } + } + pub fn refresh_edge_source_position(&self, edge_id:EdgeId) { if let Some(edge) = self.edges.get_cloned_ref(&edge_id) { if let Some(edge_source) = edge.source() { @@ -1907,19 +1890,18 @@ impl GraphEditorModel { /// This might need to be more sophisticated in the case of polymorphic types. For example, /// consider the edge source type to be `(a,Number)`, and target to be `(Text,a)`. These unify /// to `(Text,Number)`. - fn edge_color(&self, edge_id:EdgeId) -> color::Lcha { + fn edge_color(&self, edge_id:EdgeId, neutral_color:color::Lcha) -> color::Lcha { // FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape system (#795) - let styles = StyleWatch::new(&self.scene().style_sheet); - let neutral_color = color::Lcha::from(styles.get_color(theme::code::types::any::selection)); + let styles = StyleWatch::new(&self.scene().style_sheet); match self.frp.mode.value() { - Mode::Normal => { + view::Mode::Normal => { let edge_type = self.edge_hover_type() .or_else(|| self.edge_target_type(edge_id)) .or_else(|| self.edge_source_type(edge_id)); let opt_color = edge_type.map(|t|type_coloring::compute(&t,&styles)); opt_color.unwrap_or(neutral_color) }, - Mode::Profiling => { + view::Mode::Profiling => { neutral_color } } @@ -1939,8 +1921,8 @@ impl GraphEditorModel { } /// Return a color for the first detached edge. - pub fn first_detached_edge_color(&self) -> Option { - self.first_detached_edge().map(|t|self.edge_color(t)) + pub fn first_detached_edge_color(&self,neutral_color:color::Lcha) -> Option { + self.first_detached_edge().map(|t|self.edge_color(t,neutral_color)) } pub fn has_edges_with_detached_targets(&self, node_id:NodeId) -> bool { @@ -2133,6 +2115,7 @@ fn new_graph_editor(app:&Application) -> GraphEditor { // FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape system (#795) let styles = StyleWatch::new(&scene.style_sheet); + let styles_frp = StyleWatchFrp::new(&scene.style_sheet); let any_type_sel_color = color::Lcha::from(styles.get_color(theme::code::types::any::selection)); @@ -3061,13 +3044,19 @@ fn new_graph_editor(app:&Application) -> GraphEditor { out.source.on_edge_only_source_not_set <+ out.on_edge_target_set_with_source_not_set._0(); out.source.on_edge_only_source_not_set <+ out.on_edge_source_unset._0(); - eval out.on_edge_source_set (((id,_)) model.refresh_edge_color(*id)); - eval out.on_edge_target_set (((id,_)) model.refresh_edge_color(*id)); - eval out.on_edge_source_unset (((id,_)) model.refresh_edge_color(*id)); - eval out.on_edge_target_unset (((id,_)) model.refresh_edge_color(*id)); + let neutral_color = styles_frp.get_color(theme::code::types::any::selection); + _eval <- all_with(&out.on_edge_source_set,&neutral_color,f!(((id,_),neutral_color) + model.refresh_edge_color(*id,neutral_color.into()))); + _eval <- all_with(&out.on_edge_target_set,&neutral_color,f!(((id,_),neutral_color) + model.refresh_edge_color(*id,neutral_color.into()))); + _eval <- all_with(&out.on_edge_source_unset,&neutral_color,f!(((id,_),neutral_color) + model.refresh_edge_color(*id,neutral_color.into()))); + _eval <- all_with(&out.on_edge_target_unset,&neutral_color,f!(((id,_),neutral_color) + model.refresh_edge_color(*id,neutral_color.into()))); edge_to_refresh_on_hover <= out.hover_node_input.map(f_!(model.edges_with_detached_targets())); - eval edge_to_refresh_on_hover ((id) model.refresh_edge_color(*id)); + _eval <- all_with(&edge_to_refresh_on_hover,&neutral_color,f!((id,neutral_color) + model.refresh_edge_color(*id,neutral_color.into()))); some_edge_sources_unset <- out.on_all_edges_sources_set ?? out.on_some_edges_sources_unset; @@ -3139,13 +3128,14 @@ fn new_graph_editor(app:&Application) -> GraphEditor { frp::extend! { network on_some_edges_detached <- out.some_edge_endpoints_unset.gate(&out.some_edge_endpoints_unset); - cursor_style_edge_drag <- on_some_edges_detached.map(f_!([model]{ - if let Some(color) = model.first_detached_edge_color() { - cursor::Style::new_color(color).press() - } else { - cursor::Style::new_color_no_animation(any_type_sel_color).press() - } - })); + cursor_style_edge_drag <- all_with(&on_some_edges_detached,&neutral_color, + f!([model](_,neutral_color){ + if let Some(color) = model.first_detached_edge_color(neutral_color.into()) { + cursor::Style::new_color(color).press() + } else { + cursor::Style::new_color_no_animation(any_type_sel_color).press() + } + })); cursor_style_on_edge_drag_stop <- out.on_all_edges_endpoints_set.constant(default()); cursor_style_edge_drag <- any (cursor_style_edge_drag,cursor_style_on_edge_drag_stop); @@ -3182,32 +3172,23 @@ fn new_graph_editor(app:&Application) -> GraphEditor { - // ============= - // === Modes === - // ============= + // ================== + // === View Modes === + // ================== let profiling_mode_transition = Animation::new(network); frp::extend! { network - out.source.mode <+ frp.toggle_profiling_mode.map2(&frp.mode,|_,&mode| { - match mode { - Mode::Profiling => Mode::Normal, - Mode::Normal => Mode::Profiling, - } - }); - + out.source.mode <+ frp.toggle_profiling_mode.map2(&frp.mode,|_,&mode| mode.switch()); out.source.mode <+ model.profiling_button.mode; - model.profiling_button.set_mode <+ out.mode.on_change(); - eval out.mode([model](_) { - for edge_id in model.edges.keys() { - model.refresh_edge_color(edge_id); - } - }); + model.profiling_button.set_mode <+ out.mode.on_change(); + _eval <- all_with(&out.mode,&neutral_color,f!((_,neutral_color) + model.refresh_all_edge_colors(neutral_color.into()))); profiling_mode_transition.target <+ out.mode.map(|&mode| { match mode { - Mode::Normal => 0.0, - Mode::Profiling => 1.0, + view::Mode::Normal => 0.0, + view::Mode::Profiling => 1.0, } }); eval profiling_mode_transition.value ((&v) scene.dom.layers.back.filter_grayscale(v)); diff --git a/src/rust/ide/view/graph-editor/src/profiling.rs b/src/rust/ide/view/graph-editor/src/profiling.rs index ca6ac283af..441e9b6b04 100644 --- a/src/rust/ide/view/graph-editor/src/profiling.rs +++ b/src/rust/ide/view/graph-editor/src/profiling.rs @@ -2,22 +2,36 @@ //! exposes their minimum and maximum running times through its FRP endpoints. The structure needs //! to be updated whenever a node is added or deleted or changes its profiling status. +use crate::prelude::*; + +use crate::node; +use crate::NodeId; + +use enso_frp as frp; use bimap::BiBTreeMap; use ordered_float::OrderedFloat; -use super::*; - ensogl::define_endpoints! { Input { - set (NodeId,node::profiling::Status), + /// Informs the `Statuses` collection about the profiling status of a node. + set(NodeId,node::profiling::Status), + + /// Removes a node's information from the collection. remove (NodeId) } Output { + /// The minimum running time of any node in milliseconds. Is positive infinity if no status + /// was registered. min_duration (f32), + + /// The maximum running time of any node in milliseconds. Is 0.0 if no status was + /// registered. max_duration (f32), } } +/// Can be used to track the execution statuses of all nodes in the graph editor. Exposes the +/// minimum and maximum running time through FRP endpoints. #[derive(Debug,Clone,CloneRef,Default)] pub struct Statuses { frp : Frp, @@ -33,11 +47,12 @@ impl Deref for Statuses { } impl Statuses { + /// Creates a new `Statuses` collection. pub fn new() -> Self { let frp = Frp::new(); let durations = Rc::new(RefCell::new(BiBTreeMap::>::new())); - let network = &frp.network; + frp::extend! { network min_and_max_from_set <- frp.set.map(f!([durations]((node,status)) { match status { @@ -56,7 +71,7 @@ impl Statuses { Self::min_and_max(&*durations.borrow()) })); - min_and_max <- any(&min_and_max_from_set,&min_and_max_from_remove); + min_and_max <- any(&min_and_max_from_set,&min_and_max_from_remove); frp.source.min_duration <+ min_and_max._0().on_change(); frp.source.max_duration <+ min_and_max._1().on_change(); } @@ -66,6 +81,7 @@ impl Statuses { fn min_and_max(durations:&BiBTreeMap>) -> (f32,f32) { let mut durations = durations.right_values().copied(); + let min = durations.next().map(OrderedFloat::into_inner).unwrap_or(std::f32::INFINITY); let max = durations.last().map(OrderedFloat::into_inner).unwrap_or(0.0); (min, max) diff --git a/src/rust/ide/view/graph-editor/src/view.rs b/src/rust/ide/view/graph-editor/src/view.rs new file mode 100644 index 0000000000..77ef89810c --- /dev/null +++ b/src/rust/ide/view/graph-editor/src/view.rs @@ -0,0 +1,43 @@ +//! Provides the `Mode` enum to represent the graph editors view mode. + +use crate::prelude::*; + +/// Represents the current view mode of the graph editor. In profiling mode, most colors are removed +/// from the interface and each node displays some profiling information, using color to represent +/// the running time. +#[derive(Debug,Copy,Clone,CloneRef,PartialEq,Eq)] +pub enum Mode { + /// The standard mode of the graph editor. Edges are colored to reflect type information and no + /// profiling information is visible. + Normal, + + /// The graph editor's profiling mode. Color is used sparingly. Every node shows profiling + /// information and uses color to represent its running time. + Profiling +} + +impl Default for Mode { + fn default() -> Self { + Mode::Normal + } +} + +impl Mode { + /// Returns true if this is the normal mode. + pub fn is_normal(self) -> bool { + matches!(self,Mode::Normal) + } + + /// Returns true if this is the profiling mode. + pub fn is_profiling(self) -> bool { + matches!(self,Mode::Profiling) + } + + /// Maps `Normal` to `Profiling` and `Profiling` to `Normal`. + pub fn switch(self) -> Mode { + match self { + Mode::Normal => Mode::Profiling, + Mode::Profiling => Mode::Normal, + } + } +} diff --git a/src/rust/ide/view/src/debug_scenes/interface.rs b/src/rust/ide/view/src/debug_scenes/interface.rs index 8cd6b8ddb2..86d346ac10 100644 --- a/src/rust/ide/view/src/debug_scenes/interface.rs +++ b/src/rust/ide/view/src/debug_scenes/interface.rs @@ -196,11 +196,11 @@ fn init(app:&Application) { // === Profiling === - let node1_status = NodeProfilingStatus::Finished { duration: 400.0 }; + let node1_status = NodeProfilingStatus::Finished { duration: 500.0 }; graph_editor.set_node_profiling_status(node1_id, node1_status); - let node2_status = NodeProfilingStatus::Finished { duration: 300.0 }; + let node2_status = NodeProfilingStatus::Finished { duration: 1000.0 }; graph_editor.set_node_profiling_status(node2_id, node2_status); - let node3_status = NodeProfilingStatus::Finished { duration: 200.0 }; + let node3_status = NodeProfilingStatus::Finished { duration: 1500.0 }; graph_editor.set_node_profiling_status(node3_id, node3_status); diff --git a/src/rust/lib/frp/src/nodes.rs b/src/rust/lib/frp/src/nodes.rs index 8c23ad58ce..3a1af59697 100644 --- a/src/rust/lib/frp/src/nodes.rs +++ b/src/rust/lib/frp/src/nodes.rs @@ -499,6 +499,15 @@ impl Network { self.register(OwnedAllWith5::new(label,t1,t2,t3,t4,t5,f)) } + /// Specialized version `all_with`. + pub fn all_with6 + (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, t6:&T6, f:F) -> Stream + where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, T:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output)->T { + self.register(OwnedAllWith6::new(label,t1,t2,t3,t4,t5,t6,f)) + } + /// Specialized version `all_with`. pub fn all_with8 (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, t6:&T6, t7:&T7, t8:&T8, f:F) @@ -2406,6 +2415,73 @@ impl Debug for AllWith5Data { +// ================ +// === AllWith6 === +// ================ + +pub struct AllWith6Data +{ src1:watch::Ref, src2:watch::Ref, src3:watch::Ref, src4:watch::Ref + , src5:watch::Ref, src6:watch::Ref, function:F } +pub type OwnedAllWith6 = + stream::Node >; +pub type AllWith6 = + stream::WeakNode >; + +impl HasOutput for AllWith6Data +where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output)->Out { + type Output = Out; +} + +impl OwnedAllWith6 +where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output)->Out { + /// Constructor. + pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, t5:&T5, t6:&T6, function:F) -> Self { + let src1 = watch_stream(t1); + let src2 = watch_stream(t2); + let src3 = watch_stream(t3); + let src4 = watch_stream(t4); + let src5 = watch_stream(t5); + let src6 = watch_stream(t6); + let def = AllWith6Data {src1,src2,src3,src4,src5,src6,function}; + let this = Self::construct(label,def); + let weak = this.downgrade(); + t1.register_target(weak.clone_ref().into()); + t2.register_target(weak.clone_ref().into()); + t3.register_target(weak.clone_ref().into()); + t4.register_target(weak.clone_ref().into()); + t5.register_target(weak.clone_ref().into()); + t6.register_target(weak.into()); + this + } +} + +impl stream::EventConsumer for OwnedAllWith6 +where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOutput, + T6:EventOutput, Out:Data, + F:'static+Fn(&Output,&Output,&Output,&Output,&Output,&Output)->Out { + fn on_event(&self, stack:CallStack, _:&T) { + let value1 = self.src1.value(); + let value2 = self.src2.value(); + let value3 = self.src3.value(); + let value4 = self.src4.value(); + let value5 = self.src5.value(); + let value6 = self.src6.value(); + let out = (self.function)(&value1,&value2,&value3,&value4,&value5,&value6); + self.emit_event(stack,&out); + } +} + +impl Debug for AllWith6Data { + fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f,"AllWith6Data") + } +} + + // ================ // === AllWith8 === @@ -2483,6 +2559,6 @@ where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T5:EventOu impl Debug for AllWith8Data { fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f,"AllWith5Data") + write!(f,"AllWith8Data") } } From 7aeab47cf71dda35206d7eb888c677a52bc446a2 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Tue, 25 May 2021 16:13:18 +0100 Subject: [PATCH 19/29] Fix FRP initializations --- .../view/graph-editor/src/component/node/input/area.rs | 10 ++++++++++ .../graph-editor/src/component/node/output/area.rs | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs index 5dac18bb01..6a73aad08a 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs @@ -646,6 +646,7 @@ impl Area { self.frp.output.source.pointer_style <+ pointer_style; } init_color.emit(()); + frp.source.view_mode.emit(frp.view_mode.value()); port_shape.display_object().clone_ref() }; @@ -782,6 +783,13 @@ impl Area { transparent <- init_color.constant(color::Lcha::transparent()); viz_color_target <- is_connected.switch(&transparent,&connected_viz_color); + // We need to make sure that the network contains correct values before we + // connect the `viz_color` animation. The reason is that the animation will + // start from the first value that it receives, and during initialization of the + // network, while some nodes are still set to their defaults, this first value + // would be incorrect, causing the animation in some cases to start from black + // (the default color) and animating towards the color that we really want to + // set. init_color.emit(()); viz_color.target <+ viz_color_target; @@ -792,6 +800,8 @@ impl Area { } Some(frp.tp.clone_ref().into()) }); + + self.frp.source.view_mode.emit(self.frp.view_mode.value()); } /// This function first assigns the new expression to the model and then emits the definition diff --git a/src/rust/ide/view/graph-editor/src/component/node/output/area.rs b/src/rust/ide/view/graph-editor/src/component/node/output/area.rs index b9e76822a8..2ba0b1ba2c 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/output/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/output/area.rs @@ -141,6 +141,7 @@ ensogl::define_endpoints! { body_hover (bool), type_label_visibility (bool), tooltip (tooltip::Style), + view_mode (view::Mode), } } @@ -318,10 +319,11 @@ impl Model { self.frp.source.on_port_type_change <+ port_frp.tp.map(move |t|(crumbs.clone(),t.clone())); port_frp.set_type_label_visibility <+ self.frp.type_label_visibility; self.frp.source.tooltip <+ port_frp.tooltip; - port_frp.set_view_mode <+ self.frp.set_view_mode; + port_frp.set_view_mode <+ self.frp.view_mode; } port_frp.set_type_label_visibility.emit(self.frp.type_label_visibility.value()); + port_frp.set_view_mode.emit(self.frp.view_mode.value()); self.ports.add_child(&port_shape); port_index += 1; } @@ -438,6 +440,11 @@ impl Area { label_color_on_change <- label_color.value.sample(&frp.set_expression); new_label_color <- any(&label_color.value,&label_color_on_change); eval new_label_color ((color) model.label.set_color_all(color::Rgba::from(color))); + + + // === View Mode === + + frp.source.view_mode <+ frp.set_view_mode; } label_color.target_alpha(0.0); From 659a68b037e2936cbe5fafa40ed941430a7a90bc Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Tue, 25 May 2021 16:46:10 +0100 Subject: [PATCH 20/29] Rename running time label to profiling label --- .../view/graph-editor/src/component/node.rs | 38 +++++++++---------- .../src/component/node/profiling.rs | 14 +++---- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node.rs b/src/rust/ide/view/graph-editor/src/component/node.rs index c95844c9aa..4baeee7d4f 100644 --- a/src/rust/ide/view/graph-editor/src/component/node.rs +++ b/src/rust/ide/view/graph-editor/src/component/node.rs @@ -20,7 +20,7 @@ pub use expression::Expression; use crate::prelude::*; -use crate::component::node::profiling::RunningTimeLabel; +use crate::component::node::profiling::ProfilingLabel; use crate::view; use crate::component::visualization; use crate::tooltip; @@ -367,7 +367,7 @@ pub struct NodeModel { pub background : background::View, pub drag_area : drag_area::View, pub error_indicator : error_shape::View, - pub running_time_label : RunningTimeLabel, + pub profiling_label : ProfilingLabel, pub input : input::Area, pub output : output::Area, pub visualization : visualization::Container, @@ -404,15 +404,15 @@ impl NodeModel { let drag_logger = Logger::sub(&logger,"drag_area"); let error_indicator_logger = Logger::sub(&logger,"error_indicator"); - let error_indicator = error_shape::View::new(&error_indicator_logger); - let running_time_label = RunningTimeLabel::new(app); - let backdrop = backdrop::View::new(&main_logger); - let background = background::View::new(&main_logger); - let drag_area = drag_area::View::new(&drag_logger); - let vcs_indicator = vcs::StatusIndicator::new(app); - let display_object = display::object::Instance::new(&logger); + let error_indicator = error_shape::View::new(&error_indicator_logger); + let profiling_label = ProfilingLabel::new(app); + let backdrop = backdrop::View::new(&main_logger); + let background = background::View::new(&main_logger); + let drag_area = drag_area::View::new(&drag_logger); + let vcs_indicator = vcs::StatusIndicator::new(app); + let display_object = display::object::Instance::new(&logger); - display_object.add_child(&running_time_label); + display_object.add_child(&profiling_label); display_object.add_child(&drag_area); display_object.add_child(&backdrop); display_object.add_child(&background); @@ -443,7 +443,7 @@ impl NodeModel { let app = app.clone_ref(); Self {app,display_object,logger,backdrop,background,drag_area,output,input,visualization - ,error_visualization,running_time_label,action_bar,error_indicator,vcs_indicator,style} + ,error_visualization,profiling_label,action_bar,error_indicator,vcs_indicator,style} .init() } @@ -603,10 +603,10 @@ impl Node { // === View Mode === - model.input.set_view_mode <+ frp.set_view_mode; - model.output.set_view_mode <+ frp.set_view_mode; - model.running_time_label.set_view_mode <+ frp.set_view_mode; - model.vcs_indicator.set_visibility <+ frp.set_view_mode.map(|&mode| { + model.input.set_view_mode <+ frp.set_view_mode; + model.output.set_view_mode <+ frp.set_view_mode; + model.profiling_label.set_view_mode <+ frp.set_view_mode; + model.vcs_indicator.set_visibility <+ frp.set_view_mode.map(|&mode| { !matches!(mode,view::Mode::Profiling {..}) }); } @@ -693,12 +693,12 @@ impl Node { // === Profiling Indicator === frp::extend! { network - model.running_time_label.set_min_global_duration + model.profiling_label.set_min_global_duration <+ frp.set_profiling_min_global_duration; - model.running_time_label.set_max_global_duration + model.profiling_label.set_max_global_duration <+ frp.set_profiling_max_global_duration; - model.running_time_label.set_status <+ frp.set_profiling_status; - model.input.set_profiling_status <+ frp.set_profiling_status; + model.profiling_label.set_status <+ frp.set_profiling_status; + model.input.set_profiling_status <+ frp.set_profiling_status; } let bg_color_anim = color::Animation::new(network); diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs index 575b817046..110549abfb 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs @@ -1,5 +1,5 @@ //! Provides [`Status`] to represent a node's execution status, [`Status::display_color`] to express -//! that status as a color and [`RunningTimeLabel`] to display a node's execution status. +//! that status as a color and [`ProfilingLabel`] to display a node's execution status. use crate::prelude::*; @@ -173,14 +173,14 @@ ensogl::define_endpoints! { /// The necessary theme will be taken from the application's style sheet. The origin of the label, /// as a `display::Object` should be placed on the node's center. #[derive(Clone,CloneRef,Debug)] -pub struct RunningTimeLabel { +pub struct ProfilingLabel { root : display::object::Instance, label : text::Area, frp : Frp, styles : StyleWatchFrp, } -impl Deref for RunningTimeLabel { +impl Deref for ProfilingLabel { type Target = Frp; fn deref(&self) -> &Self::Target { @@ -188,8 +188,8 @@ impl Deref for RunningTimeLabel { } } -impl RunningTimeLabel { - /// Constructs a `RunningTimeLabel` for the given application. +impl ProfilingLabel { + /// Constructs a `ProfilingLabel` for the given application. pub fn new(app: &Application) -> Self { let scene = app.display.scene(); let root = display::object::Instance::new(Logger::new("ProfilingIndicator")); @@ -240,11 +240,11 @@ impl RunningTimeLabel { label.set_content <+ frp.set_status.map(|status| status.to_string()); } - RunningTimeLabel {root,label,frp,styles} + ProfilingLabel {root,label,frp,styles} } } -impl display::Object for RunningTimeLabel { +impl display::Object for ProfilingLabel { fn display_object(&self) -> &display::object::Instance { &self.root } From c1c503e089963a0673b4ca525210c48356e4e719 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Wed, 26 May 2021 13:02:58 +0100 Subject: [PATCH 21/29] Update edge colors less often --- src/rust/ide/view/graph-editor/src/lib.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index 4d3269c2f5..96efeace64 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -3044,19 +3044,20 @@ fn new_graph_editor(app:&Application) -> GraphEditor { out.source.on_edge_only_source_not_set <+ out.on_edge_target_set_with_source_not_set._0(); out.source.on_edge_only_source_not_set <+ out.on_edge_source_unset._0(); - let neutral_color = styles_frp.get_color(theme::code::types::any::selection); - _eval <- all_with(&out.on_edge_source_set,&neutral_color,f!(((id,_),neutral_color) - model.refresh_edge_color(*id,neutral_color.into()))); - _eval <- all_with(&out.on_edge_target_set,&neutral_color,f!(((id,_),neutral_color) - model.refresh_edge_color(*id,neutral_color.into()))); - _eval <- all_with(&out.on_edge_source_unset,&neutral_color,f!(((id,_),neutral_color) - model.refresh_edge_color(*id,neutral_color.into()))); - _eval <- all_with(&out.on_edge_target_unset,&neutral_color,f!(((id,_),neutral_color) - model.refresh_edge_color(*id,neutral_color.into()))); + let neutral_color = model.model.styles_frp.get_color(theme::code::types::any::selection); + eval out.on_edge_source_set ([model,neutral_color]((id, _)) + model.refresh_edge_color(*id,neutral_color.value().into())); + eval out.on_edge_target_set ([model,neutral_color]((id, _)) + model.refresh_edge_color(*id,neutral_color.value().into())); + eval out.on_edge_source_unset ([model,neutral_color]((id, _)) + model.refresh_edge_color(*id,neutral_color.value().into())); + eval out.on_edge_target_unset ([model,neutral_color]((id, _)) + model.refresh_edge_color(*id,neutral_color.value().into())); + eval neutral_color ((neutral_color) model.refresh_all_edge_colors(neutral_color.into())); edge_to_refresh_on_hover <= out.hover_node_input.map(f_!(model.edges_with_detached_targets())); - _eval <- all_with(&edge_to_refresh_on_hover,&neutral_color,f!((id,neutral_color) - model.refresh_edge_color(*id,neutral_color.into()))); + eval edge_to_refresh_on_hover ([model,neutral_color](id) + model.refresh_edge_color(*id,neutral_color.value().into())); some_edge_sources_unset <- out.on_all_edges_sources_set ?? out.on_some_edges_sources_unset; From ea12ada29225ca932fa54df017a7207c34720f72 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Wed, 26 May 2021 13:03:16 +0100 Subject: [PATCH 22/29] Fix some color initializations and updates --- .../src/component/node/input/area.rs | 9 ++++++++- src/rust/ide/view/graph-editor/src/lib.rs | 20 ++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs index 6a73aad08a..4529ae2a68 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs @@ -567,7 +567,7 @@ impl Area { // FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape system (#795) let style_sheet = &self.model.app.display.scene().style_sheet; let styles = StyleWatch::new(style_sheet); - let styles_frp = StyleWatchFrp::new(style_sheet); + let styles_frp = &self.model.styles_frp; let any_type_sel_color = styles_frp.get_color(theme::code::types::any::selection); let crumbs = port.crumbs.clone_ref(); let port_network = &port.network; @@ -725,6 +725,10 @@ impl Area { profiled <- in_profiling_mode && finished; selected <- frp.set_hover || frp.set_parent_connected; + init_colors <- source::<()>(); + std_base_color <- all(std_base_color,init_colors)._0(); + profiled_base_color <- all(profiled_base_color,init_colors)._0(); + profiling_color <- finished.switch(&std_base_color,&profiled_base_color); normal_color <- frp.tp.map(f!([styles](t) color::Rgba::from(type_coloring::compute_for_code(t.as_ref(),&styles)))); @@ -759,6 +763,9 @@ impl Area { label.set_color_bytes(range,color::Rgba::from(color)); }); } + + init_colors.emit(()); + self.set_view_mode(self.view_mode.value()); } diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index 96efeace64..e4342d237e 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -1102,7 +1102,6 @@ impl GraphEditorModelWithNetwork { let touch = &self.touch_state; let model = &self.model; - let styles_frp = StyleWatchFrp::new(&model.scene().style_sheet); let NodeCreationContext {pointer_style,tooltip_update,output_press,input_press,output} = ctx; @@ -1137,15 +1136,21 @@ impl GraphEditorModelWithNetwork { model.frp.source.hover_node_output.emit(output); }); - let neutral_color = styles_frp.get_color(theme::code::types::any::selection); + let neutral_color = model.styles_frp.get_color(theme::code::types::any::selection); _eval <- all_with(&node.model.input.frp.on_port_type_change,&neutral_color, f!(((crumbs,_),neutral_color) - model.with_input_edge_id(node_id,crumbs,|id| model.refresh_edge_color(id,neutral_color.into())))); + model.with_input_edge_id(node_id,crumbs,|id| + model.refresh_edge_color(id,neutral_color.into()) + ) + )); _eval <- all_with(&node.model.input.frp.on_port_type_change,&neutral_color, f!(((crumbs,_),neutral_color) - model.with_output_edge_id(node_id,crumbs,|id| model.refresh_edge_color(id,neutral_color.into())))); + model.with_output_edge_id(node_id,crumbs,|id| + model.refresh_edge_color(id,neutral_color.into()) + ) + )); eval node.frp.expression((t) output.source.node_expression_set.emit((node_id,t.into()))); @@ -1320,6 +1325,7 @@ pub struct GraphEditorModel { navigator : Navigator, profiling_statuses : profiling::Statuses, profiling_button : component::profiling::Button, + styles_frp : StyleWatchFrp, } @@ -1347,10 +1353,11 @@ impl GraphEditorModel { let tooltip = Tooltip::new(&app); let profiling_statuses = profiling::Statuses::new(); let profiling_button = component::profiling::Button::new(&app); + let styles_frp = StyleWatchFrp::new(&scene.style_sheet); Self { - logger,display_object,app,cursor,nodes,edges,touch_state,frp,breadcrumbs, - vis_registry,visualisations,navigator,tooltip,profiling_statuses,profiling_button, + logger,display_object,app,cursor,nodes,edges,touch_state,frp,breadcrumbs,vis_registry + ,visualisations,navigator,tooltip,profiling_statuses,profiling_button,styles_frp }.init() } @@ -2115,7 +2122,6 @@ fn new_graph_editor(app:&Application) -> GraphEditor { // FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape system (#795) let styles = StyleWatch::new(&scene.style_sheet); - let styles_frp = StyleWatchFrp::new(&scene.style_sheet); let any_type_sel_color = color::Lcha::from(styles.get_color(theme::code::types::any::selection)); From bcfa122e3c8bbccd44ad7512c753bba730ef591f Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Wed, 26 May 2021 14:53:19 +0100 Subject: [PATCH 23/29] Fix field order in struct constructions --- src/rust/ide/view/graph-editor/src/component/node.rs | 6 +++--- .../ide/view/graph-editor/src/component/node/profiling.rs | 2 +- src/rust/ide/view/graph-editor/src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node.rs b/src/rust/ide/view/graph-editor/src/component/node.rs index f45f376b37..2bf7c023cc 100644 --- a/src/rust/ide/view/graph-editor/src/component/node.rs +++ b/src/rust/ide/view/graph-editor/src/component/node.rs @@ -442,9 +442,9 @@ impl NodeModel { let style = StyleWatchFrp::new(&app.display.scene().style_sheet); let app = app.clone_ref(); - Self {app,display_object,logger,backdrop,background,drag_area,error_indicator,input,output - ,visualization,error_visualization,action_bar,profiling_label,vcs_indicator,style} - .init() + Self {app,display_object,logger,backdrop,background,drag_area,error_indicator + ,profiling_label,input,output,visualization,error_visualization,action_bar + ,vcs_indicator,style}.init() } pub fn get_crumbs_by_id(&self, id:ast::Id) -> Option { diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs index 110549abfb..ffff4d32f9 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs @@ -111,7 +111,7 @@ impl Theme { init_theme <- source::<()>(); theme <- all_with5(&lightness,&chroma,&min_time_hue,&max_time_hue,&init_theme ,|&lightness,&chroma,&min_time_hue,&max_time_hue,_| - Theme {lightness,chroma,max_time_hue,min_time_hue}); + Theme {lightness,chroma,min_time_hue,max_time_hue}); theme_sampler <- theme.sampler(); } diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index e12f0cd93b..7bff8e7cc8 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -1352,7 +1352,7 @@ impl GraphEditorModel { Self { logger,display_object,app,breadcrumbs,cursor,nodes,edges,vis_registry,tooltip, - profiling_statuses,profiling_button,touch_state,visualisations,frp,navigator,styles_frp + touch_state,visualisations,frp,navigator,profiling_statuses,profiling_button,styles_frp }.init() } From 873c5c4237571c53a8ac2a56c42ae30a30530d99 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Wed, 26 May 2021 16:51:57 +0100 Subject: [PATCH 24/29] Fix text color when edited in profiling mode --- .../view/graph-editor/src/component/node/input/area.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs index 7d891634df..b89d7c83e3 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/input/area.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/input/area.rs @@ -411,11 +411,20 @@ impl Area { use theme::code::syntax; let std_selection_color = model.styles_frp.get_color(syntax::selection); let profiled_selection_color = model.styles_frp.get_color(syntax::profiling::selection); + let std_base_color = model.styles_frp.get_color(syntax::base); + let profiled_base_color = model.styles_frp.get_color(syntax::profiling::base); selection_color_rgba <- profiled.switch(&std_selection_color,&profiled_selection_color); selection_color.target <+ selection_color_rgba.map(|c| color::Lcha::from(c)); model.label.set_selection_color <+ selection_color.value.map(|&c| color::Rgb::from(c)); + + init_colors <- source::<()>(); + std_base_color <- all(std_base_color,init_colors)._0(); + profiled_base_color <- all(profiled_base_color,init_colors)._0(); + base_color <- profiled.switch(&std_base_color,&profiled_base_color); + eval base_color ((color) model.label.set_default_color(color)); + init_colors.emit(()); } Self {frp,model} From 4f19a29ef1948263018fee6f532ff17b706103f0 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Thu, 27 May 2021 12:29:51 +0100 Subject: [PATCH 25/29] Update for renamed definitions --- .../ide/view/graph-editor/src/component/node/profiling.rs | 4 ++-- src/rust/ide/view/graph-editor/src/component/profiling.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs index ffff4d32f9..e29fdf35dc 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs @@ -197,8 +197,8 @@ impl ProfilingLabel { let label = text::Area::new(app); root.add_child(&label); label.set_position_y(crate::component::node::input::area::TEXT_SIZE/2.0); - label.remove_from_scene_layer_DEPRECATED(&scene.layers.main); - label.add_to_scene_layer_DEPRECATED(&scene.layers.label); + label.remove_from_scene_layer(&scene.layers.main); + label.add_to_scene_layer(&scene.layers.label); let frp = Frp::new(); let network = &frp.network; diff --git a/src/rust/ide/view/graph-editor/src/component/profiling.rs b/src/rust/ide/view/graph-editor/src/component/profiling.rs index cbd818ae91..920ca0d424 100644 --- a/src/rust/ide/view/graph-editor/src/component/profiling.rs +++ b/src/rust/ide/view/graph-editor/src/component/profiling.rs @@ -149,7 +149,7 @@ impl Button { let network = &frp.network; let button = ToggleButton::::new(Logger::new("profiling::Button")); - scene.layers.breadcrumbs_background.add_exclusive(&button); + scene.layers.panel.add_exclusive(&button); button.set_visibility(true); button.set_size(Vector2(32.0, 32.0)); From fdee41a10b40a53c5675f2fa4cffeb4420040a4b Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Thu, 27 May 2021 20:14:14 +0100 Subject: [PATCH 26/29] Fix cursor color after view mode switch --- src/rust/ide/view/graph-editor/src/lib.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index 7bff8e7cc8..742db21662 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -3129,17 +3129,18 @@ fn new_graph_editor(app:&Application) -> GraphEditor { frp::extend! { network - on_some_edges_detached <- out.some_edge_endpoints_unset.gate(&out.some_edge_endpoints_unset); - cursor_style_edge_drag <- all_with(&on_some_edges_detached,&neutral_color, - f!([model](_,neutral_color){ - if let Some(color) = model.first_detached_edge_color(neutral_color.into()) { - cursor::Style::new_color(color).press() + cursor_style_edge_drag <- all_with(&out.some_edge_endpoints_unset,&out.view_mode, + f!([model,neutral_color](some_edges_detached,_) { + if *some_edges_detached { + if let Some(color) = model.first_detached_edge_color(neutral_color.value().into()) { + cursor::Style::new_color(color).press() + } else { + cursor::Style::new_color_no_animation(neutral_color.value().into()).press() + } } else { - cursor::Style::new_color_no_animation(any_type_sel_color).press() + default() } })); - cursor_style_on_edge_drag_stop <- out.on_all_edges_endpoints_set.constant(default()); - cursor_style_edge_drag <- any (cursor_style_edge_drag,cursor_style_on_edge_drag_stop); let breadcrumb_style = model.breadcrumbs.pointer_style.clone_ref(); From 1073d1a47c965b9ed2e50947bc7cb988942853e4 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Thu, 27 May 2021 20:14:34 +0100 Subject: [PATCH 27/29] Rename "mode" to "view mode" --- .../graph-editor/src/component/profiling.rs | 12 ++++++------ src/rust/ide/view/graph-editor/src/lib.rs | 19 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/component/profiling.rs b/src/rust/ide/view/graph-editor/src/component/profiling.rs index 920ca0d424..4942eada9d 100644 --- a/src/rust/ide/view/graph-editor/src/component/profiling.rs +++ b/src/rust/ide/view/graph-editor/src/component/profiling.rs @@ -110,10 +110,10 @@ mod icon { ensogl::define_endpoints! { Input { - set_mode (view::Mode), + set_view_mode (view::Mode), } Output { - mode (view::Mode), + view_mode (view::Mode), } } @@ -123,8 +123,8 @@ ensogl::define_endpoints! { // === ProfilingButton === // ======================= -/// A toggle button that can be used to toggle the graph editor's mode. It positions itself in the -/// upper right corner of the scene. +/// A toggle button that can be used to toggle the graph editor's view mode. It positions itself in +/// the upper right corner of the scene. #[derive(Debug,Clone,CloneRef)] pub struct Button { frp : Frp, @@ -157,10 +157,10 @@ impl Button { // === State === - frp.source.mode <+ button.state.map(|&toggled| { + frp.source.view_mode <+ button.state.map(|&toggled| { if toggled { view::Mode::Profiling } else { view::Mode::Normal } }); - button.set_state <+ frp.set_mode.map(|&mode| mode.is_profiling()); + button.set_state <+ frp.set_view_mode.map(|&mode| mode.is_profiling()); // === Position === diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index 742db21662..cbf3648874 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -563,7 +563,7 @@ ensogl::define_endpoints! { node_being_edited (Option), node_editing (bool), - mode (view::Mode), + view_mode (view::Mode), navigator_active (bool), } @@ -1200,7 +1200,7 @@ impl GraphEditorModelWithNetwork { // === Mode === - node.set_view_mode <+ self.model.frp.mode; + node.set_view_mode <+ self.model.frp.view_mode; // === Profiling === @@ -1212,7 +1212,7 @@ impl GraphEditorModelWithNetwork { node.set_profiling_max_global_duration <+ self.model.profiling_statuses.max_duration; node.set_profiling_max_global_duration(profiling_max_duration.value()); } - node.set_view_mode(self.model.frp.mode.value()); + node.set_view_mode(self.model.frp.view_mode.value()); let initial_metadata = visualization::Metadata { preprocessor : node.model.visualization.frp.preprocessor.value() }; @@ -1895,7 +1895,7 @@ impl GraphEditorModel { fn edge_color(&self, edge_id:EdgeId, neutral_color:color::Lcha) -> color::Lcha { // FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape system (#795) let styles = StyleWatch::new(&self.scene().style_sheet); - match self.frp.mode.value() { + match self.frp.view_mode.value() { view::Mode::Normal => { let edge_type = self.edge_hover_type() .or_else(|| self.edge_target_type(edge_id)) @@ -2117,7 +2117,6 @@ fn new_graph_editor(app:&Application) -> GraphEditor { // FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape system (#795) let styles = StyleWatch::new(&scene.style_sheet); - let any_type_sel_color = color::Lcha::from(styles.get_color(theme::code::types::any::selection)); @@ -3181,14 +3180,14 @@ fn new_graph_editor(app:&Application) -> GraphEditor { let profiling_mode_transition = Animation::new(network); frp::extend! { network - out.source.mode <+ frp.toggle_profiling_mode.map2(&frp.mode,|_,&mode| mode.switch()); - out.source.mode <+ model.profiling_button.mode; + out.source.view_mode <+ frp.toggle_profiling_mode.map2(&frp.view_mode,|_,&mode| mode.switch()); + out.source.view_mode <+ model.profiling_button.view_mode; - model.profiling_button.set_mode <+ out.mode.on_change(); - _eval <- all_with(&out.mode,&neutral_color,f!((_,neutral_color) + model.profiling_button.set_view_mode <+ out.view_mode.on_change(); + _eval <- all_with(&out.view_mode,&neutral_color,f!((_,neutral_color) model.refresh_all_edge_colors(neutral_color.into()))); - profiling_mode_transition.target <+ out.mode.map(|&mode| { + profiling_mode_transition.target <+ out.view_mode.map(|&mode| { match mode { view::Mode::Normal => 0.0, view::Mode::Profiling => 1.0, From 25ce8b0aed54573da30e08fdcbb9693cfac82de2 Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Fri, 28 May 2021 16:52:18 +0100 Subject: [PATCH 28/29] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dbdc753f3..7f7d79be56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ #### Visual Environment +- [Profling mode.][1546] The IDE contains a profiling mode now which can be + entered through a button in the top-right corner or through the keybinding + ctrl+p. This mode does not display any information yet. + In the future, it will display the running times of nodes and maybe more + useful statistics. + #### EnsoGL (rendering engine)
![Bug Fixes](/docs/assets/tags/bug_fixes.svg) From 1a2917d972036ce97b37e3fd0ba6a19290c60a0d Mon Sep 17 00:00:00 2001 From: Felix Rech Date: Tue, 8 Jun 2021 11:41:37 +0100 Subject: [PATCH 29/29] Make requested changes --- .../graph-editor/src/component/node/profiling.rs | 10 +++++----- src/rust/ide/view/graph-editor/src/lib.rs | 2 +- src/rust/ide/view/graph-editor/src/profiling.rs | 12 ++++++++++++ src/rust/ide/view/graph-editor/src/view.rs | 6 ++++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs index e29fdf35dc..69d34c3b88 100644 --- a/src/rust/ide/view/graph-editor/src/component/node/profiling.rs +++ b/src/rust/ide/view/graph-editor/src/component/node/profiling.rs @@ -155,7 +155,7 @@ ensogl::define_endpoints! { set_status (Status), set_min_global_duration (f32), set_max_global_duration (f32), - set_view_mode (view::Mode), + set_view_mode (view::Mode), } } @@ -174,10 +174,10 @@ ensogl::define_endpoints! { /// as a `display::Object` should be placed on the node's center. #[derive(Clone,CloneRef,Debug)] pub struct ProfilingLabel { - root : display::object::Instance, - label : text::Area, - frp : Frp, - styles : StyleWatchFrp, + root : display::object::Instance, + label : text::Area, + frp : Frp, + styles : StyleWatchFrp, } impl Deref for ProfilingLabel { diff --git a/src/rust/ide/view/graph-editor/src/lib.rs b/src/rust/ide/view/graph-editor/src/lib.rs index cbf3648874..25623cc9c7 100644 --- a/src/rust/ide/view/graph-editor/src/lib.rs +++ b/src/rust/ide/view/graph-editor/src/lib.rs @@ -1198,7 +1198,7 @@ impl GraphEditorModelWithNetwork { output.source.visualization_disabled <+ vis_disabled.constant(node_id); - // === Mode === + // === View Mode === node.set_view_mode <+ self.model.frp.view_mode; diff --git a/src/rust/ide/view/graph-editor/src/profiling.rs b/src/rust/ide/view/graph-editor/src/profiling.rs index 441e9b6b04..7d1e1927b8 100644 --- a/src/rust/ide/view/graph-editor/src/profiling.rs +++ b/src/rust/ide/view/graph-editor/src/profiling.rs @@ -11,6 +11,12 @@ use enso_frp as frp; use bimap::BiBTreeMap; use ordered_float::OrderedFloat; + + +// ===================== +// === FRP Endpoints === +// ===================== + ensogl::define_endpoints! { Input { /// Informs the `Statuses` collection about the profiling status of a node. @@ -30,6 +36,12 @@ ensogl::define_endpoints! { } } + + +// ================ +// === Statuses === +// ================ + /// Can be used to track the execution statuses of all nodes in the graph editor. Exposes the /// minimum and maximum running time through FRP endpoints. #[derive(Debug,Clone,CloneRef,Default)] diff --git a/src/rust/ide/view/graph-editor/src/view.rs b/src/rust/ide/view/graph-editor/src/view.rs index 77ef89810c..cce3977156 100644 --- a/src/rust/ide/view/graph-editor/src/view.rs +++ b/src/rust/ide/view/graph-editor/src/view.rs @@ -2,6 +2,12 @@ use crate::prelude::*; + + +// ================= +// === View Mode === +// ================= + /// Represents the current view mode of the graph editor. In profiling mode, most colors are removed /// from the interface and each node displays some profiling information, using color to represent /// the running time.