diff --git a/app/gui/view/component-browser/component-list-panel/src/lib.rs b/app/gui/view/component-browser/component-list-panel/src/lib.rs index 868abb2c66..5f40bef921 100644 --- a/app/gui/view/component-browser/component-list-panel/src/lib.rs +++ b/app/gui/view/component-browser/component-list-panel/src/lib.rs @@ -55,7 +55,6 @@ use ensogl_core::data::bounding_box::BoundingBox; use ensogl_core::data::color; use ensogl_core::define_endpoints_2; use ensogl_core::display; -use ensogl_core::display::navigation::navigator::Navigator; use ensogl_core::display::object::ObjectOps; use ensogl_core::display::shape::StyleWatchFrp; use ensogl_derive_theme::FromTheme; @@ -238,14 +237,12 @@ pub struct Model { pub grid: grid::View, pub section_navigator: SectionNavigator, pub breadcrumbs: breadcrumbs::Breadcrumbs, - scene_navigator: Rc>>, } impl Model { fn new(app: &Application) -> Self { let app = app.clone_ref(); let display_object = display::object::Instance::new(); - let scene_navigator = default(); let background = background::View::new(); display_object.add_child(&background); @@ -260,7 +257,7 @@ impl Model { breadcrumbs.set_base_layer(&app.display.default_scene.layers.node_searcher); display_object.add_child(&breadcrumbs); - Self { display_object, background, grid, section_navigator, scene_navigator, breadcrumbs } + Self { display_object, background, grid, section_navigator, breadcrumbs } } fn set_initial_breadcrumbs(&self) { @@ -279,11 +276,6 @@ impl Model { self.grid.set_xy(style.grid_pos()); } - /// Set the navigator so it can be disabled on hover. - pub fn set_navigator(&self, navigator: Option) { - *self.scene_navigator.borrow_mut() = navigator - } - // Note that this is a workaround for lack of hierarchical mouse over events. // We need to know if the mouse is over the panel, but cannot do it via a shape, as // sub-components still need to receive all of the mouse events, too. @@ -295,23 +287,6 @@ impl Model { let viewport = BoundingBox::from_center_and_size(default(), size); viewport.contains(pos) } - - fn on_hover(&self) { - if let Some(navigator) = self.scene_navigator.borrow().as_ref() { - navigator.disable() - } else { - warn!( - "Navigator was not initialised on ComponentBrowserPanel. \ - Scroll events will not be handled correctly." - ) - } - } - - fn on_hover_end(&self) { - if let Some(navigator) = self.scene_navigator.borrow().as_ref() { - navigator.enable() - } - } } impl display::Object for Model { @@ -345,6 +320,7 @@ define_endpoints_2! { } Output{ size(Vector2), + is_hovered(bool), } } @@ -367,15 +343,13 @@ impl component::Frp for Frp { let pos = scene.screen_to_object_space(&model, pos.xy()); model.is_hovered(pos) })).gate(&is_visible).on_change(); + output.is_hovered <+ is_hovered; // TODO[ib] Temporary solution for focus, we grab keyboard events if the // component browser is visible. The proper implementation is tracked in // https://www.pivotaltracker.com/story/show/180872763 model.grid.deprecated_set_focus <+ is_visible; - on_hover <- is_hovered.on_true(); on_hover_end <- is_hovered.on_false(); - eval_ on_hover ( model.on_hover() ); - eval_ on_hover_end ( model.on_hover_end() ); model.grid.unhover_element <+ on_hover_end; diff --git a/app/gui/view/debug_scene/component-list-panel-view/src/lib.rs b/app/gui/view/debug_scene/component-list-panel-view/src/lib.rs index 8f7a85e4db..8a32f1023a 100644 --- a/app/gui/view/debug_scene/component-list-panel-view/src/lib.rs +++ b/app/gui/view/debug_scene/component-list-panel-view/src/lib.rs @@ -197,7 +197,6 @@ pub fn main() { let navigator = Navigator::new(scene, &scene.layers.node_searcher.camera()); let panel = app.new_view::(); scene.layers.node_searcher.add(&panel); - panel.model().set_navigator(Some(navigator.clone_ref())); panel.show(); let network = frp::Network::new("new_component_list_panel_view"); //TODO[ao] should be done by panel itself. @@ -209,6 +208,11 @@ pub fn main() { size <- all_with(&init, &panel.size, |(), panel_size| *panel_size); snap <- all_with(&size, &scene.frp.shape, |sz, sh| snap_to_pixel_offset(*sz, sh)); eval snap((snap) panel.set_xy(*snap)); + + + // === Disable navigator on hover === + + navigator.frp.set_enabled <+ panel.is_hovered.not(); } init.emit(()); diff --git a/app/gui/view/graph-editor/src/lib.rs b/app/gui/view/graph-editor/src/lib.rs index 64fc381ff3..7d1fb68377 100644 --- a/app/gui/view/graph-editor/src/lib.rs +++ b/app/gui/view/graph-editor/src/lib.rs @@ -2648,11 +2648,9 @@ fn new_graph_editor(app: &Application) -> GraphEditor { disable_navigator <- any_(&set_navigator_false,&some_vis_selected); enable_navigator <- any_(&set_navigator_true,&no_vis_selected); - eval_ disable_navigator ( model.navigator.disable() ); - eval_ enable_navigator ( model.navigator.enable() ); + model.navigator.frp.set_enabled <+ bool(&disable_navigator,&enable_navigator); - out.navigator_active <+ inputs.set_navigator_disabled - || out.some_visualisation_selected; + out.navigator_active <+ model.navigator.frp.enabled; } diff --git a/app/gui/view/src/component_browser.rs b/app/gui/view/src/component_browser.rs index 1a2cd02f2f..a8a694664c 100644 --- a/app/gui/view/src/component_browser.rs +++ b/app/gui/view/src/component_browser.rs @@ -91,6 +91,7 @@ ensogl::define_endpoints_2! { is_visible(bool), size(Vector2), expression_input_position(Vector2), + is_hovered(bool), } } @@ -138,6 +139,9 @@ impl component::Frp for Frp { &snap, Model::expression_input_position ); + + out.is_hovered <+ list_panel.is_hovered || documentation.frp.is_hovered; + out.is_hovered <+ input.hide.constant(false); } init.emit(()); } diff --git a/app/gui/view/src/documentation.rs b/app/gui/view/src/documentation.rs index cba4cbc928..f4e01becec 100644 --- a/app/gui/view/src/documentation.rs +++ b/app/gui/view/src/documentation.rs @@ -238,6 +238,8 @@ ensogl::define_endpoints! { /// Indicates whether the documentation panel has been selected through clicking into /// it, or deselected by clicking somewhere else. is_selected(bool), + /// Indicates whether the documentation panel has been hovered. + is_hovered(bool), } } @@ -328,6 +330,19 @@ impl View { app.frp.show_system_cursor <+ overlay.events.mouse_over; app.frp.hide_system_cursor <+ overlay.events.mouse_out; + + + // === Hover === + + frp.source.is_hovered <+ model.overlay.events.mouse_over.constant(true); + frp.source.is_hovered <+ model.overlay.events.mouse_out.constant(false); + let mouse_up = scene.mouse.frp.up.clone_ref(); + let mouse_down = scene.mouse.frp.down.clone_ref(); + let mouse_wheel = scene.mouse.frp.wheel.clone_ref(); + let mouse_position = scene.mouse.frp.position.clone_ref(); + caught_mouse <- any_(mouse_up,mouse_down,mouse_wheel,mouse_position); + pass_to_dom <- caught_mouse.gate(&frp.source.is_hovered); + eval_ pass_to_dom(scene.current_js_event.pass_to_dom.emit(())); } visualization.pass_events_to_dom_if_active(scene, network); self diff --git a/app/gui/view/src/project.rs b/app/gui/view/src/project.rs index 08caae4682..fe78380c61 100644 --- a/app/gui/view/src/project.rs +++ b/app/gui/view/src/project.rs @@ -24,7 +24,6 @@ use ensogl::application; use ensogl::application::shortcut; use ensogl::application::Application; use ensogl::display; -use ensogl::display::navigation::navigator::Navigator; use ensogl::system::web; use ensogl::system::web::dom; use ensogl::Animation; @@ -143,6 +142,7 @@ struct SearcherFrp { editing_committed: frp::Stream, is_visible: frp::Stream, is_empty: frp::Stream, + is_hovered: frp::Stream, } /// A structure containing the Searcher View: the old Node Searcher of a new Component Browser. @@ -166,12 +166,6 @@ impl SearcherVariant { } } - fn set_navigator(&self, navigator: Navigator) { - if let Self::ComponentBrowser(browser) = self { - browser.model().list.model().set_navigator(Some(navigator)) - } - } - fn frp(&self, project_view_network: &frp::Network) -> SearcherFrp { match self { SearcherVariant::ComponentBrowser(view) => { @@ -185,9 +179,11 @@ impl SearcherVariant { editing_committed, is_visible: view.output.is_visible.clone_ref().into(), is_empty: is_empty.into(), + is_hovered: view.output.is_hovered.clone_ref().into(), } } SearcherVariant::OldNodeSearcher(view) => { + let documentation = view.documentation(); frp::extend! {project_view_network editing_committed <- view.editing_committed.constant(()); } @@ -195,6 +191,7 @@ impl SearcherVariant { editing_committed, is_visible: view.output.is_visible.clone_ref().into(), is_empty: view.output.is_empty.clone_ref().into(), + is_hovered: documentation.frp.is_hovered.clone_ref().into(), } } } @@ -276,7 +273,6 @@ impl Model { let display_object = display::object::Instance::new(); let searcher = SearcherVariant::new(app); let graph_editor = app.new_view::(); - searcher.set_navigator(graph_editor.model.navigator.clone_ref()); let code_editor = app.new_view::(); let fullscreen_vis = default(); let prompt_background = prompt_background::View::new(); @@ -749,7 +745,8 @@ impl View { // === Disabling Navigation === let documentation = model.searcher.documentation(); - disable_navigation <- documentation.frp.is_selected || frp.open_dialog_shown; + searcher_active <- searcher.is_hovered || documentation.frp.is_selected; + disable_navigation <- searcher_active || frp.open_dialog_shown; graph.set_navigator_disabled <+ disable_navigation; // === Disabling Dropping === diff --git a/lib/rust/ensogl/core/src/display/navigation/navigator.rs b/lib/rust/ensogl/core/src/display/navigation/navigator.rs index 6dbb683b44..e1f238d797 100644 --- a/lib/rust/ensogl/core/src/display/navigation/navigator.rs +++ b/lib/rust/ensogl/core/src/display/navigation/navigator.rs @@ -7,6 +7,7 @@ use crate::prelude::*; use crate::animation::physics; use crate::control::callback; +use crate::define_endpoints_2; use crate::display::camera::Camera2d; use crate::display::navigation::navigator::events::NavigatorEvents; use crate::display::object::traits::*; @@ -238,6 +239,20 @@ impl NavigatorModel { +// =========== +// === FRP === +// =========== + +define_endpoints_2! { + Input { + set_enabled(bool), + } + Output { + enabled(bool), + } +} + + // ================= // === Navigator === // ================= @@ -245,14 +260,28 @@ impl NavigatorModel { /// Navigator enables camera navigation with mouse interactions. #[derive(Clone, CloneRef, Debug, Shrinkwrap)] pub struct Navigator { + #[allow(missing_docs)] + pub frp: Frp, #[shrinkwrap(main_field)] - model: Rc, + model: Rc, } impl Navigator { pub fn new(scene: &Scene, camera: &Camera2d) -> Self { let model = Rc::new(NavigatorModel::new(scene, camera)); - Navigator { model } + let frp = Frp::new(); + let out = &frp.private.output; + + let network = frp.network(); + frp::extend! { network + enable <- frp.set_enabled.on_true(); + disable <- frp.set_enabled.on_false(); + eval_ enable(model.enable()); + eval_ disable(model.disable()); + out.enabled <+ frp.set_enabled; + } + + Navigator { model, frp } } }