From 624e58bd789097160f9dcd9dd316290fc9e3e511 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Tue, 5 Mar 2024 14:11:12 -0800 Subject: [PATCH] native file drop --- packages/desktop/src/app.rs | 24 +++++++- packages/desktop/src/events.rs | 13 ++++- packages/desktop/src/file_upload.rs | 80 +++++++++++++++++++++++++- packages/html/src/events/drag.rs | 2 +- packages/html/src/point_interaction.rs | 2 +- packages/interpreter/src/js/hash.txt | 2 +- 6 files changed, 115 insertions(+), 8 deletions(-) diff --git a/packages/desktop/src/app.rs b/packages/desktop/src/app.rs index b05bb0946..ed3528508 100644 --- a/packages/desktop/src/app.rs +++ b/packages/desktop/src/app.rs @@ -2,7 +2,7 @@ use crate::{ config::{Config, WindowCloseBehaviour}, element::DesktopElement, event_handlers::WindowEventHandlers, - file_upload::{DesktopFileUploadForm, FileDialogRequest}, + file_upload::{DesktopFileDragEvent, DesktopFileUploadForm, FileDialogRequest}, ipc::{EventData, IpcMessage, UserWindowEvent}, query::QueryResult, shortcut::{GlobalHotKeyEvent, ShortcutRegistry}, @@ -11,7 +11,7 @@ use crate::{ use crossbeam_channel::Receiver; use dioxus_core::ElementId; use dioxus_core::VirtualDom; -use dioxus_html::{native_bind::NativeFileEngine, HtmlEvent, PlatformEventData}; +use dioxus_html::{native_bind::NativeFileEngine, HasFileData, HtmlEvent, PlatformEventData}; use std::{ cell::{Cell, RefCell}, collections::HashMap, @@ -231,6 +231,7 @@ impl App { let view = self.webviews.get_mut(&id).unwrap(); let query = view.desktop_context.query.clone(); + let recent_file = view.desktop_context.file_hover.clone(); // check for a mounted event placeholder and replace it with a desktop specific element let as_any = match data { @@ -238,6 +239,25 @@ impl App { let element = DesktopElement::new(element, view.desktop_context.clone(), query); Rc::new(PlatformEventData::new(Box::new(element))) } + dioxus_html::EventData::Drag(ref drag) => { + // we want to override this with a native file engine, provided by the most recent drag event + if drag.files().is_some() { + let file_event = recent_file.current().unwrap(); + let paths = match file_event { + wry::FileDropEvent::Hovered { paths, position } => paths, + wry::FileDropEvent::Dropped { paths, position } => paths, + _ => vec![], + }; + let files = Arc::new(NativeFileEngine::new(paths)); + let event = DesktopFileDragEvent { + mouse: drag.mouse.clone(), + files, + }; + Rc::new(PlatformEventData::new(Box::new(event))) + } else { + data.into_any() + } + } _ => data.into_any(), }; diff --git a/packages/desktop/src/events.rs b/packages/desktop/src/events.rs index e14c04a01..5e772320b 100644 --- a/packages/desktop/src/events.rs +++ b/packages/desktop/src/events.rs @@ -1,6 +1,9 @@ //! Convert a serialized event to an event trigger -use crate::{element::DesktopElement, file_upload::DesktopFileUploadForm}; +use crate::{ + element::DesktopElement, + file_upload::{DesktopFileDragEvent, DesktopFileUploadForm}, +}; use dioxus_html::*; pub(crate) struct SerializedHtmlEventConverter; @@ -31,8 +34,14 @@ impl HtmlEventConverter for SerializedHtmlEventConverter { } fn convert_drag_data(&self, event: &PlatformEventData) -> DragData { + // Attempt a simple serialized data conversion + if let Some(_data) = event.downcast::() { + return _data.clone().into(); + } + + // If that failed then it's a file drag form event - .downcast::() + .downcast::() .cloned() .unwrap() .into() diff --git a/packages/desktop/src/file_upload.rs b/packages/desktop/src/file_upload.rs index af6643b7a..a7edef30d 100644 --- a/packages/desktop/src/file_upload.rs +++ b/packages/desktop/src/file_upload.rs @@ -1,6 +1,16 @@ #![allow(unused)] -use dioxus_html::{native_bind::NativeFileEngine, FileEngine, HasFileData, HasFormData}; +use dioxus_html::{ + geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint}, + input_data::{MouseButton, MouseButtonSet}, + native_bind::NativeFileEngine, + point_interaction::{ + InteractionElementOffset, InteractionLocation, ModifiersInteraction, PointerInteraction, + }, + prelude::{SerializedMouseData, SerializedPointInteraction}, + FileEngine, HasDragData, HasFileData, HasFormData, HasMouseData, +}; +use muda::accelerator::Modifiers; use serde::Deserialize; use std::{cell::Cell, path::PathBuf, rc::Rc, str::FromStr, sync::Arc}; use wry::FileDropEvent; @@ -152,4 +162,72 @@ impl NativeFileHover { pub fn set(&self, event: FileDropEvent) { self.event.set(Some(event)); } + + pub fn current(&self) -> Option { + self.event.as_ref().clone().take() + } +} + +#[derive(Clone)] +pub(crate) struct DesktopFileDragEvent { + pub mouse: SerializedPointInteraction, + pub files: Arc, +} + +impl HasFileData for DesktopFileDragEvent { + fn files(&self) -> Option> { + Some(self.files.clone()) + } +} + +impl HasDragData for DesktopFileDragEvent { + fn as_any(&self) -> &dyn std::any::Any { + self + } +} + +impl HasMouseData for DesktopFileDragEvent { + fn as_any(&self) -> &dyn std::any::Any { + self + } +} + +impl InteractionLocation for DesktopFileDragEvent { + fn client_coordinates(&self) -> ClientPoint { + self.mouse.client_coordinates() + } + + fn page_coordinates(&self) -> PagePoint { + self.mouse.page_coordinates() + } + + fn screen_coordinates(&self) -> ScreenPoint { + self.mouse.screen_coordinates() + } +} + +impl InteractionElementOffset for DesktopFileDragEvent { + fn element_coordinates(&self) -> ElementPoint { + self.mouse.element_coordinates() + } + + fn coordinates(&self) -> Coordinates { + self.mouse.coordinates() + } +} + +impl ModifiersInteraction for DesktopFileDragEvent { + fn modifiers(&self) -> Modifiers { + self.mouse.modifiers() + } +} + +impl PointerInteraction for DesktopFileDragEvent { + fn held_buttons(&self) -> MouseButtonSet { + self.mouse.held_buttons() + } + + fn trigger_button(&self) -> Option { + self.mouse.trigger_button() + } } diff --git a/packages/html/src/events/drag.rs b/packages/html/src/events/drag.rs index 6e31334a1..4cd8119db 100644 --- a/packages/html/src/events/drag.rs +++ b/packages/html/src/events/drag.rs @@ -109,7 +109,7 @@ impl PointerInteraction for DragData { /// A serialized version of DragData #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)] pub struct SerializedDragData { - mouse: crate::point_interaction::SerializedPointInteraction, + pub mouse: crate::point_interaction::SerializedPointInteraction, #[serde(default)] files: Option, diff --git a/packages/html/src/point_interaction.rs b/packages/html/src/point_interaction.rs index 9aa4e0f31..b0e34f780 100644 --- a/packages/html/src/point_interaction.rs +++ b/packages/html/src/point_interaction.rs @@ -50,7 +50,7 @@ pub trait ModifiersInteraction { #[cfg(feature = "serialize")] #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone, Default)] -pub(crate) struct SerializedPointInteraction { +pub struct SerializedPointInteraction { pub alt_key: bool, /// The button number that was pressed (if applicable) when the mouse event was fired. diff --git a/packages/interpreter/src/js/hash.txt b/packages/interpreter/src/js/hash.txt index 4bfd228e6..bfd4a2268 100644 --- a/packages/interpreter/src/js/hash.txt +++ b/packages/interpreter/src/js/hash.txt @@ -1 +1 @@ -2617078454438840343 \ No newline at end of file +13140749608285001344 \ No newline at end of file