use gtk::prelude::{FileChooserExt, FileExt, NativeDialogExt};
use relm4::{gtk, ComponentParts, ComponentSender, SimpleComponent};
use std::path::PathBuf;
#[derive(Clone, Debug)]
pub struct SaveDialogSettings {
pub cancel_label: String,
pub accept_label: String,
pub create_folders: bool,
pub is_modal: bool,
pub filters: Vec<gtk::FileFilter>,
}
impl Default for SaveDialogSettings {
fn default() -> Self {
SaveDialogSettings {
accept_label: String::from("Save"),
cancel_label: String::from("Cancel"),
create_folders: true,
is_modal: true,
filters: Vec::new(),
}
}
}
#[derive(Debug)]
pub struct SaveDialog {
current_name: String,
visible: bool,
}
#[derive(Debug, Clone)]
pub enum SaveDialogMsg {
Save,
SaveAs(String),
#[doc(hidden)]
Hide,
}
#[derive(Debug, Clone)]
pub enum SaveDialogResponse {
Accept(PathBuf),
Cancel,
}
#[relm4::component(pub)]
impl SimpleComponent for SaveDialog {
type Init = SaveDialogSettings;
type Input = SaveDialogMsg;
type Output = SaveDialogResponse;
view! {
gtk::FileChooserNative {
set_action: gtk::FileChooserAction::Save,
set_create_folders: settings.create_folders,
set_modal: settings.is_modal,
set_accept_label: Some(&settings.accept_label),
set_cancel_label: Some(&settings.cancel_label),
#[iterate]
add_filter: &settings.filters,
#[watch]
set_current_name: &model.current_name,
#[watch]
set_visible: model.visible,
connect_response[sender] => move |dialog, res_ty| {
match res_ty {
gtk::ResponseType::Accept => {
if let Some(file) = dialog.file() {
if let Some(path) = file.path() {
sender.output(SaveDialogResponse::Accept(path)).unwrap();
sender.input(SaveDialogMsg::Hide);
return;
}
}
sender.output(SaveDialogResponse::Cancel).unwrap();
}
_ => sender.output(SaveDialogResponse::Cancel).unwrap(),
}
sender.input(SaveDialogMsg::Hide);
}
}
}
fn init(
settings: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = SaveDialog {
current_name: String::new(),
visible: false,
};
let widgets = view_output!();
ComponentParts { model, widgets }
}
fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
match message {
SaveDialogMsg::Save => {
self.current_name = String::new();
self.visible = true;
}
SaveDialogMsg::SaveAs(file_name) => {
self.current_name = file_name;
self.visible = true;
}
SaveDialogMsg::Hide => {
self.visible = false;
}
}
}
}