#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MessageLevel {
Info,
Warning,
Error,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DialogResult {
FilePaths(Vec<String>),
Confirmed,
Cancelled,
}
#[allow(unused_variables)]
pub fn open_file_dialog(title: &str, filters: &[(&str, &str)], multiple: bool) -> DialogResult {
#[cfg(feature = "dialogs")]
{
let mut dialog = rfd::FileDialog::new().set_title(title);
for (desc, ext) in filters {
if *ext == "*" {
dialog = dialog.add_filter(*desc, &["*"]);
} else {
dialog = dialog.add_filter(*desc, &[ext]);
}
}
if multiple {
match dialog.pick_files() {
Some(paths) => DialogResult::FilePaths(
paths
.into_iter()
.filter_map(|p| p.to_str().map(|s| s.to_owned()))
.collect(),
),
None => DialogResult::Cancelled,
}
} else {
match dialog.pick_file() {
Some(path) => {
let s = path.to_str().map(|s| s.to_owned()).unwrap_or_default();
DialogResult::FilePaths(vec![s])
}
None => DialogResult::Cancelled,
}
}
}
#[cfg(not(feature = "dialogs"))]
{
DialogResult::Cancelled
}
}
#[allow(unused_variables)]
pub fn save_file_dialog(
title: &str,
default_name: Option<&str>,
filters: &[(&str, &str)],
) -> DialogResult {
#[cfg(feature = "dialogs")]
{
let mut dialog = rfd::FileDialog::new().set_title(title);
if let Some(name) = default_name {
dialog = dialog.set_file_name(name);
}
for (desc, ext) in filters {
dialog = dialog.add_filter(*desc, &[ext]);
}
match dialog.save_file() {
Some(path) => {
let s = path.to_str().map(|s| s.to_owned()).unwrap_or_default();
DialogResult::FilePaths(vec![s])
}
None => DialogResult::Cancelled,
}
}
#[cfg(not(feature = "dialogs"))]
{
DialogResult::Cancelled
}
}
#[allow(unused_variables)]
pub fn message_dialog(title: &str, message: &str, level: MessageLevel) -> DialogResult {
#[cfg(feature = "dialogs")]
{
let level_rfd = match level {
MessageLevel::Info => rfd::MessageLevel::Info,
MessageLevel::Warning => rfd::MessageLevel::Warning,
MessageLevel::Error => rfd::MessageLevel::Error,
};
rfd::MessageDialog::new()
.set_title(title)
.set_description(message)
.set_level(level_rfd)
.set_buttons(rfd::MessageButtons::Ok)
.show();
DialogResult::Confirmed
}
#[cfg(not(feature = "dialogs"))]
{
DialogResult::Confirmed
}
}
#[allow(unused_variables)]
pub fn confirm_dialog(title: &str, message: &str) -> DialogResult {
#[cfg(feature = "dialogs")]
{
let confirmed = rfd::MessageDialog::new()
.set_title(title)
.set_description(message)
.set_level(rfd::MessageLevel::Info)
.set_buttons(rfd::MessageButtons::YesNo)
.show()
== rfd::MessageDialogResult::Yes;
if confirmed {
DialogResult::Confirmed
} else {
DialogResult::Cancelled
}
}
#[cfg(not(feature = "dialogs"))]
{
DialogResult::Cancelled
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn message_level_enum_variants() {
assert_ne!(MessageLevel::Info, MessageLevel::Warning);
assert_ne!(MessageLevel::Warning, MessageLevel::Error);
}
#[test]
fn dialog_result_eq() {
assert_eq!(DialogResult::Confirmed, DialogResult::Confirmed);
assert_eq!(DialogResult::Cancelled, DialogResult::Cancelled);
let paths = DialogResult::FilePaths(vec!["/tmp/foo.rs".into()]);
assert_eq!(paths, DialogResult::FilePaths(vec!["/tmp/foo.rs".into()]));
}
#[test]
#[cfg_attr(
feature = "dialogs",
ignore = "rfd requires main thread on macOS/Windows"
)]
fn open_file_dialog_no_feature_returns_cancelled() {
let result = open_file_dialog("pick", &[("All", "*")], false);
let _ = result;
}
#[test]
#[cfg_attr(
feature = "dialogs",
ignore = "rfd requires main thread on macOS/Windows"
)]
fn save_file_dialog_no_feature_returns_cancelled() {
let result = save_file_dialog("save", Some("output.txt"), &[("Text", "txt")]);
let _ = result;
}
#[test]
#[cfg_attr(
feature = "dialogs",
ignore = "rfd requires main thread on macOS/Windows"
)]
fn message_dialog_no_feature_returns_confirmed() {
let result = message_dialog("Title", "Body", MessageLevel::Info);
let _ = result;
}
#[test]
#[cfg_attr(
feature = "dialogs",
ignore = "rfd requires main thread on macOS/Windows"
)]
fn confirm_dialog_no_feature_returns_cancelled() {
let result = confirm_dialog("Title", "Are you sure?");
let _ = result;
}
}