mirror of
https://github.com/emilk/egui.git
synced 2026-08-31 22:00:03 -04:00
Store web_sys::File inside of DroppedFile (#8354)
* Closes #4654 * Related #4667 * [x] I have followed the instructions in the PR template This PR avoids materializing the contents of a file that was dragged into an egui application on the web. It does so by storing the `web_sys::File` handle directly on WASM. This breaks the existing API of `DroppedFile` on the web, because there is no way to retrieve the bytes synchronously form a `DroppedFile` anymore, forcing handling call sites to become asynchronous. The native API remains the same. --------- Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
@@ -19,6 +19,7 @@ workspace = true
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = ["--generate-link-to-definition"]
|
||||
targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"]
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -90,3 +91,9 @@ document-features = { workspace = true, optional = true }
|
||||
|
||||
ron = { workspace = true, optional = true }
|
||||
serde = { workspace = true, optional = true, features = ["derive", "rc"] }
|
||||
|
||||
|
||||
# web:
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
# For `DroppedFile`, which hands web apps a file handle instead of its contents.
|
||||
web-sys = { workspace = true, features = ["File"] }
|
||||
|
||||
@@ -1,19 +1,51 @@
|
||||
use std::{path::Path, sync::Arc};
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use std::{future::Future, pin::Pin};
|
||||
|
||||
/// A file dropped into egui.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct DroppedFile {
|
||||
/// Set by the `egui-winit` backend.
|
||||
pub path: Option<std::path::PathBuf>,
|
||||
///
|
||||
/// The integration owns the concrete file handle, letting egui remain independent of windowing
|
||||
/// backends and file APIs.
|
||||
pub trait DroppedFile: std::fmt::Debug {
|
||||
/// The path of the dropped file.
|
||||
///
|
||||
/// This is an absolute path on native platforms. On the web, it is a relative path containing
|
||||
/// only the file name because browsers do not expose the file's local path.
|
||||
fn path(&self) -> &Path;
|
||||
|
||||
/// Name of the file. Set by the `eframe` web backend.
|
||||
pub name: String,
|
||||
/// Read the file contents.
|
||||
///
|
||||
/// This is asynchronous because browsers can only read files asynchronously.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the browser cannot read the file.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn bytes_async(&self) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, String>> + '_>>;
|
||||
|
||||
/// With the `eframe` web backend, this is set to the mime-type of the file (if available).
|
||||
pub mime: String,
|
||||
/// Read the file contents.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the file cannot be read.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn bytes(&self) -> Result<Vec<u8>, String>;
|
||||
|
||||
/// Set by the `eframe` web backend.
|
||||
pub last_modified: Option<std::time::SystemTime>,
|
||||
|
||||
/// Set by the `eframe` web backend.
|
||||
pub bytes: Option<std::sync::Arc<[u8]>>,
|
||||
/// The browser file handle, if this file was dropped on the web.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn web_file(&self) -> Option<&web_sys::File> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// A shared reference to a dropped file.
|
||||
#[cfg(not(all(target_arch = "wasm32", target_feature = "atomics")))]
|
||||
pub type DroppedFileHandle = Arc<dyn DroppedFile + Send + Sync>;
|
||||
|
||||
/// A shared reference to a dropped file.
|
||||
///
|
||||
/// This is not necessarily `Send + Sync` when wasm threads are enabled, because
|
||||
/// [`web_sys::File`] is not thread-safe in that configuration.
|
||||
#[cfg(all(target_arch = "wasm32", target_feature = "atomics"))]
|
||||
pub type DroppedFileHandle = Arc<dyn DroppedFile>;
|
||||
|
||||
@@ -16,7 +16,7 @@ mod touch;
|
||||
mod viewport_info;
|
||||
|
||||
pub use self::{
|
||||
dropped_file::DroppedFile,
|
||||
dropped_file::{DroppedFile, DroppedFileHandle},
|
||||
event::Event,
|
||||
event_filter::EventFilter,
|
||||
hovered_file::HoveredFile,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{OrderedViewportIdMap, Theme, ViewportId, ViewportIdMap, emath::Rect};
|
||||
|
||||
use super::{DroppedFile, Event, HoveredFile, SafeAreaInsets, ViewportInfo};
|
||||
use super::{DroppedFileHandle, Event, HoveredFile, SafeAreaInsets, ViewportInfo};
|
||||
|
||||
/// What the integrations provides to egui at the start of each frame.
|
||||
///
|
||||
@@ -13,7 +13,7 @@ use super::{DroppedFile, Event, HoveredFile, SafeAreaInsets, ViewportInfo};
|
||||
///
|
||||
/// Ii "points" can be calculated from native physical pixels
|
||||
/// using `pixels_per_point` = [`crate::Context::zoom_factor`] * `native_pixels_per_point`;
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct RawInput {
|
||||
/// The id of the active viewport.
|
||||
@@ -65,9 +65,20 @@ pub struct RawInput {
|
||||
|
||||
/// Dragged files dropped into egui.
|
||||
///
|
||||
/// egui never reads the file contents.
|
||||
#[cfg_attr(
|
||||
not(target_arch = "wasm32"),
|
||||
doc = "Call [`crate::DroppedFile::bytes`] to read a dropped file."
|
||||
)]
|
||||
#[cfg_attr(
|
||||
target_arch = "wasm32",
|
||||
doc = "Call [`crate::DroppedFile::bytes_async`] to read a dropped file."
|
||||
)]
|
||||
///
|
||||
/// Note: when using `eframe` on Windows, this will always be empty if drag-and-drop support has
|
||||
/// been disabled in [`crate::viewport::ViewportBuilder`].
|
||||
pub dropped_files: Vec<DroppedFile>,
|
||||
#[cfg_attr(feature = "serde", serde(skip))]
|
||||
pub dropped_files: Vec<DroppedFileHandle>,
|
||||
|
||||
/// The native window has the keyboard focus (i.e. is receiving key presses).
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user