native_windows_gui2/resources/
file_dialog.rs1use crate::win32::resources_helper as rh;
2use winapi::um::shobjidl::{IFileDialog, IFileOpenDialog};
3
4use crate::win32::base_helper::to_utf16;
5use crate::{ControlHandle, NwgError};
6use std::{ffi::OsString, fmt, ptr};
7
8#[derive(Copy, Clone, PartialEq, Debug)]
16pub enum FileDialogAction {
17 Open,
18 OpenDirectory,
19 Save,
20}
21
22pub struct FileDialog {
45 handle: *mut IFileDialog,
46 action: FileDialogAction,
47}
48
49impl FileDialog {
50 pub fn builder() -> FileDialogBuilder {
51 FileDialogBuilder {
52 title: None,
53 filename: None,
54 action: FileDialogAction::Save,
55 multiselect: false,
56 default_folder: None,
57 filters: None,
58 }
59 }
60
61 pub fn action(&self) -> FileDialogAction {
63 self.action
64 }
65
66 pub fn run<C: Into<ControlHandle>>(&self, parent: Option<C>) -> bool {
75 use winapi::shared::winerror::S_OK;
76
77 let parent_handle = match parent {
78 Some(p) => p
79 .into()
80 .hwnd()
81 .expect("File dialog parent must be a window control"),
82 None => ptr::null_mut(),
83 };
84
85 unsafe { (&mut *self.handle).Show(parent_handle) == S_OK }
86 }
87
88 pub fn get_selected_item(&self) -> Result<OsString, NwgError> {
97 if self.multiselect() {
98 return Err(NwgError::file_dialog(
99 "FileDialog have the multiselect flag",
100 ));
101 }
102
103 unsafe { rh::filedialog_get_item(&mut *self.handle) }
104 }
105
106 pub fn get_selected_items(&self) -> Result<Vec<OsString>, NwgError> {
114 if self.action == FileDialogAction::Save {
115 return Err(NwgError::file_dialog(
116 "Save dialog cannot have more than one item selected",
117 ));
118 }
119
120 unsafe { rh::filedialog_get_items(&mut *(self.handle as *mut IFileOpenDialog)) }
121 }
122
123 pub fn multiselect(&self) -> bool {
125 use winapi::um::shobjidl::FOS_ALLOWMULTISELECT;
126
127 unsafe {
128 let flags = rh::file_dialog_options(&mut *self.handle).unwrap_or(0);
129 flags & FOS_ALLOWMULTISELECT == FOS_ALLOWMULTISELECT
130 }
131 }
132
133 pub fn set_multiselect(&self, multiselect: bool) -> Result<(), NwgError> {
140 use winapi::um::shobjidl::FOS_ALLOWMULTISELECT;
141
142 if self.action == FileDialogAction::Save {
143 return Err(NwgError::file_dialog(
144 "Cannot set multiselect flag for a save file dialog",
145 ));
146 }
147
148 let result = unsafe {
149 rh::toggle_dialog_flags(&mut *self.handle, FOS_ALLOWMULTISELECT, multiselect)
150 };
151 match result {
152 Ok(_) => Ok(()),
153 Err(e) => Err(e),
154 }
155 }
156
157 pub fn set_default_folder<'a>(&self, folder: &'a str) -> Result<(), NwgError> {
165 unsafe {
166 let handle = &mut *self.handle;
167 rh::file_dialog_set_default_folder(handle, &folder)
168 }
169 }
170
171 pub fn set_filters<'a>(&self, filters: &'a str) -> Result<(), NwgError> {
179 unsafe {
180 let handle = &mut *self.handle;
181 rh::file_dialog_set_filters(handle, &filters)
182 }
183 }
184
185 pub fn set_title<'a>(&self, title: &'a str) {
187 unsafe {
188 let title = to_utf16(title);
189 let handle = &mut *self.handle;
190 handle.SetTitle(title.as_ptr());
191 }
192 }
193
194 pub fn set_filename<'a>(&self, filename: &'a str) {
196 unsafe {
197 let filename = to_utf16(filename);
198 let handle = &mut *self.handle;
199 handle.SetFileName(filename.as_ptr());
200 }
201 }
202
203 pub fn clear_client_data(&self) {
205 unsafe {
206 let handle = &mut *self.handle;
207 handle.ClearClientData();
208 }
209 }
210}
211
212impl fmt::Debug for FileDialog {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 write!(f, "FileDialog {{ action: {:?} }}", self.action)
215 }
216}
217
218impl Default for FileDialog {
219 fn default() -> FileDialog {
220 FileDialog {
221 handle: ptr::null_mut(),
222 action: FileDialogAction::Open,
223 }
224 }
225}
226
227impl PartialEq for FileDialog {
228 fn eq(&self, other: &Self) -> bool {
229 self.handle == other.handle && self.action == other.action
230 }
231}
232
233impl Eq for FileDialog {}
234
235pub struct FileDialogBuilder {
239 pub title: Option<String>,
240 pub filename: Option<String>,
241 pub action: FileDialogAction,
242 pub multiselect: bool,
243 pub default_folder: Option<String>,
244 pub filters: Option<String>,
245}
246
247impl FileDialogBuilder {
248 pub fn title<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
249 self.title = Some(t.into());
250 self
251 }
252
253 pub fn filename<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
254 self.filename = Some(t.into());
255 self
256 }
257
258 pub fn default_folder<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
259 self.default_folder = Some(t.into());
260 self
261 }
262
263 pub fn filters<S: Into<String>>(mut self, t: S) -> FileDialogBuilder {
264 self.filters = Some(t.into());
265 self
266 }
267
268 pub fn action(mut self, a: FileDialogAction) -> FileDialogBuilder {
269 self.action = a;
270 self
271 }
272
273 pub fn multiselect(mut self, m: bool) -> FileDialogBuilder {
274 self.multiselect = m;
275 self
276 }
277
278 pub fn build(self, out: &mut FileDialog) -> Result<(), NwgError> {
279 unsafe {
280 out.handle = rh::create_file_dialog(
281 self.action,
282 self.multiselect,
283 self.default_folder,
284 self.filters,
285 )?;
286 }
287
288 out.action = self.action;
289
290 if let Some(title) = self.title {
291 out.set_title(&title);
292 }
293
294 if let Some(filename) = self.filename {
295 out.set_filename(&filename);
296 }
297
298 Ok(())
299 }
300}