mirror of
https://github.com/enso-org/enso.git
synced 2024-11-23 16:18:23 +03:00
Fix wrong placement of nodes created from dropped files. (#5906)
Right now, we use the cursor position to determine the target position for dropped items. However, it seems that during dragging of files, we do not always receive mouse events, thus cannot update the cursor position. To avoid this, this PR refactors the functionality to use the location of the drop event, instead of the last known cursor position. Fixes #5237. https://user-images.githubusercontent.com/1428930/224735951-9cd6ff62-a749-4ff3-8437-c0bee3c0dd05.mp4
This commit is contained in:
parent
b46be10f63
commit
7a40ccc3ea
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -2707,7 +2707,9 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"enso-frp",
|
||||
"enso-prelude",
|
||||
"enso-types",
|
||||
"enso-web",
|
||||
"ensogl-core",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
|
@ -1756,7 +1756,8 @@ impl GraphEditorModel {
|
||||
let profiling_statuses = profiling::Statuses::new();
|
||||
let profiling_button = component::profiling::Button::new(&app);
|
||||
let add_node_button = Rc::new(component::add_node_button::AddNodeButton::new(&app));
|
||||
let drop_manager = ensogl_drop_manager::Manager::new(&scene.dom.root);
|
||||
let drop_manager =
|
||||
ensogl_drop_manager::Manager::new(&scene.dom.root.clone_ref().into(), scene);
|
||||
let styles_frp = StyleWatchFrp::new(&scene.style_sheet);
|
||||
let selection_controller =
|
||||
selection::Controller::new(&frp, &app.cursor, &scene.mouse.frp, &touch_state, &nodes);
|
||||
@ -3752,12 +3753,14 @@ fn new_graph_editor(app: &Application) -> GraphEditor {
|
||||
let default_gap = model.styles_frp.get_number_or(gap_path, 0.0);
|
||||
let files_received = model.drop_manager.files_received().clone_ref();
|
||||
frp::extend! { network
|
||||
files_with_positions <- files_received.map3(&cursor_pos_in_scene,&default_gap,
|
||||
|files,cursor_pos,default_gap| {
|
||||
files_with_positions <- files_received.map2(&default_gap,
|
||||
move |drop_event_data,default_gap| {
|
||||
let files = &drop_event_data.files;
|
||||
let drop_posititon = drop_event_data.position;
|
||||
let single_offset = default_gap + node::HEIGHT;
|
||||
files.iter().enumerate().map(|(index,file)| {
|
||||
let offset = Vector2(0.0, single_offset * index as f32);
|
||||
(file.clone_ref(),cursor_pos+offset)
|
||||
(file.clone_ref(), drop_posititon + offset)
|
||||
}).collect_vec()
|
||||
}
|
||||
);
|
||||
|
@ -5,6 +5,8 @@ authors = ["Enso Team <contact@enso.org>"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ensogl-core = { path = "../../core" }
|
||||
enso-types = { path = "../../../types" }
|
||||
enso-web = { path = "../../../web" }
|
||||
enso-frp = { path = "../../../frp" }
|
||||
enso-prelude = { path = "../../../prelude" }
|
||||
|
@ -21,6 +21,7 @@
|
||||
/// Commonly used utilities.
|
||||
pub mod prelude {
|
||||
pub use enso_prelude::*;
|
||||
pub use enso_types::*;
|
||||
}
|
||||
|
||||
use crate::prelude::*;
|
||||
@ -30,6 +31,8 @@ use enso_web as web;
|
||||
use enso_web::stream::BlobExt;
|
||||
use enso_web::stream::ReadableStreamDefaultReader;
|
||||
use enso_web::Closure;
|
||||
use ensogl_core::display::scene::Scene;
|
||||
use ensogl_core::system::web::dom::WithKnownShape;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use enso_web::JsCast;
|
||||
@ -113,6 +116,15 @@ impl File {
|
||||
type DropClosure = Closure<dyn Fn(web_sys::DragEvent)>;
|
||||
type DragOverClosure = Closure<dyn Fn(web_sys::DragEvent) -> bool>;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
/// The data emitted by the `files_received` frp endpoint.
|
||||
pub struct DropEventData {
|
||||
/// The position of the drop event in the scene coordinates.
|
||||
pub position: Vector2,
|
||||
/// The dropped files.
|
||||
pub files: Vec<File>,
|
||||
}
|
||||
|
||||
/// The Manager of dropped files.
|
||||
///
|
||||
/// It adds listeners for drag and drop events to the target passed during construction. It provides
|
||||
@ -122,7 +134,7 @@ type DragOverClosure = Closure<dyn Fn(web_sys::DragEvent) -> bool>;
|
||||
pub struct Manager {
|
||||
#[allow(dead_code)]
|
||||
network: frp::Network,
|
||||
files_received: frp::Source<Vec<File>>,
|
||||
files_received: frp::Source<DropEventData>,
|
||||
#[allow(dead_code)]
|
||||
drop_handle: web::EventListenerHandle,
|
||||
#[allow(dead_code)]
|
||||
@ -131,17 +143,18 @@ pub struct Manager {
|
||||
|
||||
impl Manager {
|
||||
/// Constructor, adding listener to the given target.
|
||||
pub fn new(target: &enso_web::EventTarget) -> Self {
|
||||
pub fn new(dom: &WithKnownShape<web::EventTarget>, scene: &Scene) -> Self {
|
||||
debug!("Creating.");
|
||||
let network = frp::Network::new("DropFileManager");
|
||||
frp::extend! { network
|
||||
files_received <- source();
|
||||
}
|
||||
|
||||
let drop: DropClosure = Closure::new(f!([files_received](event:web_sys::DragEvent) {
|
||||
let target: &web::EventTarget = dom.deref();
|
||||
let drop: DropClosure = Closure::new(f!([files_received,scene](event:web_sys::DragEvent) {
|
||||
debug!("Dropped files.");
|
||||
event.prevent_default();
|
||||
Self::handle_drop_event(event,&files_received)
|
||||
Self::handle_drop_event(event, &files_received, &scene);
|
||||
}));
|
||||
// To mark element as a valid drop target, the `dragover` event handler should return
|
||||
// `false`. See
|
||||
@ -156,11 +169,28 @@ impl Manager {
|
||||
}
|
||||
|
||||
/// The frp endpoint emitting signal when a file is dropped.
|
||||
pub fn files_received(&self) -> &frp::Source<Vec<File>> {
|
||||
pub fn files_received(&self) -> &frp::Source<DropEventData> {
|
||||
&self.files_received
|
||||
}
|
||||
|
||||
fn handle_drop_event(event: web_sys::DragEvent, files_received: &frp::Source<Vec<File>>) {
|
||||
/// Retrieve the position of the drop event in the scene coordinates.
|
||||
fn event_position(scene: &Scene, event: &web_sys::DragEvent) -> Vector2 {
|
||||
let dom: WithKnownShape<web::EventTarget> = scene.dom.root.clone_ref().into();
|
||||
let shape = dom.shape.value();
|
||||
let base = Vector2::new(0.0, shape.height);
|
||||
let position = Vector2::new(event.client_x() as f32, -event.client_y() as f32);
|
||||
let position = base + position;
|
||||
let center = scene.frp.shape.value().center();
|
||||
let position = position - center;
|
||||
scene.screen_to_scene_coordinates(Vector3::new(position.x, position.y, 0.0)).xy()
|
||||
}
|
||||
|
||||
fn handle_drop_event(
|
||||
event: web_sys::DragEvent,
|
||||
files_received: &frp::Source<DropEventData>,
|
||||
scene: &Scene,
|
||||
) {
|
||||
let position = Self::event_position(scene, &event);
|
||||
let opt_files = event.data_transfer().and_then(|t| t.files());
|
||||
if let Some(js_files) = opt_files {
|
||||
let js_files_iter = (0..js_files.length()).filter_map(|i| js_files.get(i));
|
||||
@ -171,7 +201,8 @@ impl Manager {
|
||||
None
|
||||
}
|
||||
});
|
||||
files_received.emit(files_iter.collect_vec());
|
||||
let data = DropEventData { position, files: files_iter.collect_vec() };
|
||||
files_received.emit(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,11 +57,14 @@ fn download_file(file: ensogl_drop_manager::File) {
|
||||
#[allow(dead_code)]
|
||||
pub fn main() {
|
||||
let world = World::new().displayed_in("root");
|
||||
let drop_manager = ensogl_drop_manager::Manager::new(world.default_scene.dom.root.as_ref());
|
||||
let scene = world.default_scene.clone_ref();
|
||||
let drop_manager =
|
||||
ensogl_drop_manager::Manager::new(&scene.dom.root.clone_ref().into(), &scene);
|
||||
let network = enso_frp::Network::new("Debug Scene");
|
||||
enso_frp::extend! { network
|
||||
let file_received = drop_manager.files_received().clone_ref();
|
||||
eval file_received ([](files) for file in files { download_file(file.clone_ref())});
|
||||
eval file_received ([](ensogl_drop_manager::DropEventData{ files, ..})
|
||||
for file in files { download_file(file.clone_ref())});
|
||||
}
|
||||
|
||||
let mut loader_hidden = false;
|
||||
|
Loading…
Reference in New Issue
Block a user