diff --git a/Cargo.lock b/Cargo.lock index e499a54cdb..de1cd33267 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/app/gui/view/graph-editor/src/lib.rs b/app/gui/view/graph-editor/src/lib.rs index b248e73922..1668d58d8b 100644 --- a/app/gui/view/graph-editor/src/lib.rs +++ b/app/gui/view/graph-editor/src/lib.rs @@ -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() } ); diff --git a/lib/rust/ensogl/component/drop-manager/Cargo.toml b/lib/rust/ensogl/component/drop-manager/Cargo.toml index f1a1190023..01247c29a9 100644 --- a/lib/rust/ensogl/component/drop-manager/Cargo.toml +++ b/lib/rust/ensogl/component/drop-manager/Cargo.toml @@ -5,6 +5,8 @@ authors = ["Enso Team "] edition = "2021" [dependencies] +ensogl-core = { path = "../../core" } +enso-types = { path = "../../../types" } enso-web = { path = "../../../web" } enso-frp = { path = "../../../frp" } enso-prelude = { path = "../../../prelude" } diff --git a/lib/rust/ensogl/component/drop-manager/src/lib.rs b/lib/rust/ensogl/component/drop-manager/src/lib.rs index bec575b00b..375705d69a 100644 --- a/lib/rust/ensogl/component/drop-manager/src/lib.rs +++ b/lib/rust/ensogl/component/drop-manager/src/lib.rs @@ -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; type DragOverClosure = Closure 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, +} + /// 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 bool>; pub struct Manager { #[allow(dead_code)] network: frp::Network, - files_received: frp::Source>, + files_received: frp::Source, #[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, 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> { + pub fn files_received(&self) -> &frp::Source { &self.files_received } - fn handle_drop_event(event: web_sys::DragEvent, files_received: &frp::Source>) { + /// Retrieve the position of the drop event in the scene coordinates. + fn event_position(scene: &Scene, event: &web_sys::DragEvent) -> Vector2 { + let dom: WithKnownShape = 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, + 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); } } } diff --git a/lib/rust/ensogl/examples/drop-manager/src/lib.rs b/lib/rust/ensogl/examples/drop-manager/src/lib.rs index a1dfeedcb8..be898a202f 100644 --- a/lib/rust/ensogl/examples/drop-manager/src/lib.rs +++ b/lib/rust/ensogl/examples/drop-manager/src/lib.rs @@ -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;