relm4_components/
save_dialog.rs1use gtk::prelude::{FileChooserExt, FileExt, NativeDialogExt};
5use relm4::{ComponentParts, ComponentSender, SimpleComponent, gtk};
6
7use std::path::PathBuf;
8
9#[derive(Clone, Debug)]
10pub struct SaveDialogSettings {
12 pub cancel_label: String,
14 pub accept_label: String,
16 pub create_folders: bool,
18 pub is_modal: bool,
20 pub filters: Vec<gtk::FileFilter>,
22}
23
24impl Default for SaveDialogSettings {
25 fn default() -> Self {
26 SaveDialogSettings {
27 accept_label: String::from("Save"),
28 cancel_label: String::from("Cancel"),
29 create_folders: true,
30 is_modal: true,
31 filters: Vec::new(),
32 }
33 }
34}
35
36#[derive(Debug)]
37pub struct SaveDialog {
39 current_name: String,
40 visible: bool,
41}
42
43#[derive(Debug, Clone)]
45pub enum SaveDialogMsg {
46 Save,
48 SaveAs(String),
50 #[doc(hidden)]
51 Hide,
52}
53
54#[derive(Debug, Clone)]
56pub enum SaveDialogResponse {
57 Accept(PathBuf),
59 Cancel,
61}
62
63#[relm4::component(pub)]
65impl SimpleComponent for SaveDialog {
66 type Init = SaveDialogSettings;
67
68 type Input = SaveDialogMsg;
69 type Output = SaveDialogResponse;
70
71 view! {
72 gtk::FileChooserNative {
73 set_action: gtk::FileChooserAction::Save,
74
75 set_create_folders: settings.create_folders,
76 set_modal: settings.is_modal,
77 set_accept_label: Some(&settings.accept_label),
78 set_cancel_label: Some(&settings.cancel_label),
79 #[iterate]
80 add_filter: &settings.filters,
81
82 #[watch]
83 set_current_name: &model.current_name,
84 #[watch]
85 set_visible: model.visible,
86
87 connect_response[sender] => move |dialog, res_ty| {
88 match res_ty {
89 gtk::ResponseType::Accept => {
90 if let Some(file) = dialog.file()
91 && let Some(path) = file.path() {
92 sender.output(SaveDialogResponse::Accept(path)).unwrap();
93 sender.input(SaveDialogMsg::Hide);
94 return;
95 }
96 sender.output(SaveDialogResponse::Cancel).unwrap();
97 }
98 _ => sender.output(SaveDialogResponse::Cancel).unwrap(),
99 }
100 sender.input(SaveDialogMsg::Hide);
101 }
102 }
103 }
104
105 fn init(
106 settings: Self::Init,
107 root: Self::Root,
108 sender: ComponentSender<Self>,
109 ) -> ComponentParts<Self> {
110 let model = SaveDialog {
111 current_name: String::new(),
112 visible: false,
113 };
114
115 let widgets = view_output!();
116
117 ComponentParts { model, widgets }
118 }
119
120 fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
121 match message {
122 SaveDialogMsg::Save => {
123 self.current_name = String::new();
124 self.visible = true;
125 }
126 SaveDialogMsg::SaveAs(file_name) => {
127 self.current_name = file_name;
128 self.visible = true;
129 }
130 SaveDialogMsg::Hide => {
131 self.visible = false;
132 }
133 }
134 }
135}