-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature request: File dialog handling #2032
Comments
A good solution to native file browsing dialogs is necessary. However, to solve your immediate problem, have you tried polling the future manually in a system? It does not look good but it may solve your problem. |
There is also tinyfiledialogs which is not pure Rust (wraps a C library) but I found it to work reliable. |
I can't figure out a way to poll a future from a synchronous thread, so I haven't figured out how to get the async code to work. I should mention: the mystery |
If you can reproduce the bug with rodio alone, consider reporting it upstream at rodio's issue tracker. Otherwise, there is something to investigate in bevy_audio. I made an example of polling a future from a system in case you want to go down that route. It's a bit scary-looking but not very complicated. You will ned the use bevy::prelude::*;
use futures::pin_mut;
use futures_timer::Delay;
use std::ops::DerefMut;
use std::future::Future;
use std::time::Duration;
pub fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_system(poller.system())
.run();
}
// this defines the future we will want to poll
// it's a simple example, replace it with an actually
// useful future in your context
type FutureType = Delay;
fn setup(mut commands: Commands) {
let future = Delay::new(Duration::from_millis(500));
commands.spawn().insert(future);
}
fn poller(mut commands: Commands, mut query: Query<(Entity, &mut FutureType)>) {
for (entity, mut future) in query.iter_mut() {
println!("Frame!");
let context = &mut futures::task::Context::from_waker(futures::task::noop_waker_ref());
let future = future.deref_mut();
pin_mut!(future);
// do the polling
if let std::task::Poll::Ready(result) = future.poll(context) {
// Do something with the result of your future
println!("Timer elapsed.");
commands.entity(entity).despawn();
}
}
} It's not a very efficient polling strategy as it will poll on every frame no matter what. But I hope that in your context it's not that bad. I'd expect something to turn a future into an event or something to be a part of bevy however. That sounds like a reasonable feature request. |
Hi! RFD dev here. The only winit bug I know of related to file dialogs is: rust-windowing/winit#1779 The If you decide that bevy needs its own file dialog solution let me know, I can help with that. |
@PolyMeilex thanks for the expert opinion! It sounds like we should probably focus on fixing this issue in winit as thats our chosen "windowing abstraction" and it already has the feature and its just broken on a specific platform. I see this as a good chance for Bevy contributors to start familiarizing themselves with winit internals. We should have some expertise in that area / know how to drive our requirements upstream. |
Long term, we should probably have a way to display both native dialogues and custom so that they can be themed to the game |
Custom dialogues are impossible when running inside a sandbox like flatpak or snap unless you grant it blanket permission for all the user files. You need to use the file chooser xdg desktop portal for flatpak or snap to be able to access any file outside the sandbox. |
Is there a working example of using I tried the following and it blocks on the call to use bevy::prelude::*;
use futures::pin_mut;
use rfd::AsyncFileDialog;
use std::future::Future;
fn main() {
App::build().add_startup_system(dialog.system()).run();
}
fn dialog() {
let future = AsyncFileDialog::new().pick_file();
let context = &mut futures::task::Context::from_waker(futures::task::noop_waker_ref());
pin_mut!(future);
println!("Start Polling");
let poll_result = future.poll(context);
println!("Polling Result: {:?}", poll_result);
} |
I figured out how to use use futures_lite::future;
use std::path::PathBuf;
use bevy::{
prelude::*,
tasks::{AsyncComputeTaskPool, Task},
};
use rfd::FileDialog;
fn main() {
App::default()
.add_plugins(DefaultPlugins)
.add_startup_system(dialog.system())
.add_system(poll.system())
.run();
}
fn dialog(mut commands: Commands, thread_pool: Res<AsyncComputeTaskPool>) {
println!("Start Polling");
let task = thread_pool.spawn(async move { FileDialog::new().pick_file() });
commands.spawn().insert(task);
}
fn poll(mut commands: Commands, mut tasks: Query<(Entity, &mut Task<Option<PathBuf>>)>) {
println!("Polling");
for (entity, mut task) in tasks.iter_mut() {
if let Some(result) = future::block_on(future::poll_once(&mut *task)) {
println!("{:?}", result);
commands.entity(entity).remove::<Task<Option<PathBuf>>>();
}
}
} I tried replacing |
I was also searching for a file dialog solution. The example above that @samcarey provided was the shortest path to success I could find. Some updates were needed to work with bevy 8.1; shared below, in case others are bumping into this. I'm no Bevy/Rust expert, so if there's a better way to do this, please, let me know. use futures_lite::future;
use std::path::PathBuf;
use bevy::{
prelude::*,
tasks::{AsyncComputeTaskPool, Task},
};
use rfd::FileDialog;
fn main() {
App::default()
.add_plugins(DefaultPlugins)
.add_startup_system(dialog)
.add_system(poll)
.run();
}
#[derive(Component)]
struct SelectedFile(Task<Option<PathBuf>>);
fn dialog(mut commands: Commands) {
let thread_pool = AsyncComputeTaskPool::get();
println!("Start Polling");
let task = thread_pool.spawn(async move { FileDialog::new().pick_file() });
commands.spawn().insert(SelectedFile(task));
}
fn poll(mut commands: Commands, mut tasks: Query<(Entity, &mut SelectedFile)>) {
println!("Polling");
for (entity, mut selected_file) in tasks.iter_mut() {
if let Some(result) = future::block_on(future::poll_once(&mut selected_file.0)) {
println!("{:?}", result);
commands.entity(entity).remove::<SelectedFile>();
}
}
} |
But I wonder how Blender did it with a beautiful UI and cross platform File dialog? |
At least on macOS, blender file UI is a pain to use and doesn't use anything from the system ui/ux. It's painful enough that I'm using Python scripts for my most common import scenarios rather than use it... |
And for flatpak you have to use the org.freedesktop.portal.FileChooser dbus interface to use the native file dialog if your app doesn't have blanket permission for every file the user may want to open. |
I've created I've only tested it on Linux, but it uses cross-platform apis from |
I was also having issues with We can achieve this by passing any NonSend resource to the system (source). Example:
Quite hacky, but it seems to work. |
What problem does this solve or what need does it fill?
Native open/save file dialogs are surprisingly hard to do in Rust, and Bevy makes them even harder. The only crate I'm aware is able to show file dialogs across all main platforms is
rfd
. However, due to some bug inwinit
, a dependency of Bevy, only asynchronous file dialogs seem to work (see the discussion in this issue). Getting asynchronous code to work with Bevy would probably require either changing some Bevy internals, or fixing code further down the dependency chain.In other words, file dialogs are currently very hard in Bevy, and having them already implemented would be very convenient.
What solution would you like?
If possible, I'd like that there were something like a resource that somehow handled opening a file dialog across platforms and returning its result. It could be gated behind a feature if this doesn't work across all platforms, or requires many extra dependencies. If this turns out to be infeasible, an optional plugin for a window simulating a file dialog would still be very useful.
What alternative(s) have you considered?
I considered using other dependencies, but this doesn't seem to work due to the reasons outlined above.
The text was updated successfully, but these errors were encountered: