Scroll the documentation panel when it is hovered by the mouse (#3968)

[Task link](https://www.pivotaltracker.com/story/show/183970810).

Now documentation panel is being scrolled when only hovered by the cursor (you don't need to click on it beforehand).

Tested on macOS with both the touchpad and the mouse.

https://user-images.githubusercontent.com/6566674/206667769-04aae6b2-91ff-4877-bf10-8c0f0c4c5873.mp4
This commit is contained in:
Ilya Bogdanov 2022-12-14 19:37:04 +03:00 committed by GitHub
parent 1dfcf1cafc
commit 285959835f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 66 additions and 45 deletions

View File

@ -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<RefCell<Option<Navigator>>>,
}
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<Navigator>) {
*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<Model> 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;

View File

@ -197,7 +197,6 @@ pub fn main() {
let navigator = Navigator::new(scene, &scene.layers.node_searcher.camera());
let panel = app.new_view::<ide_view_component_list_panel::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(());

View File

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

View File

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

View File

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

View File

@ -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<bool>,
is_empty: frp::Stream<bool>,
is_hovered: frp::Stream<bool>,
}
/// 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::<GraphEditor>();
searcher.set_navigator(graph_editor.model.navigator.clone_ref());
let code_editor = app.new_view::<code_editor::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 ===

View File

@ -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<NavigatorModel>,
model: Rc<NavigatorModel>,
}
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 }
}
}