1#![allow(missing_copy_implementations)]
2
3use core::ffi::c_void;
4
5use azul_core::window::AzStringPair;
6use azul_css::{impl_option, impl_option_inner, props::basic::color::ColorU, AzString, StringVec};
7use tfd::{DefaultColorValue, MessageBoxIcon};
8
9#[derive(Debug)]
11pub struct MsgBox {
12 pub _reserved: *mut c_void,
14}
15
16#[derive(Debug)]
18pub struct FileDialog {
19 pub _reserved: *mut c_void,
21}
22
23#[derive(Debug)]
25pub struct ColorPickerDialog {
26 pub _reserved: *mut c_void,
28}
29
30#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
31#[repr(C)]
32pub enum OkCancel {
33 Ok,
34 Cancel,
35}
36
37impl From<tfd::OkCancel> for OkCancel {
38 #[inline]
39 fn from(e: tfd::OkCancel) -> Self {
40 match e {
41 tfd::OkCancel::Ok => OkCancel::Ok,
42 tfd::OkCancel::Cancel => OkCancel::Cancel,
43 }
44 }
45}
46
47impl From<OkCancel> for tfd::OkCancel {
48 #[inline]
49 fn from(e: OkCancel) -> Self {
50 match e {
51 OkCancel::Ok => tfd::OkCancel::Ok,
52 OkCancel::Cancel => tfd::OkCancel::Cancel,
53 }
54 }
55}
56
57pub fn msg_box_ok_cancel(
59 title: &str,
60 message: &str,
61 icon: MessageBoxIcon,
62 default: OkCancel,
63) -> OkCancel {
64 let msg_box = tfd::MessageBox::new(title, message)
65 .with_icon(icon)
66 .run_modal_ok_cancel(default.into());
67 msg_box.into()
68}
69
70#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
72#[repr(C)]
73pub enum YesNo {
74 Yes,
75 No,
76}
77
78impl From<YesNo> for tfd::YesNo {
79 #[inline]
80 fn from(e: YesNo) -> Self {
81 match e {
82 YesNo::Yes => tfd::YesNo::Yes,
83 YesNo::No => tfd::YesNo::No,
84 }
85 }
86}
87
88impl From<tfd::YesNo> for YesNo {
89 #[inline]
90 fn from(e: tfd::YesNo) -> Self {
91 match e {
92 tfd::YesNo::Yes => YesNo::Yes,
93 tfd::YesNo::No => YesNo::No,
94 }
95 }
96}
97
98#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
100#[repr(C)]
101pub enum MsgBoxIcon {
102 Info,
103 Warning,
104 Error,
105 Question,
106}
107
108impl From<MsgBoxIcon> for MessageBoxIcon {
109 #[inline]
110 fn from(e: MsgBoxIcon) -> Self {
111 match e {
112 MsgBoxIcon::Info => MessageBoxIcon::Info,
113 MsgBoxIcon::Warning => MessageBoxIcon::Warning,
114 MsgBoxIcon::Error => MessageBoxIcon::Error,
115 MsgBoxIcon::Question => MessageBoxIcon::Question,
116 }
117 }
118}
119
120pub fn msg_box_yes_no(title: &str, message: &str, icon: MessageBoxIcon, default: YesNo) -> YesNo {
122 let msg_box = tfd::MessageBox::new(title, message)
123 .with_icon(icon)
124 .run_modal_yes_no(default.into());
125 msg_box.into()
126}
127
128pub fn msg_box_ok(title: &str, message: &str, icon: MessageBoxIcon) {
130 let mut msg = message.to_string();
131
132 msg = msg.replace('\"', "");
133 msg = msg.replace('\'', "");
134
135 tfd::MessageBox::new(title, &msg)
136 .with_icon(icon)
137 .run_modal();
138}
139
140pub fn msg_box(content: &str) {
142 msg_box_ok("Info", content, MessageBoxIcon::Info);
143}
144
145pub fn color_picker_dialog(title: &str, default_value: Option<ColorU>) -> Option<ColorU> {
147 let rgb = default_value.map_or([0, 0, 0], |c| [c.r, c.g, c.b]);
148
149 let default_color = DefaultColorValue::RGB(rgb);
150 let result = tfd::ColorChooser::new(title)
151 .with_default_color(default_color)
152 .run_modal()?;
153
154 Some(ColorU {
155 r: result.1[0],
156 g: result.1[1],
157 b: result.1[2],
158 a: ColorU::ALPHA_OPAQUE,
159 })
160}
161
162#[derive(Debug, Clone, PartialEq, PartialOrd)]
163#[repr(C)]
164pub struct FileTypeList {
165 pub document_types: StringVec,
166 pub document_descriptor: AzString,
167}
168
169impl_option!(
170 FileTypeList,
171 OptionFileTypeList,
172 copy = false,
173 [Debug, Clone, PartialEq, PartialOrd]
174);
175
176pub fn open_file_dialog(
181 title: &str,
182 default_path: Option<&str>,
183 filter_list: Option<FileTypeList>,
184) -> Option<AzString> {
185 let mut dialog = tfd::FileDialog::new(title);
186
187 if let Some(path) = default_path {
188 dialog = dialog.with_path(path);
189 }
190
191 if let Some(filter) = filter_list {
192 let v = filter.document_types.clone().into_library_owned_vec();
193
194 let patterns: Vec<&str> = v.iter().map(|s| s.as_str()).collect();
195
196 dialog = dialog.with_filter(&patterns, filter.document_descriptor.as_str());
197 }
198
199 dialog.open_file().map(|s| s.into())
200}
201
202pub fn open_directory_dialog(title: &str, default_path: Option<&str>) -> Option<AzString> {
204 let mut dialog = tfd::FileDialog::new(title);
205
206 if let Some(path) = default_path {
207 dialog = dialog.with_path(path);
208 }
209
210 dialog.select_folder().map(|s| s.into())
211}
212
213pub fn open_multiple_files_dialog(
219 title: &str,
220 default_path: Option<&str>,
221 filter_list: Option<FileTypeList>,
222) -> Option<StringVec> {
223 let mut dialog = tfd::FileDialog::new(title).with_multiple_selection(true);
224
225 if let Some(path) = default_path {
226 dialog = dialog.with_path(path);
227 }
228
229 if let Some(filter) = filter_list {
230 let v = filter.document_types.clone().into_library_owned_vec();
231
232 let patterns: Vec<&str> = v.iter().map(|s| s.as_str()).collect();
233
234 dialog = dialog.with_filter(&patterns, filter.document_descriptor.as_str());
235 }
236
237 dialog.open_files().map(|s| s.into())
238}
239
240pub fn save_file_dialog(title: &str, default_path: Option<&str>) -> Option<AzString> {
242 let mut dialog = tfd::FileDialog::new(title);
243
244 if let Some(path) = default_path {
245 dialog = dialog.with_path(path);
246 }
247
248 dialog.save_file().map(|s| s.into())
249}