egui_file_dialog/
create_directory_dialog.rs1use std::path::{Path, PathBuf};
2use std::sync::Arc;
3
4use crate::{FileDialogConfig, FileDialogLabels, FileSystem};
5
6pub struct CreateDirectoryResponse {
7 directory: Option<PathBuf>,
9}
10
11impl CreateDirectoryResponse {
12 pub fn new(directory: &Path) -> Self {
14 Self {
15 directory: Some(directory.to_path_buf()),
16 }
17 }
18
19 pub const fn new_empty() -> Self {
21 Self { directory: None }
22 }
23
24 pub fn directory(&self) -> Option<PathBuf> {
27 self.directory.clone()
28 }
29}
30
31#[derive(Debug)]
33pub struct CreateDirectoryDialog {
34 open: bool,
36 init: bool,
39 directory: Option<PathBuf>,
41
42 input: String,
44 error: Option<String>,
46 scroll_to_error: bool,
48 request_focus: bool,
50
51 file_system: Arc<dyn FileSystem + Send + Sync>,
52}
53
54impl CreateDirectoryDialog {
55 pub fn from_filesystem(file_system: Arc<dyn FileSystem + Send + Sync>) -> Self {
57 Self {
58 open: false,
59 init: false,
60 directory: None,
61
62 input: String::new(),
63 error: None,
64 scroll_to_error: false,
65 request_focus: true,
66 file_system,
67 }
68 }
69
70 pub fn open(&mut self, directory: PathBuf) {
72 self.reset();
73
74 self.open = true;
75 self.init = true;
76 self.directory = Some(directory);
77 }
78
79 pub fn close(&mut self) {
81 self.reset();
82 }
83
84 pub fn submit(&mut self) -> CreateDirectoryResponse {
86 self.request_focus = true;
88
89 if self.error.is_none() {
90 return self.create_directory();
91 }
92
93 CreateDirectoryResponse::new_empty()
94 }
95
96 pub fn update(
99 &mut self,
100 ui: &mut egui::Ui,
101 config: &FileDialogConfig,
102 ) -> CreateDirectoryResponse {
103 if !self.open {
104 return CreateDirectoryResponse::new_empty();
105 }
106
107 let mut result = CreateDirectoryResponse::new_empty();
108
109 ui.horizontal(|ui| {
110 ui.label(&config.default_folder_icon);
111
112 let text_edit_response = ui.text_edit_singleline(&mut self.input);
113
114 if self.init {
115 text_edit_response.scroll_to_me(Some(egui::Align::Center));
116 text_edit_response.request_focus();
117
118 self.error = self.validate_input(&config.labels);
119 self.init = false;
120 self.request_focus = false;
121 }
122
123 if self.request_focus {
124 text_edit_response.request_focus();
125 self.request_focus = false;
126 }
127
128 if text_edit_response.changed() {
129 self.error = self.validate_input(&config.labels);
130 }
131
132 let apply_button_response =
133 ui.add_enabled(self.error.is_none(), egui::Button::new("✔"));
134
135 if apply_button_response.clicked() {
136 result = self.submit();
137 }
138
139 if ui.button("✖").clicked()
140 || (text_edit_response.lost_focus() && !apply_button_response.contains_pointer())
141 {
142 self.close();
143 }
144 });
145
146 if let Some(err) = &self.error {
147 ui.add_space(5.0);
148
149 let response = ui
150 .horizontal_wrapped(|ui| {
151 ui.spacing_mut().item_spacing.x = 0.0;
152
153 ui.colored_label(
154 ui.style().visuals.error_fg_color,
155 format!("{} ", config.err_icon),
156 );
157
158 ui.label(err);
159 })
160 .response;
161
162 if self.scroll_to_error {
163 response.scroll_to_me(Some(egui::Align::Center));
164 self.scroll_to_error = false;
165 }
166 }
167
168 result
169 }
170
171 pub const fn is_open(&self) -> bool {
173 self.open
174 }
175
176 fn create_directory(&mut self) -> CreateDirectoryResponse {
180 if let Some(mut dir) = self.directory.clone() {
181 dir.push(self.input.as_str());
182
183 match self.file_system.create_dir(&dir) {
184 Ok(()) => {
185 self.close();
186 return CreateDirectoryResponse::new(dir.as_path());
187 }
188 Err(err) => {
189 self.error = Some(self.create_error(format!("Error: {err}").as_str()));
190 return CreateDirectoryResponse::new_empty();
191 }
192 }
193 }
194
195 self.error = Some(self.create_error("No directory given"));
199
200 CreateDirectoryResponse::new_empty()
201 }
202
203 fn validate_input(&mut self, labels: &FileDialogLabels) -> Option<String> {
206 if self.input.is_empty() {
207 return Some(self.create_error(&labels.err_empty_file_name));
208 }
209
210 if let Some(mut x) = self.directory.clone() {
211 x.push(self.input.as_str());
212
213 if x.is_dir() {
214 return Some(self.create_error(&labels.err_directory_exists));
215 }
216 if x.is_file() {
217 return Some(self.create_error(&labels.err_file_exists));
218 }
219 } else {
220 return Some(self.create_error("No directory given"));
224 }
225
226 None
227 }
228
229 fn create_error(&mut self, error: &str) -> String {
231 self.scroll_to_error = true;
232 error.to_string()
233 }
234
235 fn reset(&mut self) {
238 self.open = false;
239 self.init = false;
240 self.directory = None;
241 self.input.clear();
242 self.error = None;
243 self.scroll_to_error = false;
244 }
245}