|
@@ -1,733 +0,0 @@
|
|
|
-// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
|
|
-// SPDX-License-Identifier: Apache-2.0
|
|
|
-// SPDX-License-Identifier: MIT
|
|
|
-
|
|
|
-//! Use native message and file open/save dialogs.
|
|
|
-//!
|
|
|
-//! This module exposes non-blocking APIs on its root, relying on callback closures
|
|
|
-//! to give results back. This is particularly useful when running dialogs from the main thread.
|
|
|
-//! When using on asynchronous contexts such as async commands, the [`blocking`] APIs are recommended.
|
|
|
-
|
|
|
-pub use nonblocking::*;
|
|
|
-
|
|
|
-#[cfg(not(target_os = "linux"))]
|
|
|
-macro_rules! run_dialog {
|
|
|
- ($e:expr, $h: ident) => {{
|
|
|
- std::thread::spawn(move || {
|
|
|
- let response = $e;
|
|
|
- $h(response);
|
|
|
- });
|
|
|
- }};
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(target_os = "linux")]
|
|
|
-macro_rules! run_dialog {
|
|
|
- ($e:expr, $h: ident) => {{
|
|
|
- std::thread::spawn(move || {
|
|
|
- let context = glib::MainContext::default();
|
|
|
- context.invoke_with_priority(glib::PRIORITY_HIGH, move || {
|
|
|
- let response = $e;
|
|
|
- $h(response);
|
|
|
- });
|
|
|
- });
|
|
|
- }};
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(not(target_os = "linux"))]
|
|
|
-macro_rules! run_file_dialog {
|
|
|
- ($e:expr, $h: ident) => {{
|
|
|
- std::thread::spawn(move || {
|
|
|
- let response = crate::async_runtime::block_on($e);
|
|
|
- $h(response);
|
|
|
- });
|
|
|
- }};
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(target_os = "linux")]
|
|
|
-macro_rules! run_file_dialog {
|
|
|
- ($e:expr, $h: ident) => {{
|
|
|
- std::thread::spawn(move || {
|
|
|
- let context = glib::MainContext::default();
|
|
|
- context.invoke_with_priority(glib::PRIORITY_HIGH, move || {
|
|
|
- let response = $e;
|
|
|
- $h(response);
|
|
|
- });
|
|
|
- });
|
|
|
- }};
|
|
|
-}
|
|
|
-
|
|
|
-macro_rules! run_dialog_sync {
|
|
|
- ($e:expr) => {{
|
|
|
- let (tx, rx) = sync_channel(0);
|
|
|
- let cb = move |response| {
|
|
|
- tx.send(response).unwrap();
|
|
|
- };
|
|
|
- run_file_dialog!($e, cb);
|
|
|
- rx.recv().unwrap()
|
|
|
- }};
|
|
|
-}
|
|
|
-
|
|
|
-macro_rules! file_dialog_builder {
|
|
|
- () => {
|
|
|
- #[cfg(target_os = "linux")]
|
|
|
- type FileDialog = rfd::FileDialog;
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- type FileDialog = rfd::AsyncFileDialog;
|
|
|
-
|
|
|
- /// The file dialog builder.
|
|
|
- ///
|
|
|
- /// Constructs file picker dialogs that can select single/multiple files or directories.
|
|
|
- #[derive(Debug, Default)]
|
|
|
- pub struct FileDialogBuilder(FileDialog);
|
|
|
-
|
|
|
- impl FileDialogBuilder {
|
|
|
- /// Gets the default file dialog builder.
|
|
|
- pub fn new() -> Self {
|
|
|
- Default::default()
|
|
|
- }
|
|
|
-
|
|
|
- /// Add file extension filter. Takes in the name of the filter, and list of extensions
|
|
|
- #[must_use]
|
|
|
- pub fn add_filter(mut self, name: impl AsRef<str>, extensions: &[&str]) -> Self {
|
|
|
- self.0 = self.0.add_filter(name.as_ref(), extensions);
|
|
|
- self
|
|
|
- }
|
|
|
-
|
|
|
- /// Set starting directory of the dialog.
|
|
|
- #[must_use]
|
|
|
- pub fn set_directory<P: AsRef<Path>>(mut self, directory: P) -> Self {
|
|
|
- self.0 = self.0.set_directory(directory);
|
|
|
- self
|
|
|
- }
|
|
|
-
|
|
|
- /// Set starting file name of the dialog.
|
|
|
- #[must_use]
|
|
|
- pub fn set_file_name(mut self, file_name: &str) -> Self {
|
|
|
- self.0 = self.0.set_file_name(file_name);
|
|
|
- self
|
|
|
- }
|
|
|
-
|
|
|
- /// Sets the parent window of the dialog.
|
|
|
- #[must_use]
|
|
|
- pub fn set_parent<W: raw_window_handle::HasRawWindowHandle>(mut self, parent: &W) -> Self {
|
|
|
- self.0 = self.0.set_parent(parent);
|
|
|
- self
|
|
|
- }
|
|
|
-
|
|
|
- /// Set the title of the dialog.
|
|
|
- #[must_use]
|
|
|
- pub fn set_title(mut self, title: &str) -> Self {
|
|
|
- self.0 = self.0.set_title(title);
|
|
|
- self
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-macro_rules! message_dialog_builder {
|
|
|
- () => {
|
|
|
- /// A builder for message dialogs.
|
|
|
- pub struct MessageDialogBuilder(rfd::MessageDialog);
|
|
|
-
|
|
|
- impl MessageDialogBuilder {
|
|
|
- /// Creates a new message dialog builder.
|
|
|
- pub fn new(title: impl AsRef<str>, message: impl AsRef<str>) -> Self {
|
|
|
- let title = title.as_ref().to_string();
|
|
|
- let message = message.as_ref().to_string();
|
|
|
- Self(
|
|
|
- rfd::MessageDialog::new()
|
|
|
- .set_title(&title)
|
|
|
- .set_description(&message),
|
|
|
- )
|
|
|
- }
|
|
|
-
|
|
|
- /// Set parent windows explicitly (optional)
|
|
|
- ///
|
|
|
- /// ## Platform-specific
|
|
|
- ///
|
|
|
- /// - **Linux:** Unsupported.
|
|
|
- pub fn parent<W: raw_window_handle::HasRawWindowHandle>(mut self, parent: &W) -> Self {
|
|
|
- self.0 = self.0.set_parent(parent);
|
|
|
- self
|
|
|
- }
|
|
|
-
|
|
|
- /// Set the set of button that will be displayed on the dialog.
|
|
|
- pub fn buttons(mut self, buttons: MessageDialogButtons) -> Self {
|
|
|
- self.0 = self.0.set_buttons(buttons.into());
|
|
|
- self
|
|
|
- }
|
|
|
-
|
|
|
- /// Set type of a dialog.
|
|
|
- ///
|
|
|
- /// Depending on the system it can result in type specific icon to show up,
|
|
|
- /// the will inform user it message is a error, warning or just information.
|
|
|
- pub fn kind(mut self, kind: MessageDialogKind) -> Self {
|
|
|
- self.0 = self.0.set_level(kind.into());
|
|
|
- self
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-/// Options for action buttons on message dialogs.
|
|
|
-#[non_exhaustive]
|
|
|
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
-pub enum MessageDialogButtons {
|
|
|
- /// Ok button.
|
|
|
- Ok,
|
|
|
- /// Ok and Cancel buttons.
|
|
|
- OkCancel,
|
|
|
- /// Yes and No buttons.
|
|
|
- YesNo,
|
|
|
- /// OK button with customized text.
|
|
|
- OkWithLabel(String),
|
|
|
- /// Ok and Cancel buttons with customized text.
|
|
|
- OkCancelWithLabels(String, String),
|
|
|
-}
|
|
|
-
|
|
|
-impl From<MessageDialogButtons> for rfd::MessageButtons {
|
|
|
- fn from(kind: MessageDialogButtons) -> Self {
|
|
|
- match kind {
|
|
|
- MessageDialogButtons::Ok => Self::Ok,
|
|
|
- MessageDialogButtons::OkCancel => Self::OkCancel,
|
|
|
- MessageDialogButtons::YesNo => Self::YesNo,
|
|
|
- MessageDialogButtons::OkWithLabel(ok_text) => Self::OkCustom(ok_text),
|
|
|
- MessageDialogButtons::OkCancelWithLabels(ok_text, cancel_text) => {
|
|
|
- Self::OkCancelCustom(ok_text, cancel_text)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/// Types of message, ask and confirm dialogs.
|
|
|
-#[non_exhaustive]
|
|
|
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
|
|
-pub enum MessageDialogKind {
|
|
|
- /// Information dialog.
|
|
|
- Info,
|
|
|
- /// Warning dialog.
|
|
|
- Warning,
|
|
|
- /// Error dialog.
|
|
|
- Error,
|
|
|
-}
|
|
|
-
|
|
|
-impl From<MessageDialogKind> for rfd::MessageLevel {
|
|
|
- fn from(kind: MessageDialogKind) -> Self {
|
|
|
- match kind {
|
|
|
- MessageDialogKind::Info => Self::Info,
|
|
|
- MessageDialogKind::Warning => Self::Warning,
|
|
|
- MessageDialogKind::Error => Self::Error,
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/// Blocking interfaces for the dialog APIs.
|
|
|
-///
|
|
|
-/// The blocking APIs will block the current thread to execute instead of relying on callback closures,
|
|
|
-/// which makes them easier to use.
|
|
|
-///
|
|
|
-/// **NOTE:** You cannot block the main thread when executing the dialog APIs, so you must use the [`crate::api::dialog`] methods instead.
|
|
|
-/// Examples of main thread context are the [`crate::App::run`] closure and non-async commands.
|
|
|
-pub mod blocking {
|
|
|
- use super::{MessageDialogButtons, MessageDialogKind};
|
|
|
- use crate::{Runtime, Window};
|
|
|
- use std::path::{Path, PathBuf};
|
|
|
- use std::sync::mpsc::sync_channel;
|
|
|
-
|
|
|
- file_dialog_builder!();
|
|
|
- message_dialog_builder!();
|
|
|
-
|
|
|
- impl FileDialogBuilder {
|
|
|
- /// Shows the dialog to select a single file.
|
|
|
- /// This is a blocking operation,
|
|
|
- /// and should *NOT* be used when running on the main thread context.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::blocking::FileDialogBuilder;
|
|
|
- /// #[tauri::command]
|
|
|
- /// async fn my_command() {
|
|
|
- /// let file_path = FileDialogBuilder::new().pick_file();
|
|
|
- /// // do something with the optional file path here
|
|
|
- /// // the file path is `None` if the user closed the dialog
|
|
|
- /// }
|
|
|
- /// ```
|
|
|
- pub fn pick_file(self) -> Option<PathBuf> {
|
|
|
- #[allow(clippy::let_and_return)]
|
|
|
- let response = run_dialog_sync!(self.0.pick_file());
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- let response = response.map(|p| p.path().to_path_buf());
|
|
|
- response
|
|
|
- }
|
|
|
-
|
|
|
- /// Shows the dialog to select multiple files.
|
|
|
- /// This is a blocking operation,
|
|
|
- /// and should *NOT* be used when running on the main thread context.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::blocking::FileDialogBuilder;
|
|
|
- /// #[tauri::command]
|
|
|
- /// async fn my_command() {
|
|
|
- /// let file_path = FileDialogBuilder::new().pick_files();
|
|
|
- /// // do something with the optional file paths here
|
|
|
- /// // the file paths value is `None` if the user closed the dialog
|
|
|
- /// }
|
|
|
- /// ```
|
|
|
- pub fn pick_files(self) -> Option<Vec<PathBuf>> {
|
|
|
- #[allow(clippy::let_and_return)]
|
|
|
- let response = run_dialog_sync!(self.0.pick_files());
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- let response =
|
|
|
- response.map(|paths| paths.into_iter().map(|p| p.path().to_path_buf()).collect());
|
|
|
- response
|
|
|
- }
|
|
|
-
|
|
|
- /// Shows the dialog to select a single folder.
|
|
|
- /// This is a blocking operation,
|
|
|
- /// and should *NOT* be used when running on the main thread context.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::blocking::FileDialogBuilder;
|
|
|
- /// #[tauri::command]
|
|
|
- /// async fn my_command() {
|
|
|
- /// let folder_path = FileDialogBuilder::new().pick_folder();
|
|
|
- /// // do something with the optional folder path here
|
|
|
- /// // the folder path is `None` if the user closed the dialog
|
|
|
- /// }
|
|
|
- /// ```
|
|
|
- pub fn pick_folder(self) -> Option<PathBuf> {
|
|
|
- #[allow(clippy::let_and_return)]
|
|
|
- let response = run_dialog_sync!(self.0.pick_folder());
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- let response = response.map(|p| p.path().to_path_buf());
|
|
|
- response
|
|
|
- }
|
|
|
-
|
|
|
- /// Shows the dialog to select multiple folders.
|
|
|
- /// This is a blocking operation,
|
|
|
- /// and should *NOT* be used when running on the main thread context.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::blocking::FileDialogBuilder;
|
|
|
- /// #[tauri::command]
|
|
|
- /// async fn my_command() {
|
|
|
- /// let folder_paths = FileDialogBuilder::new().pick_folders();
|
|
|
- /// // do something with the optional folder paths here
|
|
|
- /// // the folder paths value is `None` if the user closed the dialog
|
|
|
- /// }
|
|
|
- /// ```
|
|
|
- pub fn pick_folders(self) -> Option<Vec<PathBuf>> {
|
|
|
- #[allow(clippy::let_and_return)]
|
|
|
- let response = run_dialog_sync!(self.0.pick_folders());
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- let response =
|
|
|
- response.map(|paths| paths.into_iter().map(|p| p.path().to_path_buf()).collect());
|
|
|
- response
|
|
|
- }
|
|
|
-
|
|
|
- /// Shows the dialog to save a file.
|
|
|
- /// This is a blocking operation,
|
|
|
- /// and should *NOT* be used when running on the main thread context.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::blocking::FileDialogBuilder;
|
|
|
- /// #[tauri::command]
|
|
|
- /// async fn my_command() {
|
|
|
- /// let file_path = FileDialogBuilder::new().save_file();
|
|
|
- /// // do something with the optional file path here
|
|
|
- /// // the file path is `None` if the user closed the dialog
|
|
|
- /// }
|
|
|
- /// ```
|
|
|
- pub fn save_file(self) -> Option<PathBuf> {
|
|
|
- #[allow(clippy::let_and_return)]
|
|
|
- let response = run_dialog_sync!(self.0.save_file());
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- let response = response.map(|p| p.path().to_path_buf());
|
|
|
- response
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- impl MessageDialogBuilder {
|
|
|
- //// Shows a message dialog.
|
|
|
- ///
|
|
|
- /// - In `Ok` dialog, it will return `true` when `OK` was pressed.
|
|
|
- /// - In `OkCancel` dialog, it will return `true` when `OK` was pressed.
|
|
|
- /// - In `YesNo` dialog, it will return `true` when `Yes` was pressed.
|
|
|
- pub fn show(self) -> bool {
|
|
|
- let (tx, rx) = sync_channel(1);
|
|
|
- let f = move |response| {
|
|
|
- tx.send(response).unwrap();
|
|
|
- };
|
|
|
- run_dialog!(self.0.show(), f);
|
|
|
- rx.recv().unwrap()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Displays a dialog with a message and an optional title with a "yes" and a "no" button and wait for it to be closed.
|
|
|
- ///
|
|
|
- /// This is a blocking operation,
|
|
|
- /// and should *NOT* be used when running on the main thread context.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::blocking::ask;
|
|
|
- /// # let app = tauri::Builder::default().build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json")).unwrap();
|
|
|
- /// # let window = tauri::Manager::get_window(&app, "main").unwrap();
|
|
|
- /// let answer = ask(Some(&window), "Tauri", "Is Tauri awesome?");
|
|
|
- /// // do something with `answer`
|
|
|
- /// ```
|
|
|
- #[allow(unused_variables)]
|
|
|
- pub fn ask<R: Runtime>(
|
|
|
- parent_window: Option<&Window<R>>,
|
|
|
- title: impl AsRef<str>,
|
|
|
- message: impl AsRef<str>,
|
|
|
- ) -> bool {
|
|
|
- run_message_dialog(parent_window, title, message, rfd::MessageButtons::YesNo)
|
|
|
- }
|
|
|
-
|
|
|
- /// Displays a dialog with a message and an optional title with an "ok" and a "cancel" button and wait for it to be closed.
|
|
|
- ///
|
|
|
- /// This is a blocking operation,
|
|
|
- /// and should *NOT* be used when running on the main thread context.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::blocking::confirm;
|
|
|
- /// # let app = tauri::Builder::default().build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json")).unwrap();
|
|
|
- /// # let window = tauri::Manager::get_window(&app, "main").unwrap();
|
|
|
- /// let answer = confirm(Some(&window), "Tauri", "Are you sure?");
|
|
|
- /// // do something with `answer`
|
|
|
- /// ```
|
|
|
- #[allow(unused_variables)]
|
|
|
- pub fn confirm<R: Runtime>(
|
|
|
- parent_window: Option<&Window<R>>,
|
|
|
- title: impl AsRef<str>,
|
|
|
- message: impl AsRef<str>,
|
|
|
- ) -> bool {
|
|
|
- run_message_dialog(parent_window, title, message, rfd::MessageButtons::OkCancel)
|
|
|
- }
|
|
|
-
|
|
|
- /// Displays a message dialog and wait for it to be closed.
|
|
|
- ///
|
|
|
- /// This is a blocking operation,
|
|
|
- /// and should *NOT* be used when running on the main thread context.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::blocking::message;
|
|
|
- /// # let app = tauri::Builder::default().build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json")).unwrap();
|
|
|
- /// # let window = tauri::Manager::get_window(&app, "main").unwrap();
|
|
|
- /// message(Some(&window), "Tauri", "Tauri is awesome!");
|
|
|
- /// ```
|
|
|
- #[allow(unused_variables)]
|
|
|
- pub fn message<R: Runtime>(
|
|
|
- parent_window: Option<&Window<R>>,
|
|
|
- title: impl AsRef<str>,
|
|
|
- message: impl AsRef<str>,
|
|
|
- ) {
|
|
|
- let _ = run_message_dialog(parent_window, title, message, rfd::MessageButtons::Ok);
|
|
|
- }
|
|
|
-
|
|
|
- #[allow(unused_variables)]
|
|
|
- fn run_message_dialog<R: Runtime>(
|
|
|
- parent_window: Option<&Window<R>>,
|
|
|
- title: impl AsRef<str>,
|
|
|
- message: impl AsRef<str>,
|
|
|
- buttons: rfd::MessageButtons,
|
|
|
- ) -> bool {
|
|
|
- let (tx, rx) = sync_channel(1);
|
|
|
- super::nonblocking::run_message_dialog(
|
|
|
- parent_window,
|
|
|
- title,
|
|
|
- message,
|
|
|
- buttons,
|
|
|
- MessageDialogKind::Info,
|
|
|
- move |response| {
|
|
|
- tx.send(response).unwrap();
|
|
|
- },
|
|
|
- );
|
|
|
- rx.recv().unwrap()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-mod nonblocking {
|
|
|
- use super::{MessageDialogButtons, MessageDialogKind};
|
|
|
- use crate::{Runtime, Window};
|
|
|
- use std::path::{Path, PathBuf};
|
|
|
-
|
|
|
- file_dialog_builder!();
|
|
|
- message_dialog_builder!();
|
|
|
-
|
|
|
- impl FileDialogBuilder {
|
|
|
- /// Shows the dialog to select a single file.
|
|
|
- /// This is not a blocking operation,
|
|
|
- /// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
|
|
- ///
|
|
|
- /// For usage in other contexts such as commands, prefer [`Self::pick_file`].
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::FileDialogBuilder;
|
|
|
- /// tauri::Builder::default()
|
|
|
- /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
|
|
- /// .expect("failed to build tauri app")
|
|
|
- /// .run(|_app, _event| {
|
|
|
- /// FileDialogBuilder::new().pick_file(|file_path| {
|
|
|
- /// // do something with the optional file path here
|
|
|
- /// // the file path is `None` if the user closed the dialog
|
|
|
- /// })
|
|
|
- /// })
|
|
|
- /// ```
|
|
|
- pub fn pick_file<F: FnOnce(Option<PathBuf>) + Send + 'static>(self, f: F) {
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- let f = |path: Option<rfd::FileHandle>| f(path.map(|p| p.path().to_path_buf()));
|
|
|
- run_file_dialog!(self.0.pick_file(), f)
|
|
|
- }
|
|
|
-
|
|
|
- /// Shows the dialog to select multiple files.
|
|
|
- /// This is not a blocking operation,
|
|
|
- /// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::FileDialogBuilder;
|
|
|
- /// tauri::Builder::default()
|
|
|
- /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
|
|
- /// .expect("failed to build tauri app")
|
|
|
- /// .run(|_app, _event| {
|
|
|
- /// FileDialogBuilder::new().pick_files(|file_paths| {
|
|
|
- /// // do something with the optional file paths here
|
|
|
- /// // the file paths value is `None` if the user closed the dialog
|
|
|
- /// })
|
|
|
- /// })
|
|
|
- /// ```
|
|
|
- pub fn pick_files<F: FnOnce(Option<Vec<PathBuf>>) + Send + 'static>(self, f: F) {
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- let f = |paths: Option<Vec<rfd::FileHandle>>| {
|
|
|
- f(paths.map(|list| list.into_iter().map(|p| p.path().to_path_buf()).collect()))
|
|
|
- };
|
|
|
- run_file_dialog!(self.0.pick_files(), f)
|
|
|
- }
|
|
|
-
|
|
|
- /// Shows the dialog to select a single folder.
|
|
|
- /// This is not a blocking operation,
|
|
|
- /// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::FileDialogBuilder;
|
|
|
- /// tauri::Builder::default()
|
|
|
- /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
|
|
- /// .expect("failed to build tauri app")
|
|
|
- /// .run(|_app, _event| {
|
|
|
- /// FileDialogBuilder::new().pick_folder(|folder_path| {
|
|
|
- /// // do something with the optional folder path here
|
|
|
- /// // the folder path is `None` if the user closed the dialog
|
|
|
- /// })
|
|
|
- /// })
|
|
|
- /// ```
|
|
|
- pub fn pick_folder<F: FnOnce(Option<PathBuf>) + Send + 'static>(self, f: F) {
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- let f = |path: Option<rfd::FileHandle>| f(path.map(|p| p.path().to_path_buf()));
|
|
|
- run_file_dialog!(self.0.pick_folder(), f)
|
|
|
- }
|
|
|
-
|
|
|
- /// Shows the dialog to select multiple folders.
|
|
|
- /// This is not a blocking operation,
|
|
|
- /// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::FileDialogBuilder;
|
|
|
- /// tauri::Builder::default()
|
|
|
- /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
|
|
- /// .expect("failed to build tauri app")
|
|
|
- /// .run(|_app, _event| {
|
|
|
- /// FileDialogBuilder::new().pick_folders(|file_paths| {
|
|
|
- /// // do something with the optional folder paths here
|
|
|
- /// // the folder paths value is `None` if the user closed the dialog
|
|
|
- /// })
|
|
|
- /// })
|
|
|
- /// ```
|
|
|
- pub fn pick_folders<F: FnOnce(Option<Vec<PathBuf>>) + Send + 'static>(self, f: F) {
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- let f = |paths: Option<Vec<rfd::FileHandle>>| {
|
|
|
- f(paths.map(|list| list.into_iter().map(|p| p.path().to_path_buf()).collect()))
|
|
|
- };
|
|
|
- run_file_dialog!(self.0.pick_folders(), f)
|
|
|
- }
|
|
|
-
|
|
|
- /// Shows the dialog to save a file.
|
|
|
- ///
|
|
|
- /// This is not a blocking operation,
|
|
|
- /// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::FileDialogBuilder;
|
|
|
- /// tauri::Builder::default()
|
|
|
- /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
|
|
- /// .expect("failed to build tauri app")
|
|
|
- /// .run(|_app, _event| {
|
|
|
- /// FileDialogBuilder::new().save_file(|file_path| {
|
|
|
- /// // do something with the optional file path here
|
|
|
- /// // the file path is `None` if the user closed the dialog
|
|
|
- /// })
|
|
|
- /// })
|
|
|
- /// ```
|
|
|
- pub fn save_file<F: FnOnce(Option<PathBuf>) + Send + 'static>(self, f: F) {
|
|
|
- #[cfg(not(target_os = "linux"))]
|
|
|
- let f = |path: Option<rfd::FileHandle>| f(path.map(|p| p.path().to_path_buf()));
|
|
|
- run_file_dialog!(self.0.save_file(), f)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- impl MessageDialogBuilder {
|
|
|
- /// Shows a message dialog:
|
|
|
- ///
|
|
|
- /// - In `Ok` dialog, it will call the closure with `true` when `OK` was pressed
|
|
|
- /// - In `OkCancel` dialog, it will call the closure with `true` when `OK` was pressed
|
|
|
- /// - In `YesNo` dialog, it will call the closure with `true` when `Yes` was pressed
|
|
|
- pub fn show<F: FnOnce(bool) + Send + 'static>(self, f: F) {
|
|
|
- run_dialog!(self.0.show(), f);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// Displays a non-blocking dialog with a message and an optional title with a "yes" and a "no" button.
|
|
|
- ///
|
|
|
- /// This is not a blocking operation,
|
|
|
- /// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::ask;
|
|
|
- /// # let app = tauri::Builder::default().build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json")).unwrap();
|
|
|
- /// # let window = tauri::Manager::get_window(&app, "main").unwrap();
|
|
|
- /// ask(Some(&window), "Tauri", "Is Tauri awesome?", |answer| {
|
|
|
- /// // do something with `answer`
|
|
|
- /// });
|
|
|
- /// ```
|
|
|
- #[allow(unused_variables)]
|
|
|
- pub fn ask<R: Runtime, F: FnOnce(bool) + Send + 'static>(
|
|
|
- parent_window: Option<&Window<R>>,
|
|
|
- title: impl AsRef<str>,
|
|
|
- message: impl AsRef<str>,
|
|
|
- f: F,
|
|
|
- ) {
|
|
|
- run_message_dialog(
|
|
|
- parent_window,
|
|
|
- title,
|
|
|
- message,
|
|
|
- rfd::MessageButtons::YesNo,
|
|
|
- MessageDialogKind::Info,
|
|
|
- f,
|
|
|
- )
|
|
|
- }
|
|
|
-
|
|
|
- /// Displays a non-blocking dialog with a message and an optional title with an "ok" and a "cancel" button.
|
|
|
- ///
|
|
|
- /// This is not a blocking operation,
|
|
|
- /// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::confirm;
|
|
|
- /// # let app = tauri::Builder::default().build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json")).unwrap();
|
|
|
- /// # let window = tauri::Manager::get_window(&app, "main").unwrap();
|
|
|
- /// confirm(Some(&window), "Tauri", "Are you sure?", |answer| {
|
|
|
- /// // do something with `answer`
|
|
|
- /// });
|
|
|
- /// ```
|
|
|
- #[allow(unused_variables)]
|
|
|
- pub fn confirm<R: Runtime, F: FnOnce(bool) + Send + 'static>(
|
|
|
- parent_window: Option<&Window<R>>,
|
|
|
- title: impl AsRef<str>,
|
|
|
- message: impl AsRef<str>,
|
|
|
- f: F,
|
|
|
- ) {
|
|
|
- run_message_dialog(
|
|
|
- parent_window,
|
|
|
- title,
|
|
|
- message,
|
|
|
- rfd::MessageButtons::OkCancel,
|
|
|
- MessageDialogKind::Info,
|
|
|
- f,
|
|
|
- )
|
|
|
- }
|
|
|
-
|
|
|
- /// Displays a non-blocking message dialog.
|
|
|
- ///
|
|
|
- /// This is not a blocking operation,
|
|
|
- /// and should be used when running on the main thread to avoid deadlocks with the event loop.
|
|
|
- ///
|
|
|
- /// # Examples
|
|
|
- ///
|
|
|
- /// ```rust,no_run
|
|
|
- /// use tauri::api::dialog::message;
|
|
|
- /// # let app = tauri::Builder::default().build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json")).unwrap();
|
|
|
- /// # let window = tauri::Manager::get_window(&app, "main").unwrap();
|
|
|
- /// message(Some(&window), "Tauri", "Tauri is awesome!");
|
|
|
- /// ```
|
|
|
- #[allow(unused_variables)]
|
|
|
- pub fn message<R: Runtime>(
|
|
|
- parent_window: Option<&Window<R>>,
|
|
|
- title: impl AsRef<str>,
|
|
|
- message: impl AsRef<str>,
|
|
|
- ) {
|
|
|
- run_message_dialog(
|
|
|
- parent_window,
|
|
|
- title,
|
|
|
- message,
|
|
|
- rfd::MessageButtons::Ok,
|
|
|
- MessageDialogKind::Info,
|
|
|
- |_| {},
|
|
|
- )
|
|
|
- }
|
|
|
-
|
|
|
- #[allow(unused_variables)]
|
|
|
- pub(crate) fn run_message_dialog<R: Runtime, F: FnOnce(bool) + Send + 'static>(
|
|
|
- parent_window: Option<&Window<R>>,
|
|
|
- title: impl AsRef<str>,
|
|
|
- message: impl AsRef<str>,
|
|
|
- buttons: rfd::MessageButtons,
|
|
|
- level: MessageDialogKind,
|
|
|
- f: F,
|
|
|
- ) {
|
|
|
- let title = title.as_ref().to_string();
|
|
|
- let message = message.as_ref().to_string();
|
|
|
- #[allow(unused_mut)]
|
|
|
- let mut builder = rfd::MessageDialog::new()
|
|
|
- .set_title(&title)
|
|
|
- .set_description(&message)
|
|
|
- .set_buttons(buttons)
|
|
|
- .set_level(level.into());
|
|
|
-
|
|
|
- #[cfg(any(windows, target_os = "macos"))]
|
|
|
- {
|
|
|
- if let Some(window) = parent_window {
|
|
|
- builder = builder.set_parent(window);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- run_dialog!(builder.show(), f)
|
|
|
- }
|
|
|
-}
|