No rendering after drop (#6911)

This commit is contained in:
Stijn ("stain") Seghers 2023-06-14 14:30:14 +02:00 committed by GitHub
parent 67821bf8df
commit e9e90fe152
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 160 additions and 258 deletions

View File

@ -81,7 +81,7 @@ impl Initializer {
match self.initialize_ide_controller_with_retries().await { match self.initialize_ide_controller_with_retries().await {
Ok(controller) => { Ok(controller) => {
let can_manage_projects = controller.can_manage_projects(); 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 can_manage_projects {
if let Some(project) = &self.config.project_to_open { if let Some(project) = &self.config.project_to_open {
ide.open_or_create_project(project.clone()); ide.open_or_create_project(project.clone());

View File

@ -203,12 +203,20 @@ pub fn main() {
#[wasm_bindgen] #[wasm_bindgen]
pub fn drop() { pub fn drop() {
let ide = IDE.with(RefCell::take); 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 //TODO[ao] #6420 We should not do this, but somehow the `dom` field in the scene is
// leaking. // leaking.
ide.ensogl_app.display.default_scene.dom.root.remove(); ide.ensogl_app.display.default_scene.dom.root.remove();
} // The presenter need to be dropped first, so all visible components should hide themselves
mem::drop(ide); // 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); EXECUTOR.with(RefCell::take);
leak_detector::TRACKED_OBJECTS.with(|objects| { leak_detector::TRACKED_OBJECTS.with(|objects| {
let objects = objects.borrow(); let objects = objects.borrow();

View File

@ -12,7 +12,6 @@ use crate::presenter::graph::AstNodeId;
use crate::presenter::graph::ViewNodeId; use crate::presenter::graph::ViewNodeId;
use enso_frp as frp; use enso_frp as frp;
use ensogl::application::View;
use ide_view as view; use ide_view as view;
use ide_view::graph_editor::component::node as node_view; use ide_view::graph_editor::component::node as node_view;
use ide_view::graph_editor::component::visualization as visualization_view; use ide_view::graph_editor::component::visualization as visualization_view;
@ -181,7 +180,6 @@ impl Visualization {
state, state,
}); });
let app = &view.app().frp;
frp::extend! { network frp::extend! { network
eval view.visualization_shown (((node, metadata)) model.visualization_shown(*node, metadata.clone())); eval view.visualization_shown (((node, metadata)) model.visualization_shown(*node, metadata.clone()));
eval view.visualization_hidden ((node) model.visualization_hidden(*node)); eval view.visualization_hidden ((node) model.visualization_hidden(*node));
@ -196,8 +194,7 @@ impl Visualization {
view.set_visualization_data <+ set_data; view.set_visualization_data <+ set_data;
view.set_error_visualization_data <+ error_update; view.set_error_visualization_data <+ error_update;
view.disable_visualization <+ visualization_failure._0(); view.visualization_update_failed <+ visualization_failure;
app.show_notification <+ visualization_failure._1();
eval_ view.visualization_registry_reload_requested (model.load_visualizations()); eval_ view.visualization_registry_reload_requested (model.load_visualizations());
} }

View File

@ -492,10 +492,6 @@ impl ensogl_core::application::View for Breadcrumbs {
Self::new(app) Self::new(app)
} }
fn app(&self) -> &Application {
self.widget.app()
}
fn default_shortcuts() -> Vec<Shortcut> { fn default_shortcuts() -> Vec<Shortcut> {
use ensogl_core::application::shortcut::ActionType::*; use ensogl_core::application::shortcut::ActionType::*;
[(Press, "shift enter", "move_up"), (Press, "ctrl shift enter", "move_down")] [(Press, "shift enter", "move_up"), (Press, "ctrl shift enter", "move_down")]

View File

@ -246,7 +246,6 @@ pub struct Model {
impl Model { impl Model {
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
let app = app.clone_ref();
let scene = &app.display.default_scene; let scene = &app.display.default_scene;
let display_object = display::object::Instance::new(); let display_object = display::object::Instance::new();
@ -256,7 +255,7 @@ impl Model {
let grid = app.new_view::<grid::View>(); let grid = app.new_view::<grid::View>();
display_object.add_child(&grid); display_object.add_child(&grid);
let section_navigator = SectionNavigator::new(&app); let section_navigator = SectionNavigator::new(app);
display_object.add_child(&section_navigator); display_object.add_child(&section_navigator);
let breadcrumbs = app.new_view::<breadcrumbs::Breadcrumbs>(); let breadcrumbs = app.new_view::<breadcrumbs::Breadcrumbs>();

View File

@ -132,6 +132,7 @@ pub struct BreadcrumbsModel {
/// A container for all the breadcrumbs after project name. This contained and all its /// A container for all the breadcrumbs after project name. This contained and all its
/// breadcrumbs are moved when project name component is resized. /// breadcrumbs are moved when project name component is resized.
breadcrumbs_container: display::object::Instance, breadcrumbs_container: display::object::Instance,
// Required for creating new breadcrumbs
app: Application, app: Application,
breadcrumbs: Rc<RefCell<Vec<Breadcrumb>>>, breadcrumbs: Rc<RefCell<Vec<Breadcrumb>>>,
frp_inputs: FrpInputs, frp_inputs: FrpInputs,

View File

@ -127,7 +127,6 @@ impl Animations {
#[derive(Debug, Clone, CloneRef)] #[derive(Debug, Clone, CloneRef)]
#[allow(missing_docs)] #[allow(missing_docs)]
struct ProjectNameModel { struct ProjectNameModel {
app: Application,
display_object: display::object::Instance, display_object: display::object::Instance,
view: background::View, view: background::View,
style: StyleWatch, style: StyleWatch,
@ -138,7 +137,6 @@ struct ProjectNameModel {
impl ProjectNameModel { impl ProjectNameModel {
/// Constructor. /// Constructor.
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
let app = app.clone_ref();
let scene = &app.display.default_scene; let scene = &app.display.default_scene;
let display_object = display::object::Instance::new(); let display_object = display::object::Instance::new();
// FIXME : StyleWatch is unsuitable here, as it was designed as an internal tool for shape // 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); scene.layers.panel.add(&view);
let project_name = default(); 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. /// Compute the width of the ProjectName view.
@ -423,12 +421,10 @@ impl View for ProjectName {
fn label() -> &'static str { fn label() -> &'static str {
"ProjectName" "ProjectName"
} }
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
ProjectName::new(app) ProjectName::new(app)
} }
fn app(&self) -> &Application {
&self.model.app
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> { fn default_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::*; use shortcut::ActionType::*;

View File

@ -402,6 +402,7 @@ impl Deref for Node {
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub struct NodeModel { pub struct NodeModel {
// Required for switching the node to a different layer
pub app: Application, pub app: Application,
pub display_object: display::object::Instance, pub display_object: display::object::Instance,
pub background: Background, pub background: Background,

View File

@ -133,7 +133,6 @@ impl From<node::Expression> for Expression {
/// Internal model of the port area. /// Internal model of the port area.
#[derive(Debug)] #[derive(Debug)]
pub struct Model { pub struct Model {
app: Application,
display_object: display::object::Instance, display_object: display::object::Instance,
edit_mode_label: text::Text, edit_mode_label: text::Text,
expression: RefCell<Expression>, expression: RefCell<Expression>,
@ -152,17 +151,16 @@ impl Model {
/// Constructor. /// Constructor.
#[profile(Debug)] #[profile(Debug)]
pub fn new(app: &Application) -> Self { pub fn new(app: &Application) -> Self {
let app = app.clone_ref();
let display_object = display::object::Instance::new_named("input"); let display_object = display::object::Instance::new_named("input");
let edit_mode_label = app.new_view::<text::Text>(); let edit_mode_label = app.new_view::<text::Text>();
let expression = default(); let expression = default();
let styles = StyleWatch::new(&app.display.default_scene.style_sheet); let styles = StyleWatch::new(&app.display.default_scene.style_sheet);
let styles_frp = StyleWatchFrp::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)); with_context(|ctx| ctx.layers.widget.add(&widget_tree));
Self { app, display_object, edit_mode_label, expression, styles, styles_frp, widget_tree } Self { display_object, edit_mode_label, expression, styles, styles_frp, widget_tree }
.init() .init(app)
} }
/// React to edit mode change. Shows and hides appropriate child views according to current /// React to edit mode change. Shows and hides appropriate child views according to current
@ -183,19 +181,24 @@ impl Model {
} }
#[profile(Debug)] #[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. // 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. // It needs to be more flexible once we have proper depth management.
// See https://www.pivotaltracker.com/story/show/183567632. // 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); self.set_label_layer(&scene.layers.label);
let text_color = self.styles.get_color(theme::graph_editor::node::text); 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.set_single_line_mode(true);
self.edit_mode_label.disable_command("cursor_move_up");
self.edit_mode_label.disable_command("cursor_move_down"); app.commands.set_command_enabled(&self.edit_mode_label, "cursor_move_up", false);
self.edit_mode_label.disable_command("add_cursor_at_mouse_position"); 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_color);
self.edit_mode_label.set_property_default(text::Size(TEXT_SIZE)); self.edit_mode_label.set_property_default(text::Size(TEXT_SIZE));
self.edit_mode_label.remove_all_cursors(); self.edit_mode_label.remove_all_cursors();

View File

@ -400,6 +400,7 @@ fn entry_for_current_value(
/// is minimal, as the actual dropdown view is not created. /// is minimal, as the actual dropdown view is not created.
#[derive(Debug)] #[derive(Debug)]
struct LazyDropdown { struct LazyDropdown {
// Required for lazy initialization
app: ensogl::application::Application, app: ensogl::application::Application,
set_all_entries: frp::Any<Vec<Choice>>, set_all_entries: frp::Any<Vec<Choice>>,
set_selected_entries: frp::Any<HashSet<Choice>>, set_selected_entries: frp::Any<HashSet<Choice>>,

View File

@ -156,7 +156,6 @@ impl Model {
/// Constructor. /// Constructor.
#[profile(Debug)] #[profile(Debug)]
pub fn new(app: &Application, frp: &Frp) -> Self { pub fn new(app: &Application, frp: &Frp) -> Self {
let app = app.clone_ref();
let display_object = display::object::Instance::new_named("output"); let display_object = display::object::Instance::new_named("output");
let ports = display::object::Instance::new(); let ports = display::object::Instance::new();
let port_models = default(); let port_models = default();
@ -169,7 +168,7 @@ impl Model {
display_object.add_child(&label); display_object.add_child(&label);
display_object.add_child(&ports); display_object.add_child(&ports);
Self { Self {
app, app: app.clone_ref(),
display_object, display_object,
ports, ports,
port_models, port_models,
@ -180,21 +179,21 @@ impl Model {
styles_frp, styles_frp,
frp, frp,
} }
.init() .init(app)
} }
#[profile(Debug)] #[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. // 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. // 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); scene.layers.main.remove(&self.label);
self.label.add_to_scene_layer(&scene.layers.label); self.label.add_to_scene_layer(&scene.layers.label);
let text_color = self.styles.get_color(theme::graph_editor::node::text); let text_color = self.styles.get_color(theme::graph_editor::node::text);
self.label.set_single_line_mode(true); self.label.set_single_line_mode(true);
self.label.disable_command("cursor_move_up"); app.commands.set_command_enabled(&self.label, "cursor_move_up", false);
self.label.disable_command("cursor_move_down"); app.commands.set_command_enabled(&self.label, "cursor_move_up", false);
self.label.set_property_default(text_color); self.label.set_property_default(text_color);
self.label.set_property_default(text::Size(input::area::TEXT_SIZE)); self.label.set_property_default(text::Size(input::area::TEXT_SIZE));
self.label.remove_all_cursors(); self.label.remove_all_cursors();

View File

@ -658,6 +658,8 @@ ensogl::define_endpoints_2! {
set_error_visualization_data ((NodeId, visualization::Data)), set_error_visualization_data ((NodeId, visualization::Data)),
enable_visualization (NodeId), enable_visualization (NodeId),
disable_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. /// Remove from visualization registry all non-default visualizations.
reset_visualization_registry (), reset_visualization_registry (),
@ -760,6 +762,7 @@ ensogl::define_endpoints_2! {
is_fs_visualization_displayed (bool), is_fs_visualization_displayed (bool),
visualization_preprocessor_changed ((NodeId,PreprocessorConfiguration)), visualization_preprocessor_changed ((NodeId,PreprocessorConfiguration)),
visualization_registry_reload_requested (), visualization_registry_reload_requested (),
visualization_update_error ((NodeId, String)),
widgets_requested (NodeId, ast::Id, ast::Id), widgets_requested (NodeId, ast::Id, ast::Id),
request_import (ImString), request_import (ImString),
@ -1802,6 +1805,7 @@ impl GraphEditorModelWithNetwork {
#[allow(missing_docs)] // FIXME[everyone] Public-facing API should be documented. #[allow(missing_docs)] // FIXME[everyone] Public-facing API should be documented.
pub struct GraphEditorModel { pub struct GraphEditorModel {
pub display_object: display::object::Instance, pub display_object: display::object::Instance,
// Required for dynamically creating nodes and edges.
pub app: Application, pub app: Application,
pub breadcrumbs: component::Breadcrumbs, pub breadcrumbs: component::Breadcrumbs,
pub cursor: cursor::Cursor, pub cursor: cursor::Cursor,
@ -2713,10 +2717,6 @@ impl application::View for GraphEditor {
new_graph_editor(app) new_graph_editor(app)
} }
fn app(&self) -> &Application {
&self.model.app
}
fn default_shortcuts() -> Vec<application::shortcut::Shortcut> { fn default_shortcuts() -> Vec<application::shortcut::Shortcut> {
use crate::shortcuts::SHORTCUTS; use crate::shortcuts::SHORTCUTS;
SHORTCUTS.iter().map(|(a, b, c, d)| Self::self_shortcut_when(*a, *c, *d, *b)).collect() 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_by_press <= viz_tgt_nodes.gate_not(&viz_tgt_nodes_all_on);
viz_enable <- any(viz_enable_by_press,inputs.enable_visualization); 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_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_preview_disable <= viz_tgt_nodes_off.sample(&viz_preview_mode_end);
viz_fullscreen_on <= viz_open_fs_ev.map(f_!(model.nodes.last_selected())); 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.is_fs_visualization_displayed <+ out.visualization_fullscreen.map(Option::is_some);
out.visualization_update_error <+ inputs.visualization_update_failed;
// === Register Visualization === // === Register Visualization ===

View File

@ -155,10 +155,6 @@ impl application::View for View {
Self::new(app) Self::new(app)
} }
fn app(&self) -> &Application {
self.model.app()
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> { fn default_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::*; use shortcut::ActionType::*;
[(Press, "ctrl `", "toggle"), (Press, "escape", "hide")] [(Press, "ctrl `", "toggle"), (Press, "escape", "hide")]

View File

@ -143,7 +143,6 @@ ensogl::define_endpoints! {
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
struct Model { struct Model {
app: Application,
display_object: display::object::Instance, display_object: display::object::Instance,
project_view_top_bar: ProjectViewTopBar, project_view_top_bar: ProjectViewTopBar,
graph_editor: Rc<GraphEditor>, graph_editor: Rc<GraphEditor>,
@ -175,10 +174,8 @@ impl Model {
display_object.add_child(&project_view_top_bar); display_object.add_child(&project_view_top_bar);
display_object.remove_child(&searcher); display_object.remove_child(&searcher);
let app = app.clone_ref();
let graph_editor = Rc::new(graph_editor); let graph_editor = Rc::new(graph_editor);
Self { Self {
app,
display_object, display_object,
project_view_top_bar, project_view_top_bar,
graph_editor, graph_editor,
@ -411,6 +408,7 @@ impl View {
graph.set_navigator_disabled <+ disable_navigation; graph.set_navigator_disabled <+ disable_navigation;
model.popup.set_label <+ graph.model.breadcrumbs.project_name_error; 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_read_only <+ frp.set_read_only;
graph.set_debug_mode <+ frp.source.debug_mode; graph.set_debug_mode <+ frp.source.debug_mode;
@ -722,10 +720,6 @@ impl application::View for View {
View::new(app) View::new(app)
} }
fn app(&self) -> &Application {
&self.model.app
}
fn default_shortcuts() -> Vec<application::shortcut::Shortcut> { fn default_shortcuts() -> Vec<application::shortcut::Shortcut> {
use shortcut::ActionType::*; use shortcut::ActionType::*;
[ [

View File

@ -44,7 +44,6 @@ mod shape {
/// An internal model of Status Bar component /// An internal model of Status Bar component
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
pub struct Model { pub struct Model {
app: Application,
display_object: display::object::Instance, display_object: display::object::Instance,
shape: shape::View, shape: shape::View,
close: close::View, close: close::View,
@ -54,7 +53,6 @@ pub struct Model {
impl Model { impl Model {
/// Constructor. /// Constructor.
pub fn new(app: &Application) -> Self { pub fn new(app: &Application) -> Self {
let app = app.clone_ref();
let display_object = display::object::Instance::new_named("WindowControlButtons"); let display_object = display::object::Instance::new_named("WindowControlButtons");
ensogl::shapes_order_dependencies! { ensogl::shapes_order_dependencies! {
@ -63,10 +61,10 @@ impl Model {
shape -> fullscreen::shape; shape -> fullscreen::shape;
} }
}; };
let close = close::View::new(&app); let close = close::View::new(app);
display_object.add_child(&close); display_object.add_child(&close);
let fullscreen = fullscreen::View::new(&app); let fullscreen = fullscreen::View::new(app);
display_object.add_child(&fullscreen); display_object.add_child(&fullscreen);
let shape = shape::View::new(); let shape = shape::View::new();
@ -74,7 +72,7 @@ impl Model {
app.display.default_scene.layers.panel.add(&display_object); 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. /// Updates positions of the buttons and sizes of the mouse area.
@ -190,10 +188,8 @@ impl application::View for View {
fn label() -> &'static str { fn label() -> &'static str {
"TopButtons" "TopButtons"
} }
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
View::new(app) View::new(app)
} }
fn app(&self) -> &Application {
&self.model.app
}
} }

View File

@ -33,13 +33,14 @@ enum State {
/// visibility. /// visibility.
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
pub struct Model { pub struct Model {
// Required for creating project view dynamically
app: Application, app: Application,
display_object: display::object::Instance, display_object: display::object::Instance,
state: Rc<CloneCell<State>>, state: Rc<CloneCell<State>>,
status_bar: crate::status_bar::View, status_bar: crate::status_bar::View,
welcome_view: crate::welcome_screen::View, welcome_view: crate::welcome_screen::View,
project_view: Rc<CloneCell<Option<crate::project::View>>>, project_view: Rc<CloneCell<Option<crate::project::View>>>,
frp: Frp, frp_outputs: FrpOutputsSource,
} }
impl Model { impl Model {
@ -53,9 +54,9 @@ impl Model {
let welcome_view = app.new_view::<crate::welcome_screen::View>(); let welcome_view = app.new_view::<crate::welcome_screen::View>();
let project_view = Rc::new(CloneCell::new(None)); let project_view = Rc::new(CloneCell::new(None));
display_object.add_child(&welcome_view); 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 /// 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) { fn init_project_view(&self) {
if self.project_view.get().is_none() { if self.project_view.get().is_none() {
let network = &self.frp.network;
let view = self.app.new_view::<crate::project::View>(); let view = self.app.new_view::<crate::project::View>();
let network = &view.network;
let project_list_frp = &view.project_list().frp; let project_list_frp = &view.project_list().frp;
let status_bar = &self.status_bar; let status_bar = &self.status_bar;
let display_object = &self.display_object; 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_shown <- view.fullscreen_visualization_shown.on_true();
fs_vis_hidden <- view.fullscreen_visualization_shown.on_false(); fs_vis_hidden <- view.fullscreen_visualization_shown.on_false();
eval fs_vis_shown ((_) status_bar.unset_parent()); eval fs_vis_shown ((_) status_bar.unset_parent());
eval fs_vis_hidden ([display_object, status_bar](_) display_object.add_child(&status_bar)); 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)); self.project_view.set(Some(view));
} }
@ -203,8 +204,4 @@ impl application::View for View {
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
Self::new(app) Self::new(app)
} }
fn app(&self) -> &Application {
&self.model.app
}
} }

View File

@ -107,7 +107,6 @@ pub type Entry = list_view::entry::GlyphHighlightedLabel;
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
struct Model { struct Model {
app: Application,
display_object: display::object::Instance, display_object: display::object::Instance,
list: ListView<Entry>, list: ListView<Entry>,
documentation: documentation::View, documentation: documentation::View,
@ -117,11 +116,10 @@ struct Model {
impl Model { impl Model {
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
let scene = &app.display.default_scene; let scene = &app.display.default_scene;
let app = app.clone_ref();
let display_object = display::object::Instance::new(); let display_object = display::object::Instance::new();
let list = app.new_view::<ListView<Entry>>(); let list = app.new_view::<ListView<Entry>>();
list.deprecated_focus(); list.deprecated_focus();
let documentation = documentation::View::new(&app); let documentation = documentation::View::new(app);
let doc_provider = default(); let doc_provider = default();
scene.layers.node_searcher.add(&list); scene.layers.node_searcher.add(&list);
display_object.add_child(&documentation); display_object.add_child(&documentation);
@ -137,7 +135,7 @@ impl Model {
list.set_x(ACTION_LIST_X); list.set_x(ACTION_LIST_X);
documentation.set_x(DOCUMENTATION_X); documentation.set_x(DOCUMENTATION_X);
documentation.set_y(-action_list_gap); 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) { fn set_height(&self, h: f32) {
@ -287,12 +285,11 @@ impl application::View for View {
fn label() -> &'static str { fn label() -> &'static str {
"Searcher" "Searcher"
} }
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
Self::new(app) Self::new(app)
} }
fn app(&self) -> &Application {
&self.model.app
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> { fn default_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::*; use shortcut::ActionType::*;
[(Press, "tab", "use_as_suggestion")] [(Press, "tab", "use_as_suggestion")]

View File

@ -116,7 +116,6 @@ static STYLESHEET: &str = include_str!("../style.css");
/// Model of Welcome Screen that generates HTML DOM elements. /// Model of Welcome Screen that generates HTML DOM elements.
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
pub struct Model { pub struct Model {
application: Application,
dom: DomSymbol, dom: DomSymbol,
display_object: display::object::Instance, display_object: display::object::Instance,
side_menu: SideMenu, side_menu: SideMenu,
@ -126,7 +125,6 @@ pub struct Model {
impl Model { impl Model {
/// Constructor. `frp` is used to set up event handlers on buttons. /// Constructor. `frp` is used to set up event handlers on buttons.
pub fn new(app: &Application) -> Self { pub fn new(app: &Application) -> Self {
let application = app.clone_ref();
let display_object = display::object::Instance::new(); let display_object = display::object::Instance::new();
let side_menu = SideMenu::new(); let side_menu = SideMenu::new();
@ -141,7 +139,7 @@ impl Model {
style.set_inner_html(STYLESHEET); style.set_inner_html(STYLESHEET);
dom.append_or_warn(&style); 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 { fn create_dom(side_menu: &SideMenu, template_cards: &TemplateCards) -> DomSymbol {
@ -258,8 +256,4 @@ impl application::View for View {
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
Self::new(app) Self::new(app)
} }
fn app(&self) -> &Application {
&self.model.application
}
} }

View File

@ -203,19 +203,17 @@ pub mod shape {
#[derivative(Clone(bound = ""))] #[derivative(Clone(bound = ""))]
#[allow(missing_docs)] #[allow(missing_docs)]
pub struct Model<S: Shape> { pub struct Model<S: Shape> {
app: Application,
display_object: display::object::Instance, display_object: display::object::Instance,
shape: ShapeView<S>, shape: ShapeView<S>,
} }
impl<Shape: ButtonShape> Model<Shape> { impl<Shape: ButtonShape> Model<Shape> {
/// Construct a button's model. /// Construct a button's model.
pub fn new(app: &Application) -> Self { pub fn new(_app: &Application) -> Self {
let app = app.clone_ref();
let display_object = display::object::Instance::new(); let display_object = display::object::Instance::new();
let shape = ShapeView::new(); let shape = ShapeView::new();
display_object.add_child(&shape); display_object.add_child(&shape);
Self { app, display_object, shape } Self { display_object, shape }
} }
/// Set the background (i.e. the circle) color. /// Set the background (i.e. the circle) color.

View File

@ -95,7 +95,6 @@ impl component::Frp<Model> for Frp {
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
pub struct Model { pub struct Model {
app: Application,
background: background::View, background: background::View,
label: Rc<RefCell<Option<text::Text>>>, label: Rc<RefCell<Option<text::Text>>>,
display_object: display::object::Instance, display_object: display::object::Instance,
@ -115,8 +114,7 @@ impl component::Model for Model {
display_object.add_child(&background); display_object.add_child(&background);
scene.layers.tooltip.add(&background); scene.layers.tooltip.add(&background);
let app = app.clone_ref(); Model { background, label, display_object }
Model { app, background, label, display_object }
} }
} }

View File

@ -114,6 +114,7 @@ pub struct FlameGraph {
blocks: Vec<Block>, blocks: Vec<Block>,
marks: Vec<Mark>, marks: Vec<Mark>,
origin_x: f64, origin_x: f64,
// Required for dynamically adding blocks.
app: Application, app: Application,
} }

View File

@ -98,7 +98,6 @@ impl component::Frp<Model> for Frp {
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
pub struct Model { pub struct Model {
app: Application,
background: background::View, background: background::View,
label: Rc<RefCell<Option<text::Text>>>, label: Rc<RefCell<Option<text::Text>>>,
display_object: display::object::Instance, display_object: display::object::Instance,
@ -118,8 +117,7 @@ impl component::Model for Model {
display_object.add_child(&background); display_object.add_child(&background);
scene.layers.tooltip.add(&background); scene.layers.tooltip.add(&background);
let app = app.clone_ref(); Model { background, label, display_object }
Model { app, background, label, display_object }
} }
} }

View File

@ -59,6 +59,7 @@ impl<E: display::Object> display::Object for VisibleEntry<E> {
#[derive(CloneRef, Debug, Derivative)] #[derive(CloneRef, Debug, Derivative)]
#[derivative(Clone(bound = ""))] #[derivative(Clone(bound = ""))]
pub struct CreationCtx<EntryParams> { pub struct CreationCtx<EntryParams> {
// Required for dynamically creating entries.
pub app: Application, pub app: Application,
pub network: frp::WeakNetwork, pub network: frp::WeakNetwork,
pub set_entry_size: frp::Stream<Vector2>, pub set_entry_size: frp::Stream<Vector2>,

View File

@ -688,10 +688,6 @@ impl<E: Entry> application::View for GridView<E> {
GridView::<E>::new(app) GridView::<E>::new(app)
} }
fn app(&self) -> &Application {
self.widget.app()
}
fn default_shortcuts() -> Vec<application::shortcut::Shortcut> { fn default_shortcuts() -> Vec<application::shortcut::Shortcut> {
use application::shortcut::ActionType::*; use application::shortcut::ActionType::*;
[ [

View File

@ -144,10 +144,6 @@ where
ComponentView::new(app) ComponentView::new(app)
} }
fn app(&self) -> &Application {
self.widget.app()
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> { fn default_shortcuts() -> Vec<shortcut::Shortcut> {
F::default_shortcuts() F::default_shortcuts()
} }

View File

@ -59,8 +59,7 @@ struct Model {
} }
impl Model { impl Model {
fn new(app: Application) -> Self { fn new(app: &Application) -> Self {
let app = app.clone_ref();
let scene = &app.display.default_scene; let scene = &app.display.default_scene;
let display_object = display::object::Instance::new(); let display_object = display::object::Instance::new();
let label = app.new_view::<text::Text>(); let label = app.new_view::<text::Text>();
@ -144,7 +143,7 @@ impl Label {
/// Constructor. /// Constructor.
pub fn new(app: &Application) -> Self { pub fn new(app: &Application) -> Self {
let frp = Rc::new(Frp::new()); 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() Label { model, frp }.init()
} }

View File

@ -66,6 +66,7 @@ pub type List<E> = ListData<E, <E as Entry>::Params>;
#[derivative(Clone(bound = ""))] #[derivative(Clone(bound = ""))]
#[clone_ref(bound = "E:CloneRef")] #[clone_ref(bound = "E:CloneRef")]
pub struct ListData<E, P> { pub struct ListData<E, P> {
// Required for dynamically creating new entries.
app: Application, app: Application,
display_object: display::object::Instance, display_object: display::object::Instance,
entries: Rc<RefCell<Vec<DisplayedEntry<E>>>>, entries: Rc<RefCell<Vec<DisplayedEntry<E>>>>,

View File

@ -124,7 +124,6 @@ impl Default for JumpTarget {
/// The Model of Select Component. /// The Model of Select Component.
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
struct Model<E: Entry> { struct Model<E: Entry> {
app: Application,
entries: entry::List<E>, entries: entry::List<E>,
selection: Selection, selection: Selection,
background: Rectangle, background: Rectangle,
@ -134,10 +133,9 @@ struct Model<E: Entry> {
impl<E: Entry> Model<E> { impl<E: Entry> Model<E> {
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
let app = app.clone_ref();
let display_object = display::object::Instance::new(); let display_object = display::object::Instance::new();
let scrolled_area = 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(); let background = Rectangle();
background.set_border_color(color::Rgba::transparent()); background.set_border_color(color::Rgba::transparent());
let selection = Selection::default(); let selection = Selection::default();
@ -146,7 +144,7 @@ impl<E: Entry> Model<E> {
display_object.add_child(&scrolled_area); display_object.add_child(&scrolled_area);
scrolled_area.add_child(&entries); scrolled_area.add_child(&entries);
scrolled_area.add_child(&selection); 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 /// Update the displayed entries list when _view_ has changed - the list was scrolled or
@ -438,7 +436,7 @@ where E::Model: Default
// === Selected Entry === // === 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.select_entry;
frp.source.selected_entry <+ frp.output.chosen_entry; frp.source.selected_entry <+ frp.output.chosen_entry;
@ -636,12 +634,11 @@ impl<E: Entry> application::View for ListView<E> {
fn label() -> &'static str { fn label() -> &'static str {
"ListView" "ListView"
} }
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
ListView::new(app) ListView::new(app)
} }
fn app(&self) -> &Application {
&self.model.app
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> { fn default_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::*; use shortcut::ActionType::*;
[ [

View File

@ -367,18 +367,14 @@ impl ScrollArea {
(0.0..=size.x).contains(&local_pos.x) && (-size.y..=0.0).contains(&local_pos.y) (0.0..=size.x).contains(&local_pos.x) && (-size.y..=0.0).contains(&local_pos.y)
})); }));
hovering <- hovering.sampler(); hovering <- hovering.sampler();
let on_scroll = model.display_object.on_event::<mouse::Wheel>();
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 } ScrollArea { model, frp }
} }

View File

@ -115,7 +115,7 @@ impl Frp {
resize <- frp.set_length.map(|&length| Vector2::new(length,WIDTH)); 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.use_track_handles(false);
model.set_track_corner_round(true); model.set_track_corner_round(true);
@ -358,22 +358,17 @@ pub struct Scrollbar {
/// Public FRP api of the Component. /// Public FRP api of the Component.
pub frp: Rc<Frp>, pub frp: Rc<Frp>,
model: Rc<Model>, model: Rc<Model>,
/// 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 { impl Scrollbar {
/// Constructor. /// Constructor.
pub fn new(app: &Application) -> Self { 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 frp = Frp::default();
let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet); 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); 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 { fn label() -> &'static str {
"Scrollbar" "Scrollbar"
} }
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
Scrollbar::new(app) Scrollbar::new(app)
} }
fn app(&self) -> &Application {
&self.app
}
} }

View File

@ -100,18 +100,16 @@ impl display::Object for Model {
pub struct FloatLabel { pub struct FloatLabel {
pub frp: Rc<Frp>, pub frp: Rc<Frp>,
model: Rc<Model>, model: Rc<Model>,
app: Application,
} }
impl FloatLabel { impl FloatLabel {
/// Constructor. /// Constructor.
pub fn new(app: &Application) -> Self { 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 frp = Frp::default();
frp.init(&model); frp.init(&model);
let frp = Rc::new(frp); let frp = Rc::new(frp);
Self { frp, model, app } Self { frp, model }
} }
} }

View File

@ -9,6 +9,7 @@ use crate::shape::shape_is_dragged;
use enso_frp as frp; use enso_frp as frp;
use enso_frp::io::Mouse_DEPRECATED; use enso_frp::io::Mouse_DEPRECATED;
use enso_frp::Network; use enso_frp::Network;
use ensogl_core::application::Application;
use ensogl_core::display::object::ObjectOps; use ensogl_core::display::object::ObjectOps;
use ensogl_core::display::shape::StyleWatchFrp; use ensogl_core::display::shape::StyleWatchFrp;
use ensogl_hardcoded_theme as theme; use ensogl_hardcoded_theme as theme;
@ -69,6 +70,7 @@ pub struct Frp {
impl Frp { impl Frp {
/// Create and initialize the FRP. /// Create and initialize the FRP.
pub fn new( pub fn new(
app: &Application,
model: &Model, model: &Model,
style: &StyleWatchFrp, style: &StyleWatchFrp,
network: &Network, network: &Network,
@ -76,7 +78,7 @@ impl Frp {
mouse: &Mouse_DEPRECATED, mouse: &Mouse_DEPRECATED,
) -> Frp { ) -> Frp {
let net = &network; 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 shadow = shadow::frp_from_style(style, theme::shadow);
let text_size = style.get_number(theme::text::size); let text_size = style.get_number(theme::text::size);

View File

@ -77,22 +77,17 @@ pub struct NumberPicker {
/// Public FRP api of the Component. /// Public FRP api of the Component.
pub frp: Rc<number::Frp>, pub frp: Rc<number::Frp>,
model: Rc<Model>, model: Rc<Model>,
/// 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 { impl NumberPicker {
/// Constructor. /// Constructor.
pub fn new(app: &Application) -> Self { 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 frp = number::Frp::default();
let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet); 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); 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 { fn label() -> &'static str {
"NumberPicker" "NumberPicker"
} }
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
NumberPicker::new(app) NumberPicker::new(app)
} }
fn app(&self) -> &Application {
&self.app
}
} }
@ -147,22 +140,17 @@ pub struct NumberRangePicker {
/// Public FRP api of the Component. /// Public FRP api of the Component.
pub frp: Rc<range::Frp>, pub frp: Rc<range::Frp>,
model: Rc<Model>, model: Rc<Model>,
/// 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 { impl NumberRangePicker {
/// Constructor. /// Constructor.
pub fn new(app: &Application) -> Self { 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 frp = range::Frp::default();
let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet); 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); 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 { fn label() -> &'static str {
"RangePicker" "RangePicker"
} }
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
NumberRangePicker::new(app) NumberRangePicker::new(app)
} }
fn app(&self) -> &Application {
&self.app
}
} }

View File

@ -70,8 +70,6 @@ pub struct Model {
background_left_corner_roundness: Rc<Cell<bool>>, background_left_corner_roundness: Rc<Cell<bool>>,
background_right_corner_roundness: Rc<Cell<bool>>, background_right_corner_roundness: Rc<Cell<bool>>,
padding: Rc<Cell<f32>>, padding: Rc<Cell<f32>>,
pub app: Application,
} }
#[allow(missing_docs)] #[allow(missing_docs)]
@ -95,7 +93,6 @@ impl Model {
let background_right_corner_roundness = default(); let background_right_corner_roundness = default();
let padding = default(); let padding = default();
let app = app.clone_ref();
let scene = &app.display.default_scene; let scene = &app.display.default_scene;
root.add_child(&label); root.add_child(&label);
@ -134,7 +131,6 @@ impl Model {
background_left_corner_roundness, background_left_corner_roundness,
background_right_corner_roundness, background_right_corner_roundness,
padding, padding,
app,
} }
} }

View File

@ -49,7 +49,8 @@ impl Frp {
model.show_background(true); 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 background_click = relative_shape_down_position(network, scene, &model.background);
let track_click = relative_shape_down_position(network, scene, &model.track); let track_click = relative_shape_down_position(network, scene, &model.track);

View File

@ -44,7 +44,8 @@ impl Frp {
let scene = &app.display.default_scene; let scene = &app.display.default_scene;
let mouse = &scene.mouse.frp_deprecated; 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.use_track_handles(true);
model.show_background(true); model.show_background(true);

View File

@ -89,6 +89,7 @@ impl component::Frp<Model> for Frp {
/// Internal model of the SequenceDiagram. /// Internal model of the SequenceDiagram.
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
pub struct Model { pub struct Model {
// Required for dynamically creating new lines.
app: Application, app: Application,
display_object: display::object::Instance, display_object: display::object::Instance,
actor_lines: Rc<RefCell<Vec<LabeledLine>>>, actor_lines: Rc<RefCell<Vec<LabeledLine>>>,

View File

@ -337,10 +337,6 @@ pub struct Slider {
#[deref] #[deref]
pub frp: Frp, pub frp: Frp,
model: Rc<Model>, model: Rc<Model>,
/// 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 { impl Slider {
@ -348,12 +344,11 @@ impl Slider {
pub fn new(app: &Application) -> Self { pub fn new(app: &Application) -> Self {
let frp = Frp::new(); let frp = Frp::new();
let model = Rc::new(Model::new(app, frp.network())); let model = Rc::new(Model::new(app, frp.network()));
let app = app.clone_ref(); Self { frp, model }.init(app)
Self { frp, model, app }.init()
} }
fn init(self) -> Self { fn init(self, app: &Application) -> Self {
self.init_value_update(); self.init_value_update(app);
self.init_limit_handling(); self.init_limit_handling();
self.init_value_display(); self.init_value_display();
@ -367,13 +362,13 @@ impl Slider {
} }
/// Initialize the slider value update FRP network. /// 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 network = self.frp.network();
let frp = &self.frp; let frp = &self.frp;
let input = &self.frp.input; let input = &self.frp.input;
let output = &self.frp.private.output; let output = &self.frp.private.output;
let model = &self.model; let model = &self.model;
let scene = &self.app.display.default_scene; let scene = &app.display.default_scene;
let mouse = &scene.mouse.frp_deprecated; let mouse = &scene.mouse.frp_deprecated;
let keyboard = &scene.keyboard.frp; let keyboard = &scene.keyboard.frp;
@ -845,10 +840,6 @@ impl application::View for Slider {
Self::new(app) Self::new(app)
} }
fn app(&self) -> &Application {
&self.app
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> { fn default_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::DoublePress; use shortcut::ActionType::DoublePress;
use shortcut::ActionType::Press; use shortcut::ActionType::Press;

View File

@ -1978,10 +1978,6 @@ impl application::View for Text {
Text::new(app) Text::new(app)
} }
fn app(&self) -> &Application {
&self.data.app
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> { fn default_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::*; use shortcut::ActionType::*;
([ ([

View File

@ -76,15 +76,6 @@ pub struct ApplicationData {
pub frp: Frp, 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 { impl Application {
/// Constructor. /// Constructor.
pub fn new(dom: impl DomPath) -> Self { pub fn new(dom: impl DomPath) -> Self {
@ -94,7 +85,7 @@ impl Application {
let commands = command::Registry::create(); let commands = command::Registry::create();
let shortcuts = let shortcuts =
shortcut::Registry::new(&scene.mouse.frp_deprecated, &scene.keyboard.frp, &commands); 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); let cursor = Cursor::new(&display.default_scene);
display.add_child(&cursor); display.add_child(&cursor);
let frp = Frp::new(); let frp = Frp::new();
@ -106,20 +97,27 @@ impl Application {
fn init(self) -> Self { fn init(self) -> Self {
let frp = &self.frp; let frp = &self.frp;
let data = &self.inner;
let network = self.frp.network(); let network = self.frp.network();
enso_frp::extend! { network enso_frp::extend! { network
app_focused <- self.display.default_scene.frp.focused.on_change(); 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; 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. // We hide the system cursor to replace it with the EnsoGL-provided one.
self.frp.hide_system_cursor(); self.frp.hide_system_cursor();
self 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. /// Create a new instance of a view.
pub fn new_view<T: View>(&self) -> T { pub fn new_view<T: View>(&self) -> T {
self.views.new_view(self) self.views.new_view(self)

View File

@ -27,9 +27,6 @@ pub trait View: FrpNetworkProvider + DerefToCommandApi {
/// Constructor. /// Constructor.
fn new(app: &Application) -> Self; fn new(app: &Application) -> Self;
/// Application reference.
fn app(&self) -> &Application;
/// Set of default shortcuts. /// Set of default shortcuts.
fn default_shortcuts() -> Vec<Shortcut> { fn default_shortcuts() -> Vec<Shortcut> {
default() default()
@ -58,24 +55,6 @@ pub trait View: FrpNetworkProvider + DerefToCommandApi {
condition, condition,
) )
} }
/// Disable the command in this component instance.
fn disable_command(&self, name: impl AsRef<str>)
where Self: Sized {
self.set_command_enabled(name, false)
}
/// Enable the command in this component instance.
fn enable_command(&self, name: impl AsRef<str>)
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<str>, 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. /// 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. /// Sets the command enable status for the provided component instance.
fn set_command_enabled<T: View>(&self, instance: &T, name: impl AsRef<str>, enabled: bool) { pub fn set_command_enabled<T: View>(&self, instance: &T, name: impl AsRef<str>, enabled: bool) {
self.with_command_mut(instance, name, |command| command.enabled = enabled) self.with_command_mut(instance, name, |command| command.enabled = enabled)
} }
} }

View File

@ -2,8 +2,6 @@
use crate::prelude::*; use crate::prelude::*;
use crate::display::world::World;
use super::command; use super::command;
use super::shortcut; use super::shortcut;
use super::Application; use super::Application;
@ -26,7 +24,6 @@ pub use command::View;
#[derive(Debug, Clone, CloneRef)] #[derive(Debug, Clone, CloneRef)]
#[allow(missing_docs)] #[allow(missing_docs)]
pub struct Registry { pub struct Registry {
pub display: World,
pub command_registry: command::Registry, pub command_registry: command::Registry,
pub shortcut_registry: shortcut::Registry, pub shortcut_registry: shortcut::Registry,
pub definitions: Rc<RefCell<HashSet<String>>>, pub definitions: Rc<RefCell<HashSet<String>>>,
@ -35,15 +32,13 @@ pub struct Registry {
impl Registry { impl Registry {
/// Constructor. /// Constructor.
pub fn create( pub fn create(
display: &World,
command_registry: &command::Registry, command_registry: &command::Registry,
shortcut_registry: &shortcut::Registry, shortcut_registry: &shortcut::Registry,
) -> Self { ) -> Self {
let display = display.clone_ref();
let command_registry = command_registry.clone_ref(); let command_registry = command_registry.clone_ref();
let shortcut_registry = shortcut_registry.clone_ref(); let shortcut_registry = shortcut_registry.clone_ref();
let definitions = default(); let definitions = default();
Self { display, command_registry, shortcut_registry, definitions } Self { command_registry, shortcut_registry, definitions }
} }
/// View registration. /// View registration.

View File

@ -18,6 +18,14 @@ struct Garbage {
before_mouse_events: Vec<Box<dyn Any>>, before_mouse_events: Vec<Box<dyn Any>>,
} }
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 /// The Garbage Collector
/// ///
@ -90,6 +98,14 @@ impl Collector {
}; };
drop(before_mouse_events); 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();
}
}
} }

View File

@ -670,6 +670,13 @@ impl WorldData {
self.garbage_collector.collect(object); 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 /// Set the maximum frequency at which the pointer location will be checked, in terms of number
/// of frames per check. /// of frames per check.
pub fn set_pixel_read_period(&self, period: usize) { pub fn set_pixel_read_period(&self, period: usize) {

View File

@ -367,13 +367,6 @@ impl<Model: 'static, Frp: 'static> Widget<Model, Frp> {
pub fn model(&self) -> &Model { pub fn model(&self) -> &Model {
&self.data.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<Model: 'static, Frp: 'static> display::Object for Widget<Model, Frp> { impl<Model: 'static, Frp: 'static> display::Object for Widget<Model, Frp> {

View File

@ -44,15 +44,13 @@ use ensogl_text_msdf::run_once_initialized;
#[derive(Clone, CloneRef, Debug)] #[derive(Clone, CloneRef, Debug)]
struct Model { struct Model {
app: Application,
display_object: display::object::Instance, display_object: display::object::Instance,
shape: Rectangle, shape: Rectangle,
cover: Rectangle, cover: Rectangle,
} }
impl Model { impl Model {
fn new(app: &Application) -> Self { fn new() -> Self {
let app = app.clone_ref();
let display_object = display::object::Instance::new(); let display_object = display::object::Instance::new();
let shape: Rectangle = default(); let shape: Rectangle = default();
shape.set_size(Vector2(300.0, 300.0)); shape.set_size(Vector2(300.0, 300.0));
@ -68,7 +66,7 @@ impl Model {
cover.set_corner_radius_max(); cover.set_corner_radius_max();
cover.set_pointer_events(false); cover.set_pointer_events(false);
display_object.add_child(&cover); display_object.add_child(&cover);
Self { app, display_object, shape, cover } Self { display_object, shape, cover }
} }
} }
@ -99,9 +97,9 @@ struct View {
impl View { impl View {
/// Constructor. /// Constructor.
pub fn new(app: &Application) -> Self { pub fn new() -> Self {
let frp = Frp::new(); let frp = Frp::new();
let model = Model::new(app); let model = Model::new();
let network = &frp.network; let network = &frp.network;
frp::extend! { network frp::extend! { network
trace model.shape.events_deprecated.mouse_up; trace model.shape.events_deprecated.mouse_up;
@ -139,11 +137,9 @@ impl application::View for View {
fn label() -> &'static str { fn label() -> &'static str {
"Circul" "Circul"
} }
fn new(app: &Application) -> Self {
View::new(app) fn new(_app: &Application) -> Self {
} View::new()
fn app(&self) -> &Application {
&self.model.app
} }
} }

View File

@ -232,16 +232,14 @@ impl FrpNetworkProvider for SliderCollection {
struct SliderCollection { struct SliderCollection {
#[deref] #[deref]
frp: Frp, frp: Frp,
app: Application,
model: Model, model: Model,
} }
impl SliderCollection { impl SliderCollection {
fn new(app: &Application) -> Self { fn new(app: &Application) -> Self {
let frp = Frp::new(); let frp = Frp::new();
let app = app.clone_ref(); let model = Model::new(app);
let model = Model::new(&app); Self { frp, model }.init()
Self { frp, app, model }.init()
} }
fn init(self) -> Self { fn init(self) -> Self {
@ -272,10 +270,6 @@ impl View for SliderCollection {
Self::new(app) Self::new(app)
} }
fn app(&self) -> &Application {
&self.app
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> { fn default_shortcuts() -> Vec<shortcut::Shortcut> {
use shortcut::ActionType::Press; use shortcut::ActionType::Press;
vec![ vec![

View File

@ -146,9 +146,9 @@ impl Drop for TraceCopies {
/// A module containing an utility for detecting leaks. /// 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 /// 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 them to be removed, you may add a [`Trace`] field to it and call [`enable`]. Then, at
/// expect all instances to be dropped, we may check the [`TRACKED_OBJECTS`] global variable, what /// the point where we expect all instances to be dropped, we may check the [`TRACKED_OBJECTS`]
/// instances are still alive and their creation backtraces. /// global variable, what instances are still alive and their creation backtraces.
pub mod leak_detector { pub mod leak_detector {
use crate::*; use crate::*;