diff --git a/app/gui/src/ide/initializer.rs b/app/gui/src/ide/initializer.rs index ece7f37f50..0c37727a5b 100644 --- a/app/gui/src/ide/initializer.rs +++ b/app/gui/src/ide/initializer.rs @@ -81,7 +81,7 @@ impl Initializer { match self.initialize_ide_controller_with_retries().await { Ok(controller) => { let can_manage_projects = controller.can_manage_projects(); - let ide = Ide::new(ensogl_app, view.clone_ref(), controller); + let ide = Ide::new(ensogl_app, view, controller); if can_manage_projects { if let Some(project) = &self.config.project_to_open { ide.open_or_create_project(project.clone()); diff --git a/app/gui/src/lib.rs b/app/gui/src/lib.rs index 9b15f1d354..07faae7eda 100644 --- a/app/gui/src/lib.rs +++ b/app/gui/src/lib.rs @@ -203,12 +203,20 @@ pub fn main() { #[wasm_bindgen] pub fn drop() { let ide = IDE.with(RefCell::take); - if let Some(Ok(ide)) = &ide { + if let Some(Ok(ide)) = ide { //TODO[ao] #6420 We should not do this, but somehow the `dom` field in the scene is // leaking. ide.ensogl_app.display.default_scene.dom.root.remove(); - } - mem::drop(ide); + // The presenter need to be dropped first, so all visible components should hide themselves + // and be pushed to the garbage collector before we clear it. + mem::drop(ide.presenter); + //TODO[ao] As widgets which are garbage-collected may (and ofter do) keep references to + // [`Application`] or [`World`], we need to force dropping them. This is not an ideal + // solution, but the garbage collector will be removed soon anyway - see + // https://github.com/enso-org/enso/issues/6850#issuecomment-1576754037 + ide.ensogl_app.display.force_garbage_drop(); + mem::drop(ide.ensogl_app) + }; EXECUTOR.with(RefCell::take); leak_detector::TRACKED_OBJECTS.with(|objects| { let objects = objects.borrow(); diff --git a/app/gui/src/presenter/graph/visualization.rs b/app/gui/src/presenter/graph/visualization.rs index 7eeef199b5..de530ecc06 100644 --- a/app/gui/src/presenter/graph/visualization.rs +++ b/app/gui/src/presenter/graph/visualization.rs @@ -12,7 +12,6 @@ use crate::presenter::graph::AstNodeId; use crate::presenter::graph::ViewNodeId; use enso_frp as frp; -use ensogl::application::View; use ide_view as view; use ide_view::graph_editor::component::node as node_view; use ide_view::graph_editor::component::visualization as visualization_view; @@ -181,7 +180,6 @@ impl Visualization { state, }); - let app = &view.app().frp; frp::extend! { network eval view.visualization_shown (((node, metadata)) model.visualization_shown(*node, metadata.clone())); eval view.visualization_hidden ((node) model.visualization_hidden(*node)); @@ -196,8 +194,7 @@ impl Visualization { view.set_visualization_data <+ set_data; view.set_error_visualization_data <+ error_update; - view.disable_visualization <+ visualization_failure._0(); - app.show_notification <+ visualization_failure._1(); + view.visualization_update_failed <+ visualization_failure; eval_ view.visualization_registry_reload_requested (model.load_visualizations()); } diff --git a/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs b/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs index 557fee8cbb..588bcc17a0 100644 --- a/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs +++ b/app/gui/view/component-browser/component-list-panel/breadcrumbs/src/lib.rs @@ -492,10 +492,6 @@ impl ensogl_core::application::View for Breadcrumbs { Self::new(app) } - fn app(&self) -> &Application { - self.widget.app() - } - fn default_shortcuts() -> Vec { use ensogl_core::application::shortcut::ActionType::*; [(Press, "shift enter", "move_up"), (Press, "ctrl shift enter", "move_down")] diff --git a/app/gui/view/component-browser/component-list-panel/src/lib.rs b/app/gui/view/component-browser/component-list-panel/src/lib.rs index b037b545f6..9cb7608f2e 100644 --- a/app/gui/view/component-browser/component-list-panel/src/lib.rs +++ b/app/gui/view/component-browser/component-list-panel/src/lib.rs @@ -246,7 +246,6 @@ pub struct Model { impl Model { fn new(app: &Application) -> Self { - let app = app.clone_ref(); let scene = &app.display.default_scene; let display_object = display::object::Instance::new(); @@ -256,7 +255,7 @@ impl Model { let grid = app.new_view::(); display_object.add_child(&grid); - let section_navigator = SectionNavigator::new(&app); + let section_navigator = SectionNavigator::new(app); display_object.add_child(§ion_navigator); let breadcrumbs = app.new_view::(); diff --git a/app/gui/view/graph-editor/src/component/breadcrumbs.rs b/app/gui/view/graph-editor/src/component/breadcrumbs.rs index cf825a7787..62bc42e66c 100644 --- a/app/gui/view/graph-editor/src/component/breadcrumbs.rs +++ b/app/gui/view/graph-editor/src/component/breadcrumbs.rs @@ -132,6 +132,7 @@ pub struct BreadcrumbsModel { /// A container for all the breadcrumbs after project name. This contained and all its /// breadcrumbs are moved when project name component is resized. breadcrumbs_container: display::object::Instance, + // Required for creating new breadcrumbs app: Application, breadcrumbs: Rc>>, frp_inputs: FrpInputs, diff --git a/app/gui/view/graph-editor/src/component/breadcrumbs/project_name.rs b/app/gui/view/graph-editor/src/component/breadcrumbs/project_name.rs index 8f2c4eff11..172dcce7b4 100644 --- a/app/gui/view/graph-editor/src/component/breadcrumbs/project_name.rs +++ b/app/gui/view/graph-editor/src/component/breadcrumbs/project_name.rs @@ -127,7 +127,6 @@ impl Animations { #[derive(Debug, Clone, CloneRef)] #[allow(missing_docs)] struct ProjectNameModel { - app: Application, display_object: display::object::Instance, view: background::View, style: StyleWatch, @@ -138,7 +137,6 @@ struct ProjectNameModel { impl ProjectNameModel { /// Constructor. fn new(app: &Application) -> Self { - let app = app.clone_ref(); let scene = &app.display.default_scene; let display_object = display::object::Instance::new(); // FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape @@ -160,7 +158,7 @@ impl ProjectNameModel { scene.layers.panel.add(&view); let project_name = default(); - Self { app, display_object, view, style, text_field, project_name }.init() + Self { display_object, view, style, text_field, project_name }.init() } /// Compute the width of the ProjectName view. @@ -423,12 +421,10 @@ impl View for ProjectName { fn label() -> &'static str { "ProjectName" } + fn new(app: &Application) -> Self { ProjectName::new(app) } - fn app(&self) -> &Application { - &self.model.app - } fn default_shortcuts() -> Vec { use shortcut::ActionType::*; diff --git a/app/gui/view/graph-editor/src/component/node.rs b/app/gui/view/graph-editor/src/component/node.rs index efbd73bfef..3edccd0021 100644 --- a/app/gui/view/graph-editor/src/component/node.rs +++ b/app/gui/view/graph-editor/src/component/node.rs @@ -402,6 +402,7 @@ impl Deref for Node { #[derive(Clone, CloneRef, Debug)] #[allow(missing_docs)] pub struct NodeModel { + // Required for switching the node to a different layer pub app: Application, pub display_object: display::object::Instance, pub background: Background, diff --git a/app/gui/view/graph-editor/src/component/node/input/area.rs b/app/gui/view/graph-editor/src/component/node/input/area.rs index 7a0c73de88..99baecc58b 100644 --- a/app/gui/view/graph-editor/src/component/node/input/area.rs +++ b/app/gui/view/graph-editor/src/component/node/input/area.rs @@ -133,7 +133,6 @@ impl From for Expression { /// Internal model of the port area. #[derive(Debug)] pub struct Model { - app: Application, display_object: display::object::Instance, edit_mode_label: text::Text, expression: RefCell, @@ -152,17 +151,16 @@ impl Model { /// Constructor. #[profile(Debug)] pub fn new(app: &Application) -> Self { - let app = app.clone_ref(); let display_object = display::object::Instance::new_named("input"); let edit_mode_label = app.new_view::(); let expression = default(); let styles = StyleWatch::new(&app.display.default_scene.style_sheet); let styles_frp = StyleWatchFrp::new(&app.display.default_scene.style_sheet); - let widget_tree = widget::Tree::new(&app); + let widget_tree = widget::Tree::new(app); with_context(|ctx| ctx.layers.widget.add(&widget_tree)); - Self { app, display_object, edit_mode_label, expression, styles, styles_frp, widget_tree } - .init() + Self { display_object, edit_mode_label, expression, styles, styles_frp, widget_tree } + .init(app) } /// React to edit mode change. Shows and hides appropriate child views according to current @@ -183,19 +181,24 @@ impl Model { } #[profile(Debug)] - fn init(self) -> Self { + fn init(self, app: &Application) -> Self { // TODO: Depth sorting of labels to in front of the mouse pointer. Temporary solution. // It needs to be more flexible once we have proper depth management. // See https://www.pivotaltracker.com/story/show/183567632. - let scene = &self.app.display.default_scene; + let scene = &app.display.default_scene; self.set_label_layer(&scene.layers.label); let text_color = self.styles.get_color(theme::graph_editor::node::text); self.edit_mode_label.set_single_line_mode(true); - self.edit_mode_label.disable_command("cursor_move_up"); - self.edit_mode_label.disable_command("cursor_move_down"); - self.edit_mode_label.disable_command("add_cursor_at_mouse_position"); + + app.commands.set_command_enabled(&self.edit_mode_label, "cursor_move_up", false); + app.commands.set_command_enabled(&self.edit_mode_label, "cursor_move_down", false); + app.commands.set_command_enabled( + &self.edit_mode_label, + "add_cursor_at_mouse_position", + false, + ); self.edit_mode_label.set_property_default(text_color); self.edit_mode_label.set_property_default(text::Size(TEXT_SIZE)); self.edit_mode_label.remove_all_cursors(); diff --git a/app/gui/view/graph-editor/src/component/node/input/widget/single_choice.rs b/app/gui/view/graph-editor/src/component/node/input/widget/single_choice.rs index 3659f90397..130d4dccef 100644 --- a/app/gui/view/graph-editor/src/component/node/input/widget/single_choice.rs +++ b/app/gui/view/graph-editor/src/component/node/input/widget/single_choice.rs @@ -400,6 +400,7 @@ fn entry_for_current_value( /// is minimal, as the actual dropdown view is not created. #[derive(Debug)] struct LazyDropdown { + // Required for lazy initialization app: ensogl::application::Application, set_all_entries: frp::Any>, set_selected_entries: frp::Any>, diff --git a/app/gui/view/graph-editor/src/component/node/output/area.rs b/app/gui/view/graph-editor/src/component/node/output/area.rs index 1581a91c98..3b49a1fcf0 100644 --- a/app/gui/view/graph-editor/src/component/node/output/area.rs +++ b/app/gui/view/graph-editor/src/component/node/output/area.rs @@ -156,7 +156,6 @@ impl Model { /// Constructor. #[profile(Debug)] pub fn new(app: &Application, frp: &Frp) -> Self { - let app = app.clone_ref(); let display_object = display::object::Instance::new_named("output"); let ports = display::object::Instance::new(); let port_models = default(); @@ -169,7 +168,7 @@ impl Model { display_object.add_child(&label); display_object.add_child(&ports); Self { - app, + app: app.clone_ref(), display_object, ports, port_models, @@ -180,21 +179,21 @@ impl Model { styles_frp, frp, } - .init() + .init(app) } #[profile(Debug)] - fn init(self) -> Self { + fn init(self, app: &Application) -> Self { // FIXME[WD]: Depth sorting of labels to in front of the mouse pointer. Temporary solution. // It needs to be more flexible once we have proper depth management. - let scene = &self.app.display.default_scene; + let scene = &app.display.default_scene; scene.layers.main.remove(&self.label); self.label.add_to_scene_layer(&scene.layers.label); let text_color = self.styles.get_color(theme::graph_editor::node::text); self.label.set_single_line_mode(true); - self.label.disable_command("cursor_move_up"); - self.label.disable_command("cursor_move_down"); + app.commands.set_command_enabled(&self.label, "cursor_move_up", false); + app.commands.set_command_enabled(&self.label, "cursor_move_up", false); self.label.set_property_default(text_color); self.label.set_property_default(text::Size(input::area::TEXT_SIZE)); self.label.remove_all_cursors(); diff --git a/app/gui/view/graph-editor/src/lib.rs b/app/gui/view/graph-editor/src/lib.rs index 8841fd79cb..ebcff8b5ad 100644 --- a/app/gui/view/graph-editor/src/lib.rs +++ b/app/gui/view/graph-editor/src/lib.rs @@ -658,6 +658,8 @@ ensogl::define_endpoints_2! { set_error_visualization_data ((NodeId, visualization::Data)), enable_visualization (NodeId), disable_visualization (NodeId), + /// Inform Graph Editor that attaching or updating visualization has resulted in error. + visualization_update_failed ((NodeId, String)), /// Remove from visualization registry all non-default visualizations. reset_visualization_registry (), @@ -760,6 +762,7 @@ ensogl::define_endpoints_2! { is_fs_visualization_displayed (bool), visualization_preprocessor_changed ((NodeId,PreprocessorConfiguration)), visualization_registry_reload_requested (), + visualization_update_error ((NodeId, String)), widgets_requested (NodeId, ast::Id, ast::Id), request_import (ImString), @@ -1802,6 +1805,7 @@ impl GraphEditorModelWithNetwork { #[allow(missing_docs)] // FIXME[everyone] Public-facing API should be documented. pub struct GraphEditorModel { pub display_object: display::object::Instance, + // Required for dynamically creating nodes and edges. pub app: Application, pub breadcrumbs: component::Breadcrumbs, pub cursor: cursor::Cursor, @@ -2713,10 +2717,6 @@ impl application::View for GraphEditor { new_graph_editor(app) } - fn app(&self) -> &Application { - &self.model.app - } - fn default_shortcuts() -> Vec { use crate::shortcuts::SHORTCUTS; SHORTCUTS.iter().map(|(a, b, c, d)| Self::self_shortcut_when(*a, *c, *d, *b)).collect() @@ -3520,7 +3520,8 @@ fn new_graph_editor(app: &Application) -> GraphEditor { viz_enable_by_press <= viz_tgt_nodes.gate_not(&viz_tgt_nodes_all_on); viz_enable <- any(viz_enable_by_press,inputs.enable_visualization); viz_disable_by_press <= viz_tgt_nodes.gate(&viz_tgt_nodes_all_on); - viz_disable <- any(viz_disable_by_press,inputs.disable_visualization); + viz_update_failed <- inputs.visualization_update_failed._0(); + viz_disable <- any(viz_disable_by_press, inputs.disable_visualization, viz_update_failed); viz_preview_disable <= viz_tgt_nodes_off.sample(&viz_preview_mode_end); viz_fullscreen_on <= viz_open_fs_ev.map(f_!(model.nodes.last_selected())); @@ -3544,6 +3545,8 @@ fn new_graph_editor(app: &Application) -> GraphEditor { out.is_fs_visualization_displayed <+ out.visualization_fullscreen.map(Option::is_some); + out.visualization_update_error <+ inputs.visualization_update_failed; + // === Register Visualization === diff --git a/app/gui/view/src/code_editor.rs b/app/gui/view/src/code_editor.rs index 88083ffd01..96b5877268 100644 --- a/app/gui/view/src/code_editor.rs +++ b/app/gui/view/src/code_editor.rs @@ -155,10 +155,6 @@ impl application::View for View { Self::new(app) } - fn app(&self) -> &Application { - self.model.app() - } - fn default_shortcuts() -> Vec { use shortcut::ActionType::*; [(Press, "ctrl `", "toggle"), (Press, "escape", "hide")] diff --git a/app/gui/view/src/project.rs b/app/gui/view/src/project.rs index 70ff56b1ff..cb80d2497e 100644 --- a/app/gui/view/src/project.rs +++ b/app/gui/view/src/project.rs @@ -143,7 +143,6 @@ ensogl::define_endpoints! { #[derive(Clone, CloneRef, Debug)] struct Model { - app: Application, display_object: display::object::Instance, project_view_top_bar: ProjectViewTopBar, graph_editor: Rc, @@ -175,10 +174,8 @@ impl Model { display_object.add_child(&project_view_top_bar); display_object.remove_child(&searcher); - let app = app.clone_ref(); let graph_editor = Rc::new(graph_editor); Self { - app, display_object, project_view_top_bar, graph_editor, @@ -411,6 +408,7 @@ impl View { graph.set_navigator_disabled <+ disable_navigation; model.popup.set_label <+ graph.model.breadcrumbs.project_name_error; + model.popup.set_label <+ graph.visualization_update_error._1(); graph.set_read_only <+ frp.set_read_only; graph.set_debug_mode <+ frp.source.debug_mode; @@ -722,10 +720,6 @@ impl application::View for View { View::new(app) } - fn app(&self) -> &Application { - &self.model.app - } - fn default_shortcuts() -> Vec { use shortcut::ActionType::*; [ diff --git a/app/gui/view/src/project/project_view_top_bar/window_control_buttons.rs b/app/gui/view/src/project/project_view_top_bar/window_control_buttons.rs index a2ce8b6cfd..0b40d7763f 100644 --- a/app/gui/view/src/project/project_view_top_bar/window_control_buttons.rs +++ b/app/gui/view/src/project/project_view_top_bar/window_control_buttons.rs @@ -44,7 +44,6 @@ mod shape { /// An internal model of Status Bar component #[derive(Clone, CloneRef, Debug)] pub struct Model { - app: Application, display_object: display::object::Instance, shape: shape::View, close: close::View, @@ -54,7 +53,6 @@ pub struct Model { impl Model { /// Constructor. pub fn new(app: &Application) -> Self { - let app = app.clone_ref(); let display_object = display::object::Instance::new_named("WindowControlButtons"); ensogl::shapes_order_dependencies! { @@ -63,10 +61,10 @@ impl Model { shape -> fullscreen::shape; } }; - let close = close::View::new(&app); + let close = close::View::new(app); display_object.add_child(&close); - let fullscreen = fullscreen::View::new(&app); + let fullscreen = fullscreen::View::new(app); display_object.add_child(&fullscreen); let shape = shape::View::new(); @@ -74,7 +72,7 @@ impl Model { app.display.default_scene.layers.panel.add(&display_object); - Self { app, display_object, shape, close, fullscreen } + Self { display_object, shape, close, fullscreen } } /// Updates positions of the buttons and sizes of the mouse area. @@ -190,10 +188,8 @@ impl application::View for View { fn label() -> &'static str { "TopButtons" } + fn new(app: &Application) -> Self { View::new(app) } - fn app(&self) -> &Application { - &self.model.app - } } diff --git a/app/gui/view/src/root.rs b/app/gui/view/src/root.rs index 5919ab3a1e..d7fdfcb1f5 100644 --- a/app/gui/view/src/root.rs +++ b/app/gui/view/src/root.rs @@ -33,13 +33,14 @@ enum State { /// visibility. #[derive(Clone, CloneRef, Debug)] pub struct Model { + // Required for creating project view dynamically app: Application, display_object: display::object::Instance, state: Rc>, status_bar: crate::status_bar::View, welcome_view: crate::welcome_screen::View, project_view: Rc>>, - frp: Frp, + frp_outputs: FrpOutputsSource, } impl Model { @@ -53,9 +54,9 @@ impl Model { let welcome_view = app.new_view::(); let project_view = Rc::new(CloneCell::new(None)); display_object.add_child(&welcome_view); - let frp = frp.clone_ref(); + let frp_outputs = frp.output.source.clone_ref(); - Self { app, display_object, state, status_bar, welcome_view, project_view, frp } + Self { app, display_object, state, status_bar, welcome_view, project_view, frp_outputs } } /// Switch displayed view from Project View to Welcome Screen. Project View will not be @@ -84,18 +85,18 @@ impl Model { fn init_project_view(&self) { if self.project_view.get().is_none() { - let network = &self.frp.network; let view = self.app.new_view::(); + let network = &view.network; let project_list_frp = &view.project_list().frp; let status_bar = &self.status_bar; let display_object = &self.display_object; - frp::new_bridge_network! { [network, view.network] project_bridge + frp::extend! { network fs_vis_shown <- view.fullscreen_visualization_shown.on_true(); fs_vis_hidden <- view.fullscreen_visualization_shown.on_false(); eval fs_vis_shown ((_) status_bar.unset_parent()); eval fs_vis_hidden ([display_object, status_bar](_) display_object.add_child(&status_bar)); - self.frp.source.selected_project <+ project_list_frp.selected_project; + self.frp_outputs.selected_project <+ project_list_frp.selected_project; } self.project_view.set(Some(view)); } @@ -203,8 +204,4 @@ impl application::View for View { fn new(app: &Application) -> Self { Self::new(app) } - - fn app(&self) -> &Application { - &self.model.app - } } diff --git a/app/gui/view/src/searcher.rs b/app/gui/view/src/searcher.rs index f927a9ca60..cb63a06886 100644 --- a/app/gui/view/src/searcher.rs +++ b/app/gui/view/src/searcher.rs @@ -107,7 +107,6 @@ pub type Entry = list_view::entry::GlyphHighlightedLabel; #[derive(Clone, CloneRef, Debug)] struct Model { - app: Application, display_object: display::object::Instance, list: ListView, documentation: documentation::View, @@ -117,11 +116,10 @@ struct Model { impl Model { fn new(app: &Application) -> Self { let scene = &app.display.default_scene; - let app = app.clone_ref(); let display_object = display::object::Instance::new(); let list = app.new_view::>(); list.deprecated_focus(); - let documentation = documentation::View::new(&app); + let documentation = documentation::View::new(app); let doc_provider = default(); scene.layers.node_searcher.add(&list); display_object.add_child(&documentation); @@ -137,7 +135,7 @@ impl Model { list.set_x(ACTION_LIST_X); documentation.set_x(DOCUMENTATION_X); documentation.set_y(-action_list_gap); - Self { app, display_object, list, documentation, doc_provider } + Self { display_object, list, documentation, doc_provider } } fn set_height(&self, h: f32) { @@ -287,12 +285,11 @@ impl application::View for View { fn label() -> &'static str { "Searcher" } + fn new(app: &Application) -> Self { Self::new(app) } - fn app(&self) -> &Application { - &self.model.app - } + fn default_shortcuts() -> Vec { use shortcut::ActionType::*; [(Press, "tab", "use_as_suggestion")] diff --git a/app/gui/view/welcome-screen/src/lib.rs b/app/gui/view/welcome-screen/src/lib.rs index 29f8da0b93..f7d65c7ec2 100644 --- a/app/gui/view/welcome-screen/src/lib.rs +++ b/app/gui/view/welcome-screen/src/lib.rs @@ -116,7 +116,6 @@ static STYLESHEET: &str = include_str!("../style.css"); /// Model of Welcome Screen that generates HTML DOM elements. #[derive(Clone, CloneRef, Debug)] pub struct Model { - application: Application, dom: DomSymbol, display_object: display::object::Instance, side_menu: SideMenu, @@ -126,7 +125,6 @@ pub struct Model { impl Model { /// Constructor. `frp` is used to set up event handlers on buttons. pub fn new(app: &Application) -> Self { - let application = app.clone_ref(); let display_object = display::object::Instance::new(); let side_menu = SideMenu::new(); @@ -141,7 +139,7 @@ impl Model { style.set_inner_html(STYLESHEET); dom.append_or_warn(&style); - Self { application, dom, display_object, side_menu, template_cards } + Self { dom, display_object, side_menu, template_cards } } fn create_dom(side_menu: &SideMenu, template_cards: &TemplateCards) -> DomSymbol { @@ -258,8 +256,4 @@ impl application::View for View { fn new(app: &Application) -> Self { Self::new(app) } - - fn app(&self) -> &Application { - &self.model.application - } } diff --git a/lib/rust/ensogl/component/button/src/lib.rs b/lib/rust/ensogl/component/button/src/lib.rs index 64d486a028..47a0b3eec8 100644 --- a/lib/rust/ensogl/component/button/src/lib.rs +++ b/lib/rust/ensogl/component/button/src/lib.rs @@ -203,19 +203,17 @@ pub mod shape { #[derivative(Clone(bound = ""))] #[allow(missing_docs)] pub struct Model { - app: Application, display_object: display::object::Instance, shape: ShapeView, } impl Model { /// Construct a button's model. - pub fn new(app: &Application) -> Self { - let app = app.clone_ref(); + pub fn new(_app: &Application) -> Self { let display_object = display::object::Instance::new(); let shape = ShapeView::new(); display_object.add_child(&shape); - Self { app, display_object, shape } + Self { display_object, shape } } /// Set the background (i.e. the circle) color. diff --git a/lib/rust/ensogl/component/flame-graph/src/block.rs b/lib/rust/ensogl/component/flame-graph/src/block.rs index 3b93f11645..1a82b4b413 100644 --- a/lib/rust/ensogl/component/flame-graph/src/block.rs +++ b/lib/rust/ensogl/component/flame-graph/src/block.rs @@ -95,7 +95,6 @@ impl component::Frp for Frp { #[derive(Clone, CloneRef, Debug)] pub struct Model { - app: Application, background: background::View, label: Rc>>, display_object: display::object::Instance, @@ -115,8 +114,7 @@ impl component::Model for Model { display_object.add_child(&background); scene.layers.tooltip.add(&background); - let app = app.clone_ref(); - Model { app, background, label, display_object } + Model { background, label, display_object } } } diff --git a/lib/rust/ensogl/component/flame-graph/src/lib.rs b/lib/rust/ensogl/component/flame-graph/src/lib.rs index 8192aa752e..82c5e96224 100644 --- a/lib/rust/ensogl/component/flame-graph/src/lib.rs +++ b/lib/rust/ensogl/component/flame-graph/src/lib.rs @@ -114,6 +114,7 @@ pub struct FlameGraph { blocks: Vec, marks: Vec, origin_x: f64, + // Required for dynamically adding blocks. app: Application, } diff --git a/lib/rust/ensogl/component/flame-graph/src/mark.rs b/lib/rust/ensogl/component/flame-graph/src/mark.rs index c058b3dd36..9d16068b18 100644 --- a/lib/rust/ensogl/component/flame-graph/src/mark.rs +++ b/lib/rust/ensogl/component/flame-graph/src/mark.rs @@ -98,7 +98,6 @@ impl component::Frp for Frp { #[derive(Clone, CloneRef, Debug)] pub struct Model { - app: Application, background: background::View, label: Rc>>, display_object: display::object::Instance, @@ -118,8 +117,7 @@ impl component::Model for Model { display_object.add_child(&background); scene.layers.tooltip.add(&background); - let app = app.clone_ref(); - Model { app, background, label, display_object } + Model { background, label, display_object } } } diff --git a/lib/rust/ensogl/component/grid-view/src/entry/visible.rs b/lib/rust/ensogl/component/grid-view/src/entry/visible.rs index 49bd54ec3b..09127fb682 100644 --- a/lib/rust/ensogl/component/grid-view/src/entry/visible.rs +++ b/lib/rust/ensogl/component/grid-view/src/entry/visible.rs @@ -59,6 +59,7 @@ impl display::Object for VisibleEntry { #[derive(CloneRef, Debug, Derivative)] #[derivative(Clone(bound = ""))] pub struct CreationCtx { + // Required for dynamically creating entries. pub app: Application, pub network: frp::WeakNetwork, pub set_entry_size: frp::Stream, diff --git a/lib/rust/ensogl/component/grid-view/src/lib.rs b/lib/rust/ensogl/component/grid-view/src/lib.rs index 822d11ccb6..24758e14ee 100644 --- a/lib/rust/ensogl/component/grid-view/src/lib.rs +++ b/lib/rust/ensogl/component/grid-view/src/lib.rs @@ -688,10 +688,6 @@ impl application::View for GridView { GridView::::new(app) } - fn app(&self) -> &Application { - self.widget.app() - } - fn default_shortcuts() -> Vec { use application::shortcut::ActionType::*; [ diff --git a/lib/rust/ensogl/component/gui/src/component.rs b/lib/rust/ensogl/component/gui/src/component.rs index c4f8f49aaf..a5aa7ffe7f 100644 --- a/lib/rust/ensogl/component/gui/src/component.rs +++ b/lib/rust/ensogl/component/gui/src/component.rs @@ -144,10 +144,6 @@ where ComponentView::new(app) } - fn app(&self) -> &Application { - self.widget.app() - } - fn default_shortcuts() -> Vec { F::default_shortcuts() } diff --git a/lib/rust/ensogl/component/label/src/lib.rs b/lib/rust/ensogl/component/label/src/lib.rs index b0d475dce2..85a45cf4f7 100644 --- a/lib/rust/ensogl/component/label/src/lib.rs +++ b/lib/rust/ensogl/component/label/src/lib.rs @@ -59,8 +59,7 @@ struct Model { } impl Model { - fn new(app: Application) -> Self { - let app = app.clone_ref(); + fn new(app: &Application) -> Self { let scene = &app.display.default_scene; let display_object = display::object::Instance::new(); let label = app.new_view::(); @@ -144,7 +143,7 @@ impl Label { /// Constructor. pub fn new(app: &Application) -> Self { let frp = Rc::new(Frp::new()); - let model = Rc::new(Model::new(app.clone_ref())); + let model = Rc::new(Model::new(app)); Label { model, frp }.init() } diff --git a/lib/rust/ensogl/component/list-view/src/entry/list.rs b/lib/rust/ensogl/component/list-view/src/entry/list.rs index 4cf47d7a84..59a288a195 100644 --- a/lib/rust/ensogl/component/list-view/src/entry/list.rs +++ b/lib/rust/ensogl/component/list-view/src/entry/list.rs @@ -66,6 +66,7 @@ pub type List = ListData::Params>; #[derivative(Clone(bound = ""))] #[clone_ref(bound = "E:CloneRef")] pub struct ListData { + // Required for dynamically creating new entries. app: Application, display_object: display::object::Instance, entries: Rc>>>, diff --git a/lib/rust/ensogl/component/list-view/src/lib.rs b/lib/rust/ensogl/component/list-view/src/lib.rs index 823d7fbd33..43de0c0456 100644 --- a/lib/rust/ensogl/component/list-view/src/lib.rs +++ b/lib/rust/ensogl/component/list-view/src/lib.rs @@ -124,7 +124,6 @@ impl Default for JumpTarget { /// The Model of Select Component. #[derive(Clone, CloneRef, Debug)] struct Model { - app: Application, entries: entry::List, selection: Selection, background: Rectangle, @@ -134,10 +133,9 @@ struct Model { impl Model { fn new(app: &Application) -> Self { - let app = app.clone_ref(); let display_object = display::object::Instance::new(); let scrolled_area = display::object::Instance::new(); - let entries = entry::List::new(&app); + let entries = entry::List::new(app); let background = Rectangle(); background.set_border_color(color::Rgba::transparent()); let selection = Selection::default(); @@ -146,7 +144,7 @@ impl Model { display_object.add_child(&scrolled_area); scrolled_area.add_child(&entries); scrolled_area.add_child(&selection); - Model { app, entries, selection, background, scrolled_area, display_object } + Model { entries, selection, background, scrolled_area, display_object } } /// Update the displayed entries list when _view_ has changed - the list was scrolled or @@ -438,7 +436,7 @@ where E::Model: Default // === Selected Entry === - eval frp.source.focused([frp](f) if !f { frp.deselect_entries.emit(()) } ); + frp.deselect_entries <+ frp.focused.on_false(); frp.source.selected_entry <+ frp.select_entry; frp.source.selected_entry <+ frp.output.chosen_entry; @@ -636,12 +634,11 @@ impl application::View for ListView { fn label() -> &'static str { "ListView" } + fn new(app: &Application) -> Self { ListView::new(app) } - fn app(&self) -> &Application { - &self.model.app - } + fn default_shortcuts() -> Vec { use shortcut::ActionType::*; [ diff --git a/lib/rust/ensogl/component/scroll-area/src/lib.rs b/lib/rust/ensogl/component/scroll-area/src/lib.rs index 53c2481298..00d58c829d 100644 --- a/lib/rust/ensogl/component/scroll-area/src/lib.rs +++ b/lib/rust/ensogl/component/scroll-area/src/lib.rs @@ -367,18 +367,14 @@ impl ScrollArea { (0.0..=size.x).contains(&local_pos.x) && (-size.y..=0.0).contains(&local_pos.y) })); hovering <- hovering.sampler(); + let on_scroll = model.display_object.on_event::(); + on_scroll_when_hovering <- on_scroll.gate(&hovering); + model.h_scrollbar.scroll_by <+ on_scroll_when_hovering + .map(|event| event.delta_x() as f32); + model.v_scrollbar.scroll_by <+ on_scroll_when_hovering + .map(|event| event.delta_y() as f32); } - let mouse_manager = &mouse.mouse_manager; - let scroll_handler = f!([model](event: &mouse::Wheel) - if hovering.value() { - model.h_scrollbar.scroll_by(event.delta_x() as f32); - model.v_scrollbar.scroll_by(event.delta_y() as f32); - } - ); - let scroll_handler_handle = mouse_manager.on_wheel.add(scroll_handler); - network.store(&scroll_handler_handle); - ScrollArea { model, frp } } diff --git a/lib/rust/ensogl/component/scrollbar/src/lib.rs b/lib/rust/ensogl/component/scrollbar/src/lib.rs index 91794a9b43..94670ac881 100644 --- a/lib/rust/ensogl/component/scrollbar/src/lib.rs +++ b/lib/rust/ensogl/component/scrollbar/src/lib.rs @@ -115,7 +115,7 @@ impl Frp { resize <- frp.set_length.map(|&length| Vector2::new(length,WIDTH)); } - let base_frp = selector::Frp::new(model, style, network, resize.clone(), mouse); + let base_frp = selector::Frp::new(app, model, style, network, resize.clone(), mouse); model.use_track_handles(false); model.set_track_corner_round(true); @@ -358,22 +358,17 @@ pub struct Scrollbar { /// Public FRP api of the Component. pub frp: Rc, model: Rc, - /// Reference to the application the Component belongs to. Generally required for implementing - /// `application::View` and initialising the `Model` and `Frp` and thus provided by the - /// `Component`. - pub app: Application, } impl Scrollbar { /// Constructor. pub fn new(app: &Application) -> Self { - let app = app.clone_ref(); - let model = Rc::new(Model::new(&app)); + let model = Rc::new(Model::new(app)); let frp = Frp::default(); let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet); - frp.init(&app, &model, &style); + frp.init(app, &model, &style); let frp = Rc::new(frp); - Self { frp, model, app } + Self { frp, model } } } @@ -400,10 +395,8 @@ impl application::View for Scrollbar { fn label() -> &'static str { "Scrollbar" } + fn new(app: &Application) -> Self { Scrollbar::new(app) } - fn app(&self) -> &Application { - &self.app - } } diff --git a/lib/rust/ensogl/component/selector/src/decimal_aligned.rs b/lib/rust/ensogl/component/selector/src/decimal_aligned.rs index 15dd950863..d9f02d31cd 100644 --- a/lib/rust/ensogl/component/selector/src/decimal_aligned.rs +++ b/lib/rust/ensogl/component/selector/src/decimal_aligned.rs @@ -100,18 +100,16 @@ impl display::Object for Model { pub struct FloatLabel { pub frp: Rc, model: Rc, - app: Application, } impl FloatLabel { /// Constructor. pub fn new(app: &Application) -> Self { - let app = app.clone_ref(); - let model = Rc::new(Model::new(&app)); + let model = Rc::new(Model::new(app)); let frp = Frp::default(); frp.init(&model); let frp = Rc::new(frp); - Self { frp, model, app } + Self { frp, model } } } diff --git a/lib/rust/ensogl/component/selector/src/frp.rs b/lib/rust/ensogl/component/selector/src/frp.rs index 2917aa198a..eca18df4e4 100644 --- a/lib/rust/ensogl/component/selector/src/frp.rs +++ b/lib/rust/ensogl/component/selector/src/frp.rs @@ -9,6 +9,7 @@ use crate::shape::shape_is_dragged; use enso_frp as frp; use enso_frp::io::Mouse_DEPRECATED; use enso_frp::Network; +use ensogl_core::application::Application; use ensogl_core::display::object::ObjectOps; use ensogl_core::display::shape::StyleWatchFrp; use ensogl_hardcoded_theme as theme; @@ -69,6 +70,7 @@ pub struct Frp { impl Frp { /// Create and initialize the FRP. pub fn new( + app: &Application, model: &Model, style: &StyleWatchFrp, network: &Network, @@ -76,7 +78,7 @@ impl Frp { mouse: &Mouse_DEPRECATED, ) -> Frp { let net = &network; - let scene = &model.app.display.default_scene; + let scene = &app.display.default_scene; let shadow = shadow::frp_from_style(style, theme::shadow); let text_size = style.get_number(theme::text::size); diff --git a/lib/rust/ensogl/component/selector/src/lib.rs b/lib/rust/ensogl/component/selector/src/lib.rs index d128f10c40..11de58d0f6 100644 --- a/lib/rust/ensogl/component/selector/src/lib.rs +++ b/lib/rust/ensogl/component/selector/src/lib.rs @@ -77,22 +77,17 @@ pub struct NumberPicker { /// Public FRP api of the Component. pub frp: Rc, model: Rc, - /// Reference to the application the Component belongs to. Generally required for implementing - /// `application::View` and initialising the `Model` and `Frp` and thus provided by the - /// `Component`. - pub app: Application, } impl NumberPicker { /// Constructor. pub fn new(app: &Application) -> Self { - let app = app.clone_ref(); - let model = Rc::new(Model::new(&app)); + let model = Rc::new(Model::new(app)); let frp = number::Frp::default(); let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet); - frp.init(&app, &model, &style); + frp.init(app, &model, &style); let frp = Rc::new(frp); - Self { frp, model, app } + Self { frp, model } } } @@ -119,12 +114,10 @@ impl application::View for NumberPicker { fn label() -> &'static str { "NumberPicker" } + fn new(app: &Application) -> Self { NumberPicker::new(app) } - fn app(&self) -> &Application { - &self.app - } } @@ -147,22 +140,17 @@ pub struct NumberRangePicker { /// Public FRP api of the Component. pub frp: Rc, model: Rc, - /// Reference to the application the Component belongs to. Generally required for implementing - /// `application::View` and initialising the `Model` and `Frp` and thus provided by the - /// `Component`. - pub app: Application, } impl NumberRangePicker { /// Constructor. pub fn new(app: &Application) -> Self { - let app = app.clone_ref(); - let model = Rc::new(Model::new(&app)); + let model = Rc::new(Model::new(app)); let frp = range::Frp::default(); let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet); - frp.init(&app, &model, &style); + frp.init(app, &model, &style); let frp = Rc::new(frp); - Self { frp, model, app } + Self { frp, model } } } @@ -189,10 +177,8 @@ impl application::View for NumberRangePicker { fn label() -> &'static str { "RangePicker" } + fn new(app: &Application) -> Self { NumberRangePicker::new(app) } - fn app(&self) -> &Application { - &self.app - } } diff --git a/lib/rust/ensogl/component/selector/src/model.rs b/lib/rust/ensogl/component/selector/src/model.rs index afbb6d39ee..fd7f0c7410 100644 --- a/lib/rust/ensogl/component/selector/src/model.rs +++ b/lib/rust/ensogl/component/selector/src/model.rs @@ -70,8 +70,6 @@ pub struct Model { background_left_corner_roundness: Rc>, background_right_corner_roundness: Rc>, padding: Rc>, - - pub app: Application, } #[allow(missing_docs)] @@ -95,7 +93,6 @@ impl Model { let background_right_corner_roundness = default(); let padding = default(); - let app = app.clone_ref(); let scene = &app.display.default_scene; root.add_child(&label); @@ -134,7 +131,6 @@ impl Model { background_left_corner_roundness, background_right_corner_roundness, padding, - app, } } diff --git a/lib/rust/ensogl/component/selector/src/number.rs b/lib/rust/ensogl/component/selector/src/number.rs index d359bc9198..c942df3217 100644 --- a/lib/rust/ensogl/component/selector/src/number.rs +++ b/lib/rust/ensogl/component/selector/src/number.rs @@ -49,7 +49,8 @@ impl Frp { model.show_background(true); - let base_frp = super::Frp::new(model, style, network, frp.resize.clone().into(), mouse); + let base_frp = + super::Frp::new(app, model, style, network, frp.resize.clone().into(), mouse); let background_click = relative_shape_down_position(network, scene, &model.background); let track_click = relative_shape_down_position(network, scene, &model.track); diff --git a/lib/rust/ensogl/component/selector/src/range.rs b/lib/rust/ensogl/component/selector/src/range.rs index f24d04c57a..25dbf7e488 100644 --- a/lib/rust/ensogl/component/selector/src/range.rs +++ b/lib/rust/ensogl/component/selector/src/range.rs @@ -44,7 +44,8 @@ impl Frp { let scene = &app.display.default_scene; let mouse = &scene.mouse.frp_deprecated; - let base_frp = super::Frp::new(model, style, network, frp.resize.clone().into(), mouse); + let base_frp = + super::Frp::new(app, model, style, network, frp.resize.clone().into(), mouse); model.use_track_handles(true); model.show_background(true); diff --git a/lib/rust/ensogl/component/sequence-diagram/src/lib.rs b/lib/rust/ensogl/component/sequence-diagram/src/lib.rs index 653a2fbf88..b5023b38f1 100644 --- a/lib/rust/ensogl/component/sequence-diagram/src/lib.rs +++ b/lib/rust/ensogl/component/sequence-diagram/src/lib.rs @@ -89,6 +89,7 @@ impl component::Frp for Frp { /// Internal model of the SequenceDiagram. #[derive(Clone, CloneRef, Debug)] pub struct Model { + // Required for dynamically creating new lines. app: Application, display_object: display::object::Instance, actor_lines: Rc>>, diff --git a/lib/rust/ensogl/component/slider/src/lib.rs b/lib/rust/ensogl/component/slider/src/lib.rs index 731d9868c8..1938652082 100644 --- a/lib/rust/ensogl/component/slider/src/lib.rs +++ b/lib/rust/ensogl/component/slider/src/lib.rs @@ -337,10 +337,6 @@ pub struct Slider { #[deref] pub frp: Frp, model: Rc, - /// Reference to the application the component belongs to. Generally required for implementing - /// `application::View` and initialising the `Model` and `Frp` and thus provided by the - /// component. - pub app: Application, } impl Slider { @@ -348,12 +344,11 @@ impl Slider { pub fn new(app: &Application) -> Self { let frp = Frp::new(); let model = Rc::new(Model::new(app, frp.network())); - let app = app.clone_ref(); - Self { frp, model, app }.init() + Self { frp, model }.init(app) } - fn init(self) -> Self { - self.init_value_update(); + fn init(self, app: &Application) -> Self { + self.init_value_update(app); self.init_limit_handling(); self.init_value_display(); @@ -367,13 +362,13 @@ impl Slider { } /// Initialize the slider value update FRP network. - fn init_value_update(&self) { + fn init_value_update(&self, app: &Application) { let network = self.frp.network(); let frp = &self.frp; let input = &self.frp.input; let output = &self.frp.private.output; let model = &self.model; - let scene = &self.app.display.default_scene; + let scene = &app.display.default_scene; let mouse = &scene.mouse.frp_deprecated; let keyboard = &scene.keyboard.frp; @@ -845,10 +840,6 @@ impl application::View for Slider { Self::new(app) } - fn app(&self) -> &Application { - &self.app - } - fn default_shortcuts() -> Vec { use shortcut::ActionType::DoublePress; use shortcut::ActionType::Press; diff --git a/lib/rust/ensogl/component/text/src/component/text.rs b/lib/rust/ensogl/component/text/src/component/text.rs index 7b35a42304..b12f982682 100644 --- a/lib/rust/ensogl/component/text/src/component/text.rs +++ b/lib/rust/ensogl/component/text/src/component/text.rs @@ -1978,10 +1978,6 @@ impl application::View for Text { Text::new(app) } - fn app(&self) -> &Application { - &self.data.app - } - fn default_shortcuts() -> Vec { use shortcut::ActionType::*; ([ diff --git a/lib/rust/ensogl/core/src/application.rs b/lib/rust/ensogl/core/src/application.rs index a70860e2b7..725dc882f5 100644 --- a/lib/rust/ensogl/core/src/application.rs +++ b/lib/rust/ensogl/core/src/application.rs @@ -76,15 +76,6 @@ pub struct ApplicationData { pub frp: Frp, } -impl ApplicationData { - /// Show or hide the system mouse cursor by setting the `cursor` CSS property of the `body` - /// element. - fn show_system_cursor(&self, show: bool) { - let style = if show { "auto" } else { "none" }; - web::document.body_or_panic().set_style_or_warn("cursor", style); - } -} - impl Application { /// Constructor. pub fn new(dom: impl DomPath) -> Self { @@ -94,7 +85,7 @@ impl Application { let commands = command::Registry::create(); let shortcuts = shortcut::Registry::new(&scene.mouse.frp_deprecated, &scene.keyboard.frp, &commands); - let views = view::Registry::create(&display, &commands, &shortcuts); + let views = view::Registry::create(&commands, &shortcuts); let cursor = Cursor::new(&display.default_scene); display.add_child(&cursor); let frp = Frp::new(); @@ -106,20 +97,27 @@ impl Application { fn init(self) -> Self { let frp = &self.frp; - let data = &self.inner; let network = self.frp.network(); enso_frp::extend! { network app_focused <- self.display.default_scene.frp.focused.on_change(); - eval app_focused((t) data.show_system_cursor(!t)); + eval app_focused([](t) Self::show_system_cursor(!t)); + eval_ frp.private.input.show_system_cursor([] Self::show_system_cursor(true)); + eval_ frp.private.input.hide_system_cursor([] Self::show_system_cursor(false)); + frp.private.output.tooltip <+ frp.private.input.set_tooltip; - eval_ frp.private.input.show_system_cursor(data.show_system_cursor(true)); - eval_ frp.private.input.hide_system_cursor(data.show_system_cursor(false)); } // We hide the system cursor to replace it with the EnsoGL-provided one. self.frp.hide_system_cursor(); self } + /// Show or hide the system mouse cursor by setting the `cursor` CSS property of the `body` + /// element. + fn show_system_cursor(show: bool) { + let style = if show { "auto" } else { "none" }; + web::document.body_or_panic().set_style_or_warn("cursor", style); + } + /// Create a new instance of a view. pub fn new_view(&self) -> T { self.views.new_view(self) diff --git a/lib/rust/ensogl/core/src/application/command.rs b/lib/rust/ensogl/core/src/application/command.rs index 8065e2ae56..1ba943ec7c 100644 --- a/lib/rust/ensogl/core/src/application/command.rs +++ b/lib/rust/ensogl/core/src/application/command.rs @@ -27,9 +27,6 @@ pub trait View: FrpNetworkProvider + DerefToCommandApi { /// Constructor. fn new(app: &Application) -> Self; - /// Application reference. - fn app(&self) -> &Application; - /// Set of default shortcuts. fn default_shortcuts() -> Vec { default() @@ -58,24 +55,6 @@ pub trait View: FrpNetworkProvider + DerefToCommandApi { condition, ) } - - /// Disable the command in this component instance. - fn disable_command(&self, name: impl AsRef) - where Self: Sized { - self.set_command_enabled(name, false) - } - - /// Enable the command in this component instance. - fn enable_command(&self, name: impl AsRef) - where Self: Sized { - self.set_command_enabled(name, true) - } - - /// Set the command enable status in this component instance. - fn set_command_enabled(&self, name: impl AsRef, enabled: bool) - where Self: Sized { - self.app().commands.set_command_enabled(self, name, enabled) - } } /// FRP Network provider. Used to check whether FRP bindings are still alive. @@ -232,7 +211,7 @@ impl Registry { } /// Sets the command enable status for the provided component instance. - fn set_command_enabled(&self, instance: &T, name: impl AsRef, enabled: bool) { + pub fn set_command_enabled(&self, instance: &T, name: impl AsRef, enabled: bool) { self.with_command_mut(instance, name, |command| command.enabled = enabled) } } diff --git a/lib/rust/ensogl/core/src/application/view.rs b/lib/rust/ensogl/core/src/application/view.rs index 47b38ad821..cf69aee1fb 100644 --- a/lib/rust/ensogl/core/src/application/view.rs +++ b/lib/rust/ensogl/core/src/application/view.rs @@ -2,8 +2,6 @@ use crate::prelude::*; -use crate::display::world::World; - use super::command; use super::shortcut; use super::Application; @@ -26,7 +24,6 @@ pub use command::View; #[derive(Debug, Clone, CloneRef)] #[allow(missing_docs)] pub struct Registry { - pub display: World, pub command_registry: command::Registry, pub shortcut_registry: shortcut::Registry, pub definitions: Rc>>, @@ -35,15 +32,13 @@ pub struct Registry { impl Registry { /// Constructor. pub fn create( - display: &World, command_registry: &command::Registry, shortcut_registry: &shortcut::Registry, ) -> Self { - let display = display.clone_ref(); let command_registry = command_registry.clone_ref(); let shortcut_registry = shortcut_registry.clone_ref(); let definitions = default(); - Self { display, command_registry, shortcut_registry, definitions } + Self { command_registry, shortcut_registry, definitions } } /// View registration. diff --git a/lib/rust/ensogl/core/src/display/garbage.rs b/lib/rust/ensogl/core/src/display/garbage.rs index 9b8d790e95..a8b8ba2ea9 100644 --- a/lib/rust/ensogl/core/src/display/garbage.rs +++ b/lib/rust/ensogl/core/src/display/garbage.rs @@ -18,6 +18,14 @@ struct Garbage { before_mouse_events: Vec>, } +impl Garbage { + fn collected_items_count(&self) -> usize { + self.before_pixel_sync.len() + + self.before_pixel_update.len() + + self.before_mouse_events.len() + } +} + /// The Garbage Collector /// @@ -90,6 +98,14 @@ impl Collector { }; drop(before_mouse_events); } + + /// Immediately drop all collected garbage. + pub fn force_garbage_drop(&self) { + // Elements may add new objects on drop, thus we need to clear garbage in loop. + while self.garbage.borrow().collected_items_count() > 0 { + self.garbage.take(); + } + } } diff --git a/lib/rust/ensogl/core/src/display/world.rs b/lib/rust/ensogl/core/src/display/world.rs index cc9f33fa8a..67a7eb108c 100644 --- a/lib/rust/ensogl/core/src/display/world.rs +++ b/lib/rust/ensogl/core/src/display/world.rs @@ -670,6 +670,13 @@ impl WorldData { self.garbage_collector.collect(object); } + /// Immediately drop the garbage. + /// + /// May be used to resolve dependence cycles if garbage keeps reference to [`World`]. + pub fn force_garbage_drop(&self) { + self.garbage_collector.force_garbage_drop() + } + /// Set the maximum frequency at which the pointer location will be checked, in terms of number /// of frames per check. pub fn set_pixel_read_period(&self, period: usize) { diff --git a/lib/rust/ensogl/core/src/gui/component.rs b/lib/rust/ensogl/core/src/gui/component.rs index c9255b5ee8..158dd9db08 100644 --- a/lib/rust/ensogl/core/src/gui/component.rs +++ b/lib/rust/ensogl/core/src/gui/component.rs @@ -367,13 +367,6 @@ impl Widget { pub fn model(&self) -> &Model { &self.data.model } - - /// Reference to the application the Widget belongs to. It's required for handling model and - /// FRP garbage collection, but also may be helpful when, for example, implementing - /// `application::View`. - pub fn app(&self) -> &Application { - &self.data.app - } } impl display::Object for Widget { diff --git a/lib/rust/ensogl/examples/mouse-events/src/lib.rs b/lib/rust/ensogl/examples/mouse-events/src/lib.rs index fc8ccb02c3..57bbd21d40 100644 --- a/lib/rust/ensogl/examples/mouse-events/src/lib.rs +++ b/lib/rust/ensogl/examples/mouse-events/src/lib.rs @@ -44,15 +44,13 @@ use ensogl_text_msdf::run_once_initialized; #[derive(Clone, CloneRef, Debug)] struct Model { - app: Application, display_object: display::object::Instance, shape: Rectangle, cover: Rectangle, } impl Model { - fn new(app: &Application) -> Self { - let app = app.clone_ref(); + fn new() -> Self { let display_object = display::object::Instance::new(); let shape: Rectangle = default(); shape.set_size(Vector2(300.0, 300.0)); @@ -68,7 +66,7 @@ impl Model { cover.set_corner_radius_max(); cover.set_pointer_events(false); display_object.add_child(&cover); - Self { app, display_object, shape, cover } + Self { display_object, shape, cover } } } @@ -99,9 +97,9 @@ struct View { impl View { /// Constructor. - pub fn new(app: &Application) -> Self { + pub fn new() -> Self { let frp = Frp::new(); - let model = Model::new(app); + let model = Model::new(); let network = &frp.network; frp::extend! { network trace model.shape.events_deprecated.mouse_up; @@ -139,11 +137,9 @@ impl application::View for View { fn label() -> &'static str { "Circul" } - fn new(app: &Application) -> Self { - View::new(app) - } - fn app(&self) -> &Application { - &self.model.app + + fn new(_app: &Application) -> Self { + View::new() } } diff --git a/lib/rust/ensogl/examples/slider/src/lib.rs b/lib/rust/ensogl/examples/slider/src/lib.rs index cf01de185c..99b0bb48dd 100644 --- a/lib/rust/ensogl/examples/slider/src/lib.rs +++ b/lib/rust/ensogl/examples/slider/src/lib.rs @@ -232,16 +232,14 @@ impl FrpNetworkProvider for SliderCollection { struct SliderCollection { #[deref] frp: Frp, - app: Application, model: Model, } impl SliderCollection { fn new(app: &Application) -> Self { let frp = Frp::new(); - let app = app.clone_ref(); - let model = Model::new(&app); - Self { frp, app, model }.init() + let model = Model::new(app); + Self { frp, model }.init() } fn init(self) -> Self { @@ -272,10 +270,6 @@ impl View for SliderCollection { Self::new(app) } - fn app(&self) -> &Application { - &self.app - } - fn default_shortcuts() -> Vec { use shortcut::ActionType::Press; vec![ diff --git a/lib/rust/prelude/src/debug.rs b/lib/rust/prelude/src/debug.rs index 3e5af343bd..e748c09d96 100644 --- a/lib/rust/prelude/src/debug.rs +++ b/lib/rust/prelude/src/debug.rs @@ -146,9 +146,9 @@ impl Drop for TraceCopies { /// A module containing an utility for detecting leaks. /// /// If you suspect a particular struct is leaking, i.e. its instances are still present when we -/// expect them to be removed, you may add a [`Trace`] field to it. Then, at the point where we -/// expect all instances to be dropped, we may check the [`TRACKED_OBJECTS`] global variable, what -/// instances are still alive and their creation backtraces. +/// expect them to be removed, you may add a [`Trace`] field to it and call [`enable`]. Then, at +/// the point where we expect all instances to be dropped, we may check the [`TRACKED_OBJECTS`] +/// global variable, what instances are still alive and their creation backtraces. pub mod leak_detector { use crate::*;