desktop: Move pick_file to picker.rs

This commit is contained in:
Kamil Jarosz 2024-08-21 20:23:41 +02:00
parent 7931b8f051
commit be8be123ba
9 changed files with 86 additions and 57 deletions

View File

@ -3,7 +3,7 @@ use crate::gui::{GuiController, MENU_HEIGHT};
use crate::player::{LaunchOptions, PlayerController}; use crate::player::{LaunchOptions, PlayerController};
use crate::preferences::GlobalPreferences; use crate::preferences::GlobalPreferences;
use crate::util::{ use crate::util::{
get_screen_size, gilrs_button_to_gamepad_button, parse_url, pick_file, plot_stats_in_tracy, get_screen_size, gilrs_button_to_gamepad_button, parse_url, plot_stats_in_tracy,
winit_to_ruffle_key_code, winit_to_ruffle_text_control, winit_to_ruffle_key_code, winit_to_ruffle_text_control,
}; };
use anyhow::{Context, Error}; use anyhow::{Context, Error};
@ -482,9 +482,10 @@ impl App {
winit::event::Event::UserEvent(RuffleEvent::BrowseAndOpen(options)) => { winit::event::Event::UserEvent(RuffleEvent::BrowseAndOpen(options)) => {
let event_loop = event_loop_proxy.clone(); let event_loop = event_loop_proxy.clone();
let window = self.window.clone(); let picker = self.gui.borrow().file_picker();
tokio::spawn(async move { tokio::spawn(async move {
if let Some(url) = pick_file(None, Some(&window)) if let Some(url) = picker
.pick_file(None)
.await .await
.and_then(|p| Url::from_file_path(p).ok()) .and_then(|p| Url::from_file_path(p).ok())
{ {

View File

@ -3,11 +3,13 @@ mod controller;
mod dialogs; mod dialogs;
mod menu_bar; mod menu_bar;
mod movie; mod movie;
mod picker;
mod theme; mod theme;
mod widgets; mod widgets;
pub use controller::GuiController; pub use controller::GuiController;
pub use movie::MovieView; pub use movie::MovieView;
pub use picker::FilePicker;
use std::borrow::Cow; use std::borrow::Cow;
pub use theme::ThemePreference; pub use theme::ThemePreference;
use url::Url; use url::Url;

View File

@ -23,6 +23,8 @@ use winit::event_loop::EventLoop;
use winit::keyboard::{Key, NamedKey}; use winit::keyboard::{Key, NamedKey};
use winit::window::{Theme, Window}; use winit::window::{Theme, Window};
use super::FilePicker;
/// Integration layer connecting wgpu+winit to egui. /// Integration layer connecting wgpu+winit to egui.
pub struct GuiController { pub struct GuiController {
descriptors: Arc<Descriptors>, descriptors: Arc<Descriptors>,
@ -149,6 +151,10 @@ impl GuiController {
&self.descriptors &self.descriptors
} }
pub fn file_picker(&self) -> FilePicker {
self.gui.dialogs.file_picker()
}
pub fn resize(&mut self, size: PhysicalSize<u32>) { pub fn resize(&mut self, size: PhysicalSize<u32>) {
if size.width > 0 && size.height > 0 { if size.width > 0 && size.height > 0 {
self.size = size; self.size = size;

View File

@ -17,10 +17,12 @@ use url::Url;
use volume_controls::VolumeControls; use volume_controls::VolumeControls;
use winit::event_loop::EventLoopProxy; use winit::event_loop::EventLoopProxy;
use super::FilePicker;
pub struct Dialogs { pub struct Dialogs {
window: Weak<winit::window::Window>,
event_loop: EventLoopProxy<RuffleEvent>, event_loop: EventLoopProxy<RuffleEvent>,
picker: FilePicker,
preferences_dialog: Option<PreferencesDialog>, preferences_dialog: Option<PreferencesDialog>,
bookmarks_dialog: Option<BookmarksDialog>, bookmarks_dialog: Option<BookmarksDialog>,
bookmark_add_dialog: Option<BookmarkAddDialog>, bookmark_add_dialog: Option<BookmarkAddDialog>,
@ -44,6 +46,7 @@ impl Dialogs {
window: Weak<winit::window::Window>, window: Weak<winit::window::Window>,
event_loop: EventLoopProxy<RuffleEvent>, event_loop: EventLoopProxy<RuffleEvent>,
) -> Self { ) -> Self {
let picker = FilePicker::new(window);
Self { Self {
preferences_dialog: None, preferences_dialog: None,
bookmarks_dialog: None, bookmarks_dialog: None,
@ -52,7 +55,7 @@ impl Dialogs {
open_dialog: OpenDialog::new( open_dialog: OpenDialog::new(
player_options, player_options,
default_path, default_path,
window.clone(), picker.clone(),
event_loop.clone(), event_loop.clone(),
), ),
is_open_dialog_visible: false, is_open_dialog_visible: false,
@ -62,12 +65,16 @@ impl Dialogs {
is_about_visible: false, is_about_visible: false,
window,
event_loop, event_loop,
picker,
preferences, preferences,
} }
} }
pub fn file_picker(&self) -> FilePicker {
self.picker.clone()
}
pub fn recreate_open_dialog( pub fn recreate_open_dialog(
&mut self, &mut self,
opt: LaunchOptions, opt: LaunchOptions,
@ -75,7 +82,7 @@ impl Dialogs {
event_loop: EventLoopProxy<RuffleEvent>, event_loop: EventLoopProxy<RuffleEvent>,
) { ) {
self.is_open_dialog_visible = false; self.is_open_dialog_visible = false;
self.open_dialog = OpenDialog::new(opt, url, self.window.clone(), event_loop); self.open_dialog = OpenDialog::new(opt, url, self.picker.clone(), event_loop);
} }
pub fn open_file_advanced(&mut self) { pub fn open_file_advanced(&mut self) {
@ -89,7 +96,7 @@ impl Dialogs {
pub fn open_bookmarks(&mut self) { pub fn open_bookmarks(&mut self) {
self.bookmarks_dialog = Some(BookmarksDialog::new( self.bookmarks_dialog = Some(BookmarksDialog::new(
self.preferences.clone(), self.preferences.clone(),
self.window.clone(), self.picker.clone(),
self.event_loop.clone(), self.event_loop.clone(),
)); ));
} }
@ -98,7 +105,7 @@ impl Dialogs {
self.bookmark_add_dialog = Some(BookmarkAddDialog::new( self.bookmark_add_dialog = Some(BookmarkAddDialog::new(
self.preferences.clone(), self.preferences.clone(),
initial_url, initial_url,
self.window.clone(), self.picker.clone(),
)) ))
} }

View File

@ -1,11 +1,10 @@
use crate::gui::text;
use crate::gui::widgets::PathOrUrlField; use crate::gui::widgets::PathOrUrlField;
use crate::gui::{text, FilePicker};
use crate::preferences::GlobalPreferences; use crate::preferences::GlobalPreferences;
use crate::{custom_event::RuffleEvent, player::LaunchOptions}; use crate::{custom_event::RuffleEvent, player::LaunchOptions};
use egui::{Align2, Button, Grid, Label, Layout, Sense, Ui, Widget, Window}; use egui::{Align2, Button, Grid, Label, Layout, Sense, Ui, Widget, Window};
use egui_extras::{Column, TableBuilder}; use egui_extras::{Column, TableBuilder};
use ruffle_frontend_utils::bookmarks::Bookmark; use ruffle_frontend_utils::bookmarks::Bookmark;
use std::sync::Weak;
use unic_langid::LanguageIdentifier; use unic_langid::LanguageIdentifier;
use url::Url; use url::Url;
use winit::event_loop::EventLoopProxy; use winit::event_loop::EventLoopProxy;
@ -20,7 +19,7 @@ impl BookmarkAddDialog {
pub fn new( pub fn new(
preferences: GlobalPreferences, preferences: GlobalPreferences,
initial_url: Option<Url>, initial_url: Option<Url>,
window: Weak<winit::window::Window>, picker: FilePicker,
) -> Self { ) -> Self {
Self { Self {
preferences, preferences,
@ -29,7 +28,7 @@ impl BookmarkAddDialog {
.map(|x| ruffle_frontend_utils::url_to_readable_name(x).into_owned()) .map(|x| ruffle_frontend_utils::url_to_readable_name(x).into_owned())
.unwrap_or_default(), .unwrap_or_default(),
// TODO: hint. // TODO: hint.
url: PathOrUrlField::new(initial_url, "", window), url: PathOrUrlField::new(initial_url, "", picker),
} }
} }
@ -100,8 +99,8 @@ struct SelectedBookmark {
} }
pub struct BookmarksDialog { pub struct BookmarksDialog {
window: Weak<winit::window::Window>,
event_loop: EventLoopProxy<RuffleEvent>, event_loop: EventLoopProxy<RuffleEvent>,
picker: FilePicker,
preferences: GlobalPreferences, preferences: GlobalPreferences,
selected_bookmark: Option<SelectedBookmark>, selected_bookmark: Option<SelectedBookmark>,
} }
@ -109,11 +108,11 @@ pub struct BookmarksDialog {
impl BookmarksDialog { impl BookmarksDialog {
pub fn new( pub fn new(
preferences: GlobalPreferences, preferences: GlobalPreferences,
window: Weak<winit::window::Window>, picker: FilePicker,
event_loop: EventLoopProxy<RuffleEvent>, event_loop: EventLoopProxy<RuffleEvent>,
) -> Self { ) -> Self {
Self { Self {
window, picker,
event_loop, event_loop,
preferences, preferences,
selected_bookmark: None, selected_bookmark: None,
@ -224,7 +223,7 @@ impl BookmarksDialog {
url: PathOrUrlField::new( url: PathOrUrlField::new(
Some(bookmark.url.clone()), Some(bookmark.url.clone()),
"", "",
self.window.clone(), self.picker.clone(),
), ),
}); });
} }

View File

@ -1,6 +1,6 @@
use crate::custom_event::RuffleEvent; use crate::custom_event::RuffleEvent;
use crate::gui::text;
use crate::gui::widgets::PathOrUrlField; use crate::gui::widgets::PathOrUrlField;
use crate::gui::{text, FilePicker};
use crate::player::LaunchOptions; use crate::player::LaunchOptions;
use egui::{ use egui::{
emath, Align2, Button, Checkbox, ComboBox, Grid, Layout, Slider, TextEdit, Ui, Widget, Window, emath, Align2, Button, Checkbox, ComboBox, Grid, Layout, Slider, TextEdit, Ui, Widget, Window,
@ -11,7 +11,6 @@ use ruffle_core::{LoadBehavior, PlayerRuntime, StageAlign, StageScaleMode};
use ruffle_render::quality::StageQuality; use ruffle_render::quality::StageQuality;
use std::borrow::Cow; use std::borrow::Cow;
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
use std::sync::Weak;
use std::time::Duration; use std::time::Duration;
use unic_langid::LanguageIdentifier; use unic_langid::LanguageIdentifier;
use url::Url; use url::Url;
@ -50,7 +49,7 @@ impl OpenDialog {
pub fn new( pub fn new(
defaults: LaunchOptions, defaults: LaunchOptions,
default_url: Option<Url>, default_url: Option<Url>,
window: Weak<winit::window::Window>, picker: FilePicker,
event_loop: EventLoopProxy<RuffleEvent>, event_loop: EventLoopProxy<RuffleEvent>,
) -> Self { ) -> Self {
let spoof_url = OptionalField::new( let spoof_url = OptionalField::new(
@ -73,7 +72,7 @@ impl OpenDialog {
defaults.proxy.as_ref().map(Url::to_string), defaults.proxy.as_ref().map(Url::to_string),
UrlField::new("socks5://localhost:8080"), UrlField::new("socks5://localhost:8080"),
); );
let path = PathOrUrlField::new(default_url, "path/to/movie.swf", window); let path = PathOrUrlField::new(default_url, "path/to/movie.swf", picker);
let script_timeout = OptionalField::new( let script_timeout = OptionalField::new(
defaults defaults
.player .player

40
desktop/src/gui/picker.rs Normal file
View File

@ -0,0 +1,40 @@
use rfd::AsyncFileDialog;
use std::{
path::PathBuf,
sync::{Arc, Weak},
};
use winit::window::Window;
#[derive(Clone)]
pub struct FilePicker {
data: Arc<FilePickerData>,
}
struct FilePickerData {
parent: Weak<Window>,
}
impl FilePicker {
pub fn new(parent: Weak<Window>) -> Self {
Self {
data: Arc::new(FilePickerData { parent }),
}
}
pub async fn pick_file(&self, dir: Option<PathBuf>) -> Option<PathBuf> {
let mut dialog = AsyncFileDialog::new()
.add_filter("Flash Files", &["swf", "spl", "ruf"])
.add_filter("All Files", &["*"])
.set_title("Load a Flash File");
if let Some(dir) = dir {
dialog = dialog.set_directory(dir);
}
if let Some(parent) = self.data.parent.upgrade() {
dialog = dialog.set_parent(&parent);
}
dialog.pick_file().await.map(|h| h.into())
}
}

View File

@ -1,29 +1,26 @@
use crate::gui::text; use crate::gui::text;
use crate::util::pick_file;
use egui::{TextEdit, Ui}; use egui::{TextEdit, Ui};
use std::path::Path; use std::path::Path;
use std::sync::{Arc, Mutex, MutexGuard, Weak}; use std::sync::{Arc, Mutex, MutexGuard};
use unic_langid::LanguageIdentifier; use unic_langid::LanguageIdentifier;
use url::Url; use url::Url;
use super::FilePicker;
pub struct PathOrUrlField { pub struct PathOrUrlField {
window: Weak<winit::window::Window>, picker: FilePicker,
value: Arc<Mutex<String>>, value: Arc<Mutex<String>>,
result: Option<Url>, result: Option<Url>,
hint: &'static str, hint: &'static str,
} }
impl PathOrUrlField { impl PathOrUrlField {
pub fn new( pub fn new(default: Option<Url>, hint: &'static str, picker: FilePicker) -> Self {
default: Option<Url>,
hint: &'static str,
window: Weak<winit::window::Window>,
) -> Self {
if let Some(default) = default { if let Some(default) = default {
if default.scheme() == "file" { if default.scheme() == "file" {
if let Ok(path) = default.to_file_path() { if let Ok(path) = default.to_file_path() {
return Self { return Self {
window, picker,
value: Arc::new(Mutex::new(path.to_string_lossy().to_string())), value: Arc::new(Mutex::new(path.to_string_lossy().to_string())),
result: Some(default), result: Some(default),
hint, hint,
@ -32,7 +29,7 @@ impl PathOrUrlField {
} }
return Self { return Self {
window, picker,
value: Arc::new(Mutex::new(default.to_string())), value: Arc::new(Mutex::new(default.to_string())),
result: Some(default), result: Some(default),
hint, hint,
@ -40,7 +37,7 @@ impl PathOrUrlField {
} }
Self { Self {
window, picker,
value: Arc::new(Mutex::new("".to_string())), value: Arc::new(Mutex::new("".to_string())),
result: None, result: None,
hint, hint,
@ -65,9 +62,9 @@ impl PathOrUrlField {
}); });
let value = self.value.clone(); let value = self.value.clone();
let window = self.window.upgrade(); let picker = self.picker.clone();
tokio::spawn(async move { tokio::spawn(async move {
if let Some(path) = pick_file(dir, window.as_ref()).await { if let Some(path) = picker.pick_file(dir).await {
let mut value_lock = Self::lock_value(&value); let mut value_lock = Self::lock_value(&value);
*value_lock = path.to_string_lossy().to_string(); *value_lock = path.to_string_lossy().to_string();
} }

View File

@ -1,11 +1,9 @@
use crate::custom_event::RuffleEvent; use crate::custom_event::RuffleEvent;
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use gilrs::Button; use gilrs::Button;
use rfd::AsyncFileDialog;
use ruffle_core::events::{GamepadButton, KeyCode, TextControlCode}; use ruffle_core::events::{GamepadButton, KeyCode, TextControlCode};
use std::path::{Path, PathBuf}; use std::path::Path;
use url::Url; use url::Url;
use wgpu::rwh::{HasDisplayHandle, HasWindowHandle};
use winit::dpi::PhysicalSize; use winit::dpi::PhysicalSize;
use winit::event::{KeyEvent, Modifiers}; use winit::event::{KeyEvent, Modifiers};
use winit::event_loop::EventLoop; use winit::event_loop::EventLoop;
@ -245,26 +243,6 @@ pub fn parse_url(path: &Path) -> Result<Url, Error> {
} }
} }
pub async fn pick_file<W: HasWindowHandle + HasDisplayHandle>(
dir: Option<PathBuf>,
parent: Option<&W>,
) -> Option<PathBuf> {
let mut dialog = AsyncFileDialog::new()
.add_filter("Flash Files", &["swf", "spl", "ruf"])
.add_filter("All Files", &["*"])
.set_title("Load a Flash File");
if let Some(dir) = dir {
dialog = dialog.set_directory(dir);
}
if let Some(parent) = parent {
dialog = dialog.set_parent(parent);
}
dialog.pick_file().await.map(|h| h.into())
}
#[cfg(not(feature = "tracy"))] #[cfg(not(feature = "tracy"))]
pub fn plot_stats_in_tracy(_instance: &wgpu::Instance) {} pub fn plot_stats_in_tracy(_instance: &wgpu::Instance) {}