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);
});
});
}};
}
macro_rules! run_dialog_sync {
($e:expr) => {{
let (tx, rx) = sync_channel(0);
let cb = move |response| {
tx.send(response).unwrap();
};
run_dialog!($e, cb);
rx.recv().unwrap()
}};
}
macro_rules! file_dialog_builder {
() => {
#[derive(Debug, Default)]
pub struct FileDialogBuilder(rfd::FileDialog);
impl FileDialogBuilder {
pub fn new() -> Self {
Default::default()
}
#[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
}
#[must_use]
pub fn set_directory<P: AsRef<Path>>(mut self, directory: P) -> Self {
self.0 = self.0.set_directory(directory);
self
}
#[must_use]
pub fn set_file_name(mut self, file_name: &str) -> Self {
self.0 = self.0.set_file_name(file_name);
self
}
#[must_use]
pub fn set_parent<W: raw_window_handle::HasRawWindowHandle>(mut self, parent: &W) -> Self {
self.0 = self.0.set_parent(parent);
self
}
#[must_use]
pub fn set_title(mut self, title: &str) -> Self {
self.0 = self.0.set_title(title);
self
}
}
};
}
pub mod blocking {
use crate::{Runtime, Window};
use std::path::{Path, PathBuf};
use std::sync::mpsc::sync_channel;
file_dialog_builder!();
impl FileDialogBuilder {
pub fn pick_file(self) -> Option<PathBuf> {
run_dialog_sync!(self.0.pick_file())
}
pub fn pick_files(self) -> Option<Vec<PathBuf>> {
run_dialog_sync!(self.0.pick_files())
}
pub fn pick_folder(self) -> Option<PathBuf> {
run_dialog_sync!(self.0.pick_folder())
}
pub fn save_file(self) -> Option<PathBuf> {
run_dialog_sync!(self.0.save_file())
}
}
#[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)
}
#[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)
}
#[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,
move |response| {
tx.send(response).unwrap();
},
);
rx.recv().unwrap()
}
}
mod nonblocking {
use crate::{Runtime, Window};
use std::path::{Path, PathBuf};
file_dialog_builder!();
impl FileDialogBuilder {
pub fn pick_file<F: FnOnce(Option<PathBuf>) + Send + 'static>(self, f: F) {
run_dialog!(self.0.pick_file(), f)
}
pub fn pick_files<F: FnOnce(Option<Vec<PathBuf>>) + Send + 'static>(self, f: F) {
run_dialog!(self.0.pick_files(), f)
}
pub fn pick_folder<F: FnOnce(Option<PathBuf>) + Send + 'static>(self, f: F) {
run_dialog!(self.0.pick_folder(), f)
}
pub fn save_file<F: FnOnce(Option<PathBuf>) + Send + 'static>(self, f: F) {
run_dialog!(self.0.save_file(), f)
}
}
#[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, f)
}
#[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,
f,
)
}
#[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,
|_| {},
)
}
#[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,
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(rfd::MessageLevel::Info);
#[cfg(any(windows, target_os = "macos"))]
{
if let Some(window) = parent_window {
builder = builder.set_parent(window);
}
}
run_dialog!(builder.show(), f)
}
}