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 {
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());

View File

@ -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();

View File

@ -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());
}

View File

@ -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<Shortcut> {
use ensogl_core::application::shortcut::ActionType::*;
[(Press, "shift enter", "move_up"), (Press, "ctrl shift enter", "move_down")]

View File

@ -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::<grid::View>();
display_object.add_child(&grid);
let section_navigator = SectionNavigator::new(&app);
let section_navigator = SectionNavigator::new(app);
display_object.add_child(&section_navigator);
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
/// breadcrumbs are moved when project name component is resized.
breadcrumbs_container: display::object::Instance,
// Required for creating new breadcrumbs
app: Application,
breadcrumbs: Rc<RefCell<Vec<Breadcrumb>>>,
frp_inputs: FrpInputs,

View File

@ -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<shortcut::Shortcut> {
use shortcut::ActionType::*;

View File

@ -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,

View File

@ -133,7 +133,6 @@ impl From<node::Expression> 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<Expression>,
@ -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::<text::Text>();
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();

View File

@ -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<Vec<Choice>>,
set_selected_entries: frp::Any<HashSet<Choice>>,

View File

@ -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();

View File

@ -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<application::shortcut::Shortcut> {
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 ===

View File

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

View File

@ -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<GraphEditor>,
@ -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<application::shortcut::Shortcut> {
use shortcut::ActionType::*;
[

View File

@ -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
}
}

View File

@ -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<CloneCell<State>>,
status_bar: crate::status_bar::View,
welcome_view: crate::welcome_screen::View,
project_view: Rc<CloneCell<Option<crate::project::View>>>,
frp: Frp,
frp_outputs: FrpOutputsSource,
}
impl Model {
@ -53,9 +54,9 @@ impl Model {
let welcome_view = app.new_view::<crate::welcome_screen::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::<crate::project::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
}
}

View File

@ -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<Entry>,
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::<ListView<Entry>>();
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<shortcut::Shortcut> {
use shortcut::ActionType::*;
[(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.
#[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
}
}

View File

@ -203,19 +203,17 @@ pub mod shape {
#[derivative(Clone(bound = ""))]
#[allow(missing_docs)]
pub struct Model<S: Shape> {
app: Application,
display_object: display::object::Instance,
shape: ShapeView<S>,
}
impl<Shape: ButtonShape> Model<Shape> {
/// 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.

View File

@ -95,7 +95,6 @@ impl component::Frp<Model> for Frp {
#[derive(Clone, CloneRef, Debug)]
pub struct Model {
app: Application,
background: background::View,
label: Rc<RefCell<Option<text::Text>>>,
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 }
}
}

View File

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

View File

@ -98,7 +98,6 @@ impl component::Frp<Model> for Frp {
#[derive(Clone, CloneRef, Debug)]
pub struct Model {
app: Application,
background: background::View,
label: Rc<RefCell<Option<text::Text>>>,
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 }
}
}

View File

@ -59,6 +59,7 @@ impl<E: display::Object> display::Object for VisibleEntry<E> {
#[derive(CloneRef, Debug, Derivative)]
#[derivative(Clone(bound = ""))]
pub struct CreationCtx<EntryParams> {
// Required for dynamically creating entries.
pub app: Application,
pub network: frp::WeakNetwork,
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)
}
fn app(&self) -> &Application {
self.widget.app()
}
fn default_shortcuts() -> Vec<application::shortcut::Shortcut> {
use application::shortcut::ActionType::*;
[

View File

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

View File

@ -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::<text::Text>();
@ -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()
}

View File

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

View File

@ -124,7 +124,6 @@ impl Default for JumpTarget {
/// The Model of Select Component.
#[derive(Clone, CloneRef, Debug)]
struct Model<E: Entry> {
app: Application,
entries: entry::List<E>,
selection: Selection,
background: Rectangle,
@ -134,10 +133,9 @@ struct Model<E: Entry> {
impl<E: Entry> Model<E> {
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<E: Entry> Model<E> {
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<E: Entry> application::View for ListView<E> {
fn label() -> &'static str {
"ListView"
}
fn new(app: &Application) -> Self {
ListView::new(app)
}
fn app(&self) -> &Application {
&self.model.app
}
fn default_shortcuts() -> Vec<shortcut::Shortcut> {
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)
}));
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 }
}

View File

@ -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<Frp>,
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 {
/// 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
}
}

View File

@ -100,18 +100,16 @@ impl display::Object for Model {
pub struct FloatLabel {
pub frp: Rc<Frp>,
model: Rc<Model>,
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 }
}
}

View File

@ -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);

View File

@ -77,22 +77,17 @@ pub struct NumberPicker {
/// Public FRP api of the Component.
pub frp: Rc<number::Frp>,
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 {
/// 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<range::Frp>,
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 {
/// 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
}
}

View File

@ -70,8 +70,6 @@ pub struct Model {
background_left_corner_roundness: Rc<Cell<bool>>,
background_right_corner_roundness: Rc<Cell<bool>>,
padding: Rc<Cell<f32>>,
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,
}
}

View File

@ -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);

View File

@ -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);

View File

@ -89,6 +89,7 @@ impl component::Frp<Model> 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<RefCell<Vec<LabeledLine>>>,

View File

@ -337,10 +337,6 @@ pub struct Slider {
#[deref]
pub frp: Frp,
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 {
@ -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<shortcut::Shortcut> {
use shortcut::ActionType::DoublePress;
use shortcut::ActionType::Press;

View File

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

View File

@ -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<T: View>(&self) -> T {
self.views.new_view(self)

View File

@ -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<Shortcut> {
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<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.
@ -232,7 +211,7 @@ impl Registry {
}
/// 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)
}
}

View File

@ -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<RefCell<HashSet<String>>>,
@ -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.

View File

@ -18,6 +18,14 @@ struct Garbage {
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
///
@ -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();
}
}
}

View File

@ -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) {

View File

@ -367,13 +367,6 @@ impl<Model: 'static, Frp: 'static> Widget<Model, Frp> {
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<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)]
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()
}
}

View File

@ -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<shortcut::Shortcut> {
use shortcut::ActionType::Press;
vec![

View File

@ -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::*;