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