mirror of
https://github.com/enso-org/enso.git
synced 2024-11-21 16:36:59 +03:00
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:
parent
1dfcf1cafc
commit
285959835f
@ -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;
|
||||
|
||||
|
||||
|
@ -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(());
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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(());
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 ===
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user