1use crate::enums::{Color, Font};
2use crate::prelude::*;
3use crate::utils::FlString;
4use fltk_sys::dialog::*;
5use std::{
6 ffi::{CStr, CString},
7 mem,
8 os::raw,
9 path::{Path, PathBuf},
10};
11
12#[repr(u8)]
14#[derive(Debug, Copy, Clone, PartialEq, Eq)]
15pub enum ColorMode {
16 Rgb = 0,
18 Byte = 1,
20 Hex = 2,
22 Hsv = 3,
24}
25
26#[derive(Debug)]
28pub struct NativeFileChooser {
29 inner: *mut Fl_Native_File_Chooser,
30}
31
32#[repr(i32)]
34#[derive(Debug, Copy, Clone, PartialEq, Eq)]
35pub enum NativeFileChooserType {
36 BrowseFile = 0,
38 BrowseDir,
40 BrowseMultiFile,
42 BrowseMultiDir,
44 BrowseSaveFile,
46 BrowseSaveDir,
48}
49
50crate::macros::widget::impl_widget_type!(NativeFileChooserType);
51
52bitflags::bitflags! {
53 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
55 pub struct NativeFileChooserOptions: i32 {
56 const NoOptions = 0;
58 const SaveAsConfirm = 1;
60 const NewFolder = 2;
62 const Preview = 4;
64 const UseFilterExt = 8;
66 }
67}
68
69#[derive(Debug, Copy, Clone)]
71pub enum NativeFileChooserAction {
72 Cancelled,
74 Success,
76}
77
78impl NativeFileChooser {
79 pub fn new(op: NativeFileChooserType) -> NativeFileChooser {
81 unsafe {
82 let file_dialog = Fl_Native_File_Chooser_new(mem::transmute(op));
83 assert!(!file_dialog.is_null());
84 NativeFileChooser { inner: file_dialog }
85 }
86 }
87
88 pub fn filename(&self) -> PathBuf {
90 assert!(!self.inner.is_null());
91 unsafe {
92 let cnt = Fl_Native_File_Chooser_count(self.inner);
93 if cnt == 0 {
94 return PathBuf::new();
95 }
96 let x = Fl_Native_File_Chooser_filenames(self.inner, 0);
97 PathBuf::from(
98 CStr::from_ptr(x as *mut raw::c_char)
99 .to_string_lossy()
100 .to_string(),
101 )
102 }
103 }
104
105 pub fn filenames(&self) -> Vec<PathBuf> {
107 assert!(!self.inner.is_null());
108 unsafe {
109 let cnt = Fl_Native_File_Chooser_count(self.inner);
110 let mut names: Vec<PathBuf> = vec![];
111 for i in 0..cnt {
112 let x = Fl_Native_File_Chooser_filenames(self.inner, i);
113 names.push(PathBuf::from(
114 CStr::from_ptr(x as *mut raw::c_char)
115 .to_string_lossy()
116 .to_string(),
117 ));
118 }
119 names
120 }
121 }
122
123 pub fn directory(&self) -> Option<PathBuf> {
125 assert!(!self.inner.is_null());
126 unsafe {
127 let x = Fl_Native_File_Chooser_directory(self.inner);
128 if x.is_null() {
129 None
130 } else {
131 Some(PathBuf::from(
132 CStr::from_ptr(x as *mut raw::c_char)
133 .to_string_lossy()
134 .to_string(),
135 ))
136 }
137 }
138 }
139
140 pub fn set_directory<P: AsRef<Path>>(&mut self, dir: &P) -> Result<(), FltkError> {
144 assert!(!self.inner.is_null());
145 self.set_directory_(dir.as_ref())
146 }
147
148 fn set_directory_(&mut self, dir: &Path) -> Result<(), FltkError> {
149 assert!(!self.inner.is_null());
150 let dir = CString::new(dir.to_str().ok_or_else(|| {
151 FltkError::Unknown(String::from("Failed to convert path to string"))
152 })?)?;
153 unsafe { Fl_Native_File_Chooser_set_directory(self.inner, dir.as_ptr()) }
154 Ok(())
155 }
156
157 pub fn show(&mut self) -> Result<NativeFileChooserAction, FltkError> {
159 assert!(!self.inner.is_null());
160 unsafe {
161 match Fl_Native_File_Chooser_show(self.inner) {
162 0 => Ok(NativeFileChooserAction::Success),
163 -1 => Err(FltkError::Unknown(self.error_message().unwrap())),
164 1 => Ok(NativeFileChooserAction::Cancelled),
165 _ => unreachable!(),
166 }
167 }
168 }
169
170 pub fn set_option(&mut self, opt: NativeFileChooserOptions) {
172 assert!(!self.inner.is_null());
173 unsafe { Fl_Native_File_Chooser_set_option(self.inner, opt.bits()) }
174 }
175
176 pub fn set_type(&mut self, op: NativeFileChooserType) {
178 assert!(!self.inner.is_null());
179 unsafe { Fl_Native_File_Chooser_set_type(self.inner, op as i32) }
180 }
181
182 pub fn set_title(&mut self, title: &str) {
184 assert!(!self.inner.is_null());
185 let title = CString::safe_new(title);
186 unsafe { Fl_Native_File_Chooser_set_title(self.inner, title.as_ptr()) }
187 }
188
189 pub fn set_filter(&mut self, f: &str) {
196 assert!(!self.inner.is_null());
197 let f = CString::safe_new(f);
198 unsafe { Fl_Native_File_Chooser_set_filter(self.inner, f.as_ptr()) }
199 }
200
201 pub fn filter(&self) -> Option<String> {
203 assert!(!self.inner.is_null());
204 unsafe {
205 let ptr = Fl_Native_File_Chooser_filter(self.inner);
206 if ptr.is_null() {
207 None
208 } else {
209 Some(
210 CStr::from_ptr(ptr as *mut raw::c_char)
211 .to_string_lossy()
212 .to_string(),
213 )
214 }
215 }
216 }
217
218 pub fn filter_value(&self) -> i32 {
220 assert!(!self.inner.is_null());
221 unsafe { Fl_Native_File_Chooser_filter_value(self.inner) }
222 }
223
224 pub fn set_filter_value(&mut self, f: i32) {
226 assert!(!self.inner.is_null());
227 unsafe { Fl_Native_File_Chooser_set_filter_value(self.inner, f) }
228 }
229
230 pub fn set_preset_file(&mut self, f: &str) {
232 assert!(!self.inner.is_null());
233 let f = CString::safe_new(f);
234 unsafe { Fl_Native_File_Chooser_set_preset_file(self.inner, f.as_ptr()) }
235 }
236
237 pub fn error_message(&self) -> Option<String> {
239 assert!(!self.inner.is_null());
240 unsafe {
241 let err_msg = Fl_Native_File_Chooser_errmsg(self.inner);
242 if err_msg.is_null() {
243 None
244 } else {
245 Some(
246 CStr::from_ptr(err_msg as *mut raw::c_char)
247 .to_string_lossy()
248 .to_string(),
249 )
250 }
251 }
252 }
253}
254
255impl Drop for NativeFileChooser {
256 fn drop(&mut self) {
257 if !self.inner.is_null() {
258 unsafe { Fl_Native_File_Chooser_delete(self.inner) }
259 self.inner = std::ptr::null_mut();
260 }
261 }
262}
263
264pub fn message(txt: &str) {
266 unsafe {
267 let txt = CString::safe_new(txt);
268 Fl_message(txt.as_ptr());
269 }
270}
271
272pub fn alert(txt: &str) {
274 unsafe {
275 let txt = CString::safe_new(txt);
276 Fl_alert(txt.as_ptr());
277 }
278}
279
280pub fn choice(txt: &str, b0: &str, b1: &str, b2: &str) -> Option<i32> {
283 unsafe {
284 let txt = CString::safe_new(txt);
285 let b0 = CString::safe_new(b0);
286 let b1 = CString::safe_new(b1);
287 let b2 = CString::safe_new(b2);
288 let ret = Fl_choice_n(txt.as_ptr(), b0.as_ptr(), b1.as_ptr(), b2.as_ptr());
289 if ret < 0 { None } else { Some(ret) }
290 }
291}
292
293pub fn input(txt: &str, deflt: &str) -> Option<String> {
296 unsafe {
297 let temp = CString::safe_new(deflt);
298 let txt = CString::safe_new(txt);
299 let x = Fl_input(txt.as_ptr(), temp.as_ptr());
300 if x.is_null() {
301 None
302 } else {
303 Some(
304 CStr::from_ptr(x as *const raw::c_char)
305 .to_string_lossy()
306 .to_string(),
307 )
308 }
309 }
310}
311
312pub fn password(txt: &str, deflt: &str) -> Option<String> {
314 unsafe {
315 let temp = CString::safe_new(deflt);
316 let txt = CString::safe_new(txt);
317 let x = Fl_password(txt.as_ptr(), temp.as_ptr());
318 if x.is_null() {
319 None
320 } else {
321 Some(
322 CStr::from_ptr(x as *const raw::c_char)
323 .to_string_lossy()
324 .to_string(),
325 )
326 }
327 }
328}
329
330#[derive(Debug)]
332pub struct HelpDialog {
333 inner: *mut Fl_Help_Dialog,
334}
335
336impl Default for HelpDialog {
337 fn default() -> Self {
338 unsafe {
339 let help_dialog = Fl_Help_Dialog_new();
340 assert!(!help_dialog.is_null());
341 HelpDialog { inner: help_dialog }
342 }
343 }
344}
345
346impl HelpDialog {
347 pub fn new(x: i32, y: i32, w: i32, h: i32) -> HelpDialog {
349 let mut temp = HelpDialog::default();
350 temp.resize(x, y, w, h);
351 temp
352 }
353
354 pub fn hide(&mut self) {
356 unsafe { Fl_Help_Dialog_hide(self.inner) }
357 }
358
359 pub fn load<P: AsRef<Path>>(&mut self, file: P) -> Result<(), FltkError> {
363 self.load_(file.as_ref())
364 }
365
366 fn load_(&mut self, file: &Path) -> Result<(), FltkError> {
367 let f = file
368 .to_str()
369 .ok_or_else(|| FltkError::Unknown(String::from("Failed to convert path to string")))?;
370 let f = CString::new(f)?;
371 unsafe {
372 match Fl_Help_Dialog_load(self.inner, f.as_ptr()) {
373 0 => Ok(()),
374 _ => Err(FltkError::Internal(FltkErrorKind::ResourceNotFound)),
375 }
376 }
377 }
378
379 pub fn position(&mut self, x: i32, y: i32) {
381 unsafe { Fl_Help_Dialog_position(self.inner, x, y) }
382 }
383
384 pub fn resize(&mut self, x: i32, y: i32, w: i32, h: i32) {
386 unsafe { Fl_Help_Dialog_resize(self.inner, x, y, w, h) }
387 }
388
389 pub fn show(&mut self) {
391 unsafe { Fl_Help_Dialog_show(self.inner) }
392 }
393
394 pub fn set_text_size(&mut self, s: i32) {
396 unsafe { Fl_Help_Dialog_set_text_size(self.inner, s) }
397 }
398
399 pub fn text_size(&self) -> i32 {
401 unsafe { Fl_Help_Dialog_text_size(self.inner) }
402 }
403
404 pub fn set_value(&mut self, f: &str) {
406 let f = CString::safe_new(f);
407 unsafe { Fl_Help_Dialog_set_value(self.inner, f.as_ptr()) }
408 }
409
410 pub fn value(&self) -> Option<String> {
412 unsafe {
413 let val = Fl_Help_Dialog_value(self.inner);
414 if val.is_null() {
415 None
416 } else {
417 Some(CStr::from_ptr(val).to_string_lossy().to_string())
418 }
419 }
420 }
421
422 pub fn visible(&self) -> bool {
424 unsafe { Fl_Help_Dialog_visible(self.inner) != 0 }
425 }
426
427 pub fn shown(&self) -> bool {
429 unsafe { Fl_Help_Dialog_visible(self.inner) != 0 }
430 }
431
432 pub fn w(&self) -> i32 {
434 unsafe { Fl_Help_Dialog_w(self.inner) }
435 }
436
437 pub fn h(&self) -> i32 {
439 unsafe { Fl_Help_Dialog_h(self.inner) }
440 }
441
442 pub fn x(&self) -> i32 {
444 unsafe { Fl_Help_Dialog_x(self.inner) }
445 }
446
447 pub fn y(&self) -> i32 {
449 unsafe { Fl_Help_Dialog_y(self.inner) }
450 }
451}
452
453impl Drop for HelpDialog {
454 fn drop(&mut self) {
455 unsafe { Fl_Help_Dialog_delete(self.inner) }
456 }
457}
458
459#[repr(i32)]
461#[derive(Debug, Copy, Clone, PartialEq, Eq)]
462pub enum BeepType {
463 Default = 0,
465 Message,
467 Error,
469 Question,
471 Password,
473 Notification,
475}
476
477pub fn beep(tp: BeepType) {
479 unsafe { Fl_beep(tp as i32) }
480}
481
482pub struct FileChooser {
526 inner: *mut Fl_File_Chooser,
527}
528
529bitflags::bitflags! {
530 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
532 pub struct FileChooserType: i32 {
533 const Single = 0;
535 const Multi = 1;
537 const Create = 2;
539 const Directory = 4;
541 }
542}
543
544impl FileChooser {
545 pub fn new<P: AsRef<Path>>(
547 dir: P,
548 pattern: &str,
549 typ: FileChooserType,
550 title: &str,
551 ) -> FileChooser {
552 Self::new_(dir.as_ref(), pattern, typ, title)
553 }
554
555 fn new_(dir: &Path, pattern: &str, typ: FileChooserType, title: &str) -> FileChooser {
556 let dir = dir.to_str().unwrap_or(".");
557 let dir = CString::safe_new(dir);
558 let pattern = CString::safe_new(pattern);
559 let title = CString::safe_new(title);
560 unsafe {
561 let ptr = Fl_File_Chooser_new(
562 dir.as_ptr(),
563 pattern.as_ptr(),
564 typ.bits(),
565 title.into_raw() as _,
566 );
567 assert!(!ptr.is_null());
568 FileChooser { inner: ptr }
569 }
570 }
571 pub unsafe fn delete(dlg: &Self) {
575 unsafe { Fl_File_Chooser_delete(dlg.inner) }
576 }
577
578 pub fn new_button(&self) -> Option<impl ButtonExt> {
580 assert!(!self.inner.is_null());
581 unsafe {
582 let ptr = Fl_File_Chooser_newButton(self.inner);
583 if ptr.is_null() {
584 None
585 } else {
586 Some(crate::button::Button::from_widget_ptr(ptr as *mut _))
587 }
588 }
589 }
590
591 pub fn preview_button(&self) -> Option<impl ButtonExt> {
593 assert!(!self.inner.is_null());
594 unsafe {
595 let ptr = Fl_File_Chooser_previewButton(self.inner);
596 if ptr.is_null() {
597 None
598 } else {
599 Some(crate::button::CheckButton::from_widget_ptr(
600 ptr as *mut fltk_sys::widget::Fl_Widget,
601 ))
602 }
603 }
604 }
605
606 pub fn show_hidden_button(&self) -> Option<impl ButtonExt> {
608 assert!(!self.inner.is_null());
609 unsafe {
610 let ptr = Fl_File_Chooser_showHiddenButton(self.inner);
611 if ptr.is_null() {
612 None
613 } else {
614 Some(crate::button::CheckButton::from_widget_ptr(
615 ptr as *mut fltk_sys::widget::Fl_Widget,
616 ))
617 }
618 }
619 }
620
621 pub fn set_callback<F: FnMut(&mut Self) + 'static>(&mut self, cb: F) {
623 assert!(!self.inner.is_null());
624 unsafe {
625 unsafe extern "C" fn shim(arg1: *mut Fl_File_Chooser, data: *mut raw::c_void) {
626 unsafe {
627 let mut wid = FileChooser { inner: arg1 };
628 let a: *mut Box<dyn FnMut(&mut FileChooser)> =
629 data as *mut Box<dyn FnMut(&mut FileChooser)>;
630 let f: &mut (dyn FnMut(&mut FileChooser)) = &mut **a;
631 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&mut wid)));
632 }
633 }
634 let _old_data = self.user_data();
635 let a: *mut Box<dyn FnMut(&mut Self)> = Box::into_raw(Box::new(Box::new(cb)));
636 let data: *mut raw::c_void = a as *mut raw::c_void;
637 let callback: Option<
638 unsafe extern "C" fn(arg1: *mut Fl_File_Chooser, data: *mut raw::c_void),
639 > = Some(shim);
640 Fl_File_Chooser_set_callback(self.inner, callback, data);
641 }
642 }
643
644 pub fn set_color(&mut self, c: Color) {
646 assert!(!self.inner.is_null());
647 unsafe { Fl_File_Chooser_set_color(self.inner, c.bits()) }
648 }
649
650 pub fn color(&self) -> Color {
652 assert!(!self.inner.is_null());
653 unsafe { mem::transmute(Fl_File_Chooser_color(self.inner)) }
654 }
655
656 pub fn count(&self) -> i32 {
658 assert!(!self.inner.is_null());
659 unsafe { Fl_File_Chooser_count(self.inner) }
660 }
661
662 pub fn set_directory<P: AsRef<Path>>(&mut self, dir: P) {
664 self.set_directory_(dir.as_ref());
665 }
666
667 fn set_directory_(&mut self, dir: &Path) {
668 assert!(!self.inner.is_null());
669 if let Some(dir) = dir.to_str() {
670 let dir = CString::safe_new(dir);
671 unsafe { Fl_File_Chooser_set_directory(self.inner, dir.as_ptr()) }
672 }
673 }
674
675 pub fn directory(&self) -> Option<PathBuf> {
677 assert!(!self.inner.is_null());
678 unsafe {
679 let ptr = Fl_File_Chooser_directory(self.inner);
680 if ptr.is_null() {
681 None
682 } else {
683 Some(PathBuf::from(
684 CStr::from_ptr(ptr as *mut raw::c_char)
685 .to_string_lossy()
686 .to_string(),
687 ))
688 }
689 }
690 }
691
692 pub fn set_filter(&mut self, pattern: &str) {
698 assert!(!self.inner.is_null());
699 let pattern = CString::safe_new(pattern);
700 unsafe { Fl_File_Chooser_set_filter(self.inner, pattern.as_ptr()) }
701 }
702
703 pub fn filter(&self) -> Option<String> {
705 assert!(!self.inner.is_null());
706 unsafe {
707 let ptr = Fl_File_Chooser_filter(self.inner);
708 if ptr.is_null() {
709 None
710 } else {
711 Some(
712 CStr::from_ptr(ptr as *mut raw::c_char)
713 .to_string_lossy()
714 .to_string(),
715 )
716 }
717 }
718 }
719
720 pub fn filter_value(&self) -> i32 {
722 assert!(!self.inner.is_null());
723 unsafe { Fl_File_Chooser_filter_value(self.inner) }
724 }
725
726 pub fn set_filter_value(&mut self, f: i32) {
728 assert!(!self.inner.is_null());
729 unsafe { Fl_File_Chooser_set_filter_value(self.inner, f) }
730 }
731
732 pub fn hide(&mut self) {
734 assert!(!self.inner.is_null());
735 unsafe { Fl_File_Chooser_hide(self.inner) }
736 }
737
738 pub fn set_icon_size(&mut self, s: u8) {
740 assert!(!self.inner.is_null());
741 unsafe { Fl_File_Chooser_set_iconsize(self.inner, s) }
742 }
743
744 pub fn icon_size(&self) -> u8 {
746 assert!(!self.inner.is_null());
747 unsafe { Fl_File_Chooser_iconsize(self.inner) }
748 }
749
750 pub fn set_label(&mut self, l: &str) {
752 assert!(!self.inner.is_null());
753 let l = CString::safe_new(l);
754 let _old = unsafe { CString::from_raw(Fl_File_Chooser_label(self.inner) as _) };
755 unsafe { Fl_File_Chooser_set_label(self.inner, l.into_raw() as _) }
756 }
757
758 pub fn label(&self) -> Option<String> {
760 assert!(!self.inner.is_null());
761 unsafe {
762 let ptr = Fl_File_Chooser_label(self.inner);
763 if ptr.is_null() {
764 None
765 } else {
766 Some(
767 CStr::from_ptr(ptr as *mut raw::c_char)
768 .to_string_lossy()
769 .to_string(),
770 )
771 }
772 }
773 }
774
775 pub fn set_ok_label(&mut self, l: &'static str) {
777 assert!(!self.inner.is_null());
778 let l = CString::safe_new(l);
779 unsafe { Fl_File_Chooser_set_ok_label(self.inner, l.into_raw() as _) }
780 }
781
782 pub fn ok_label(&self) -> Option<String> {
784 assert!(!self.inner.is_null());
785 unsafe {
786 let ptr = Fl_File_Chooser_ok_label(self.inner);
787 if ptr.is_null() {
788 None
789 } else {
790 Some(
791 CStr::from_ptr(ptr as *mut raw::c_char)
792 .to_string_lossy()
793 .to_string(),
794 )
795 }
796 }
797 }
798
799 pub fn set_preview(&mut self, e: bool) {
801 assert!(!self.inner.is_null());
802 unsafe { Fl_File_Chooser_set_preview(self.inner, i32::from(e)) }
803 }
804
805 pub fn preview(&self) -> bool {
807 assert!(!self.inner.is_null());
808 unsafe { Fl_File_Chooser_preview(self.inner) != 0 }
809 }
810
811 pub fn rescan(&mut self) {
813 assert!(!self.inner.is_null());
814 unsafe { Fl_File_Chooser_rescan(self.inner) }
815 }
816
817 pub fn rescan_keep_filename(&mut self) {
819 assert!(!self.inner.is_null());
820 unsafe { Fl_File_Chooser_rescan_keep_filename(self.inner) }
821 }
822
823 pub fn show(&mut self) {
825 assert!(!self.inner.is_null());
826 unsafe { Fl_File_Chooser_show(self.inner) }
827 }
828
829 pub fn shown(&self) -> bool {
831 assert!(!self.inner.is_null());
832 unsafe { Fl_File_Chooser_shown(self.inner) != 0 }
833 }
834
835 pub fn set_text_color(&mut self, c: Color) {
837 assert!(!self.inner.is_null());
838 unsafe { Fl_File_Chooser_set_text_color(self.inner, c.bits()) }
839 }
840
841 pub fn text_color(&self) -> Color {
843 assert!(!self.inner.is_null());
844 unsafe { mem::transmute(Fl_File_Chooser_text_color(self.inner)) }
845 }
846
847 pub fn set_text_font(&mut self, f: Font) {
849 assert!(!self.inner.is_null());
850 unsafe { Fl_File_Chooser_set_text_font(self.inner, f.bits()) }
851 }
852
853 pub fn text_font(&self) -> Font {
855 assert!(!self.inner.is_null());
856 unsafe { mem::transmute(Fl_File_Chooser_text_font(self.inner)) }
857 }
858
859 pub fn set_text_size(&mut self, s: i32) {
861 assert!(!self.inner.is_null());
862 unsafe { Fl_File_Chooser_set_text_size(self.inner, s) }
863 }
864
865 pub fn text_size(&self) -> i32 {
867 assert!(!self.inner.is_null());
868 unsafe { Fl_File_Chooser_text_size(self.inner) }
869 }
870
871 pub fn set_type(&mut self, t: FileChooserType) {
873 assert!(!self.inner.is_null());
874 unsafe { Fl_File_Chooser_set_type(self.inner, t.bits()) }
875 }
876
877 pub fn get_type(&self) -> FileChooserType {
879 assert!(!self.inner.is_null());
880 unsafe { mem::transmute(Fl_File_Chooser_type(self.inner)) }
881 }
882
883 pub unsafe fn user_data(&self) -> Option<Box<dyn FnMut()>> {
887 unsafe {
888 let ptr = Fl_File_Chooser_user_data(self.inner);
889 if ptr.is_null() {
890 None
891 } else {
892 let x = ptr as *mut Box<dyn FnMut()>;
893 let x = Box::from_raw(x);
894 Fl_File_Chooser_set_callback(self.inner, None, std::ptr::null_mut());
895 Some(*x)
896 }
897 }
898 }
899
900 pub fn value(&mut self, f: i32) -> Option<String> {
902 assert!(!self.inner.is_null());
903 let f = if f == 0 { 1 } else { f };
904 unsafe {
905 let ptr = Fl_File_Chooser_value(self.inner, f);
906 if ptr.is_null() {
907 None
908 } else {
909 Some(
910 CStr::from_ptr(ptr as *mut raw::c_char)
911 .to_string_lossy()
912 .to_string(),
913 )
914 }
915 }
916 }
917
918 pub fn set_value(&mut self, filename: &str) {
920 assert!(!self.inner.is_null());
921 let filename = CString::safe_new(filename);
922 unsafe { Fl_File_Chooser_set_value(self.inner, filename.as_ptr()) }
923 }
924
925 pub fn visible(&self) -> bool {
927 assert!(!self.inner.is_null());
928 unsafe { Fl_File_Chooser_visible(self.inner) != 0 }
929 }
930
931 pub fn window(&self) -> impl WindowExt {
933 unsafe {
935 let win_ptr = self
936 .new_button()
937 .unwrap()
938 .parent()
939 .unwrap()
940 .parent()
941 .unwrap()
942 .as_widget_ptr();
943 crate::window::Window::from_widget_ptr(win_ptr)
944 }
945 }
946
947 pub fn set_add_favorites_label(msg: &'static str) {
949 let msg = CString::safe_new(msg);
950 unsafe { Fl_File_Chooser_set_add_favorites_label(msg.into_raw() as _) }
951 }
952
953 pub fn set_all_files_label(msg: &'static str) {
955 let msg = CString::safe_new(msg);
956 unsafe { Fl_File_Chooser_set_all_files_label(msg.into_raw() as _) }
957 }
958
959 pub fn set_custom_filter_label(msg: &'static str) {
961 let msg = CString::safe_new(msg);
962 unsafe { Fl_File_Chooser_set_custom_filter_label(msg.into_raw() as _) }
963 }
964
965 pub fn set_existing_file_label(msg: &'static str) {
967 let msg = CString::safe_new(msg);
968 unsafe { Fl_File_Chooser_set_existing_file_label(msg.into_raw() as _) }
969 }
970
971 pub fn set_favorites_label(msg: &'static str) {
973 let msg = CString::safe_new(msg);
974 unsafe { Fl_File_Chooser_set_favorites_label(msg.into_raw() as _) }
975 }
976
977 pub fn set_filename_label(msg: &'static str) {
979 let msg = CString::safe_new(msg);
980 unsafe { Fl_File_Chooser_set_filename_label(msg.into_raw() as _) }
981 }
982
983 pub fn set_filesystems_label(msg: &'static str) {
985 let msg = CString::safe_new(msg);
986 unsafe { Fl_File_Chooser_set_filesystems_label(msg.into_raw() as _) }
987 }
988
989 pub fn set_manage_favorites_label(msg: &'static str) {
991 let msg = CString::safe_new(msg);
992 unsafe { Fl_File_Chooser_set_manage_favorites_label(msg.into_raw() as _) }
993 }
994
995 pub fn set_new_directory_label(msg: &'static str) {
997 let msg = CString::safe_new(msg);
998 unsafe { Fl_File_Chooser_set_new_directory_label(msg.into_raw() as _) }
999 }
1000
1001 pub fn set_new_directory_tooltip(msg: &'static str) {
1003 let msg = CString::safe_new(msg);
1004 unsafe { Fl_File_Chooser_set_new_directory_tooltip(msg.into_raw() as _) }
1005 }
1006
1007 pub fn set_preview_label(msg: &'static str) {
1009 let msg = CString::safe_new(msg);
1010 unsafe { Fl_File_Chooser_set_preview_label(msg.into_raw() as _) }
1011 }
1012
1013 pub fn set_save_label(msg: &'static str) {
1015 let msg = CString::safe_new(msg);
1016 unsafe { Fl_File_Chooser_set_save_label(msg.into_raw() as _) }
1017 }
1018
1019 pub fn set_show_label(msg: &'static str) {
1021 let msg = CString::safe_new(msg);
1022 unsafe { Fl_File_Chooser_set_show_label(msg.into_raw() as _) }
1023 }
1024
1025 pub fn set_hidden_label(msg: &'static str) {
1027 let msg = CString::safe_new(msg);
1028 unsafe { Fl_File_Chooser_set_hidden_label(msg.into_raw() as _) }
1029 }
1030
1031 pub fn set_position(&mut self, x: i32, y: i32) {
1033 assert!(!self.inner.is_null());
1034 unsafe { Fl_File_Chooser_set_position(self.inner, x, y) }
1035 }
1036
1037 pub fn set_size(&mut self, w: i32, h: i32) {
1039 assert!(!self.inner.is_null());
1040 unsafe { Fl_File_Chooser_set_size(self.inner, w, h) }
1041 }
1042
1043 pub fn x(&self) -> i32 {
1045 assert!(!self.inner.is_null());
1046 unsafe { Fl_File_Chooser_x(self.inner) }
1047 }
1048
1049 pub fn y(&self) -> i32 {
1051 assert!(!self.inner.is_null());
1052 unsafe { Fl_File_Chooser_y(self.inner) }
1053 }
1054
1055 pub fn w(&self) -> i32 {
1057 assert!(!self.inner.is_null());
1058 unsafe { Fl_File_Chooser_w(self.inner) }
1059 }
1060
1061 pub fn h(&self) -> i32 {
1063 assert!(!self.inner.is_null());
1064 unsafe { Fl_File_Chooser_h(self.inner) }
1065 }
1066
1067 pub fn size(&self) -> (i32, i32) {
1069 (self.w(), self.h())
1070 }
1071
1072 pub fn pos(&self) -> (i32, i32) {
1074 (self.x(), self.y())
1075 }
1076}
1077
1078impl Drop for FileChooser {
1079 fn drop(&mut self) {
1080 unsafe { Fl_File_Chooser_delete(self.inner) }
1081 }
1082}
1083
1084pub fn dir_chooser(message: &str, fname: &str, relative: bool) -> Option<String> {
1086 unsafe {
1087 let message = CString::safe_new(message);
1088 let fname = CString::safe_new(fname);
1089 let ptr = Fl_dir_chooser(message.as_ptr(), fname.as_ptr(), i32::from(relative));
1090 if ptr.is_null() {
1091 None
1092 } else {
1093 Some(
1094 CStr::from_ptr(ptr as *mut raw::c_char)
1095 .to_string_lossy()
1096 .to_string(),
1097 )
1098 }
1099 }
1100}
1101
1102pub fn file_chooser<P: AsRef<Path>>(
1120 message: &str,
1121 pattern: &str,
1122 dir: P,
1123 relative: bool,
1124) -> Option<String> {
1125 file_chooser_(message, pattern, dir.as_ref(), relative)
1126}
1127
1128fn file_chooser_(message: &str, pattern: &str, dir: &Path, relative: bool) -> Option<String> {
1129 if let Some(dir) = dir.to_str() {
1130 let message = CString::safe_new(message);
1131 let pattern = CString::safe_new(pattern);
1132 let dir = CString::safe_new(dir);
1133 unsafe {
1134 let ptr = Fl_file_chooser(
1135 message.as_ptr(),
1136 pattern.as_ptr(),
1137 dir.as_ptr(),
1138 i32::from(relative),
1139 );
1140 if ptr.is_null() {
1141 None
1142 } else {
1143 Some(
1144 CStr::from_ptr(ptr as *mut raw::c_char)
1145 .to_string_lossy()
1146 .to_string(),
1147 )
1148 }
1149 }
1150 } else {
1151 None
1152 }
1153}
1154
1155pub fn color_chooser(name: &str, cmode: ColorMode) -> Option<(u8, u8, u8)> {
1157 unsafe {
1158 let name = CString::safe_new(name);
1159 let mut r = 255;
1160 let mut g = 255;
1161 let mut b = 255;
1162 let ret = Fl_color_chooser(name.as_ptr(), &mut r, &mut g, &mut b, cmode as i32);
1163 if ret == 0 { None } else { Some((r, g, b)) }
1164 }
1165}
1166
1167pub fn color_chooser_with_default(name: &str, cmode: ColorMode, col: (u8, u8, u8)) -> (u8, u8, u8) {
1169 unsafe {
1170 let name = CString::safe_new(name);
1171 let mut r = col.0;
1172 let mut g = col.1;
1173 let mut b = col.2;
1174 let ret = Fl_color_chooser(name.as_ptr(), &mut r, &mut g, &mut b, cmode as i32);
1175 if ret == 0 { col } else { (r, g, b) }
1176 }
1177}
1178
1179pub fn message_title(title: &str) {
1181 let title = CString::safe_new(title);
1182 unsafe { Fl_message_title(title.as_ptr() as _) }
1183}
1184
1185pub fn message_title_default(title: &str) {
1187 let title = CString::safe_new(title);
1188 unsafe { Fl_message_title_default(title.as_ptr() as _) }
1189}
1190
1191pub fn message_icon() -> impl WidgetExt {
1193 unsafe { crate::frame::Frame::from_widget_ptr(Fl_message_icon() as _) }
1194}
1195
1196pub fn message_set_hotspot(enabled: bool) {
1198 unsafe { Fl_message_set_hotspot(enabled.into()) }
1199}
1200
1201pub fn message_hotspot() -> bool {
1203 unsafe { Fl_message_hotspot() != 0 }
1204}
1205
1206pub fn message_set_font(font: Font, sz: i32) {
1208 unsafe { Fl_message_set_font(font.bits(), sz) }
1209}
1210
1211pub fn message_icon_label(label: &str) {
1213 let label = CString::safe_new(label);
1214 unsafe { Fl_message_icon_label(label.into_raw() as _) }
1215}
1216
1217pub fn message_position(x: i32, y: i32) {
1219 unsafe { Fl_message_position(x, y) }
1220}