1use crate::enums::{Color, Font};
2use crate::prelude::*;
3use crate::utils::{FlString, images_registered, register_images};
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 if !images_registered() {
557 register_images();
558 }
559 let dir = dir.to_str().unwrap_or(".");
560 let dir = CString::safe_new(dir);
561 let pattern = CString::safe_new(pattern);
562 let title = CString::safe_new(title);
563 unsafe {
564 let ptr = Fl_File_Chooser_new(
565 dir.as_ptr(),
566 pattern.as_ptr(),
567 typ.bits(),
568 title.into_raw() as _,
569 );
570 assert!(!ptr.is_null());
571 FileChooser { inner: ptr }
572 }
573 }
574 pub unsafe fn delete(dlg: &Self) {
578 unsafe { Fl_File_Chooser_delete(dlg.inner) }
579 }
580
581 pub fn new_button(&self) -> Option<impl ButtonExt> {
583 assert!(!self.inner.is_null());
584 unsafe {
585 let ptr = Fl_File_Chooser_newButton(self.inner);
586 if ptr.is_null() {
587 None
588 } else {
589 Some(crate::button::Button::from_widget_ptr(ptr as *mut _))
590 }
591 }
592 }
593
594 pub fn preview_button(&self) -> Option<impl ButtonExt> {
596 assert!(!self.inner.is_null());
597 unsafe {
598 let ptr = Fl_File_Chooser_previewButton(self.inner);
599 if ptr.is_null() {
600 None
601 } else {
602 Some(crate::button::CheckButton::from_widget_ptr(
603 ptr as *mut fltk_sys::widget::Fl_Widget,
604 ))
605 }
606 }
607 }
608
609 pub fn show_hidden_button(&self) -> Option<impl ButtonExt> {
611 assert!(!self.inner.is_null());
612 unsafe {
613 let ptr = Fl_File_Chooser_showHiddenButton(self.inner);
614 if ptr.is_null() {
615 None
616 } else {
617 Some(crate::button::CheckButton::from_widget_ptr(
618 ptr as *mut fltk_sys::widget::Fl_Widget,
619 ))
620 }
621 }
622 }
623
624 pub fn set_callback<F: FnMut(&mut Self) + 'static>(&mut self, cb: F) {
626 assert!(!self.inner.is_null());
627 unsafe {
628 unsafe extern "C" fn shim(arg1: *mut Fl_File_Chooser, data: *mut raw::c_void) {
629 unsafe {
630 let mut wid = FileChooser { inner: arg1 };
631 let a: *mut Box<dyn FnMut(&mut FileChooser)> =
632 data as *mut Box<dyn FnMut(&mut FileChooser)>;
633 let f: &mut dyn FnMut(&mut FileChooser) = &mut **a;
634 let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&mut wid)));
635 }
636 }
637 let _old_data = self.user_data();
638 let a: *mut Box<dyn FnMut(&mut Self)> = Box::into_raw(Box::new(Box::new(cb)));
639 let data: *mut raw::c_void = a as *mut raw::c_void;
640 let callback: Option<
641 unsafe extern "C" fn(arg1: *mut Fl_File_Chooser, data: *mut raw::c_void),
642 > = Some(shim);
643 Fl_File_Chooser_set_callback(self.inner, callback, data);
644 }
645 }
646
647 pub fn set_color(&mut self, c: Color) {
649 assert!(!self.inner.is_null());
650 unsafe { Fl_File_Chooser_set_color(self.inner, c.bits()) }
651 }
652
653 pub fn color(&self) -> Color {
655 assert!(!self.inner.is_null());
656 unsafe { mem::transmute(Fl_File_Chooser_color(self.inner)) }
657 }
658
659 pub fn count(&self) -> i32 {
661 assert!(!self.inner.is_null());
662 unsafe { Fl_File_Chooser_count(self.inner) }
663 }
664
665 pub fn set_directory<P: AsRef<Path>>(&mut self, dir: P) {
667 self.set_directory_(dir.as_ref());
668 }
669
670 fn set_directory_(&mut self, dir: &Path) {
671 assert!(!self.inner.is_null());
672 if let Some(dir) = dir.to_str() {
673 let dir = CString::safe_new(dir);
674 unsafe { Fl_File_Chooser_set_directory(self.inner, dir.as_ptr()) }
675 }
676 }
677
678 pub fn directory(&self) -> Option<PathBuf> {
680 assert!(!self.inner.is_null());
681 unsafe {
682 let ptr = Fl_File_Chooser_directory(self.inner);
683 if ptr.is_null() {
684 None
685 } else {
686 Some(PathBuf::from(
687 CStr::from_ptr(ptr as *mut raw::c_char)
688 .to_string_lossy()
689 .to_string(),
690 ))
691 }
692 }
693 }
694
695 pub fn set_filter(&mut self, pattern: &str) {
701 assert!(!self.inner.is_null());
702 let pattern = CString::safe_new(pattern);
703 unsafe { Fl_File_Chooser_set_filter(self.inner, pattern.as_ptr()) }
704 }
705
706 pub fn filter(&self) -> Option<String> {
708 assert!(!self.inner.is_null());
709 unsafe {
710 let ptr = Fl_File_Chooser_filter(self.inner);
711 if ptr.is_null() {
712 None
713 } else {
714 Some(
715 CStr::from_ptr(ptr as *mut raw::c_char)
716 .to_string_lossy()
717 .to_string(),
718 )
719 }
720 }
721 }
722
723 pub fn filter_value(&self) -> i32 {
725 assert!(!self.inner.is_null());
726 unsafe { Fl_File_Chooser_filter_value(self.inner) }
727 }
728
729 pub fn set_filter_value(&mut self, f: i32) {
731 assert!(!self.inner.is_null());
732 unsafe { Fl_File_Chooser_set_filter_value(self.inner, f) }
733 }
734
735 pub fn hide(&mut self) {
737 assert!(!self.inner.is_null());
738 unsafe { Fl_File_Chooser_hide(self.inner) }
739 }
740
741 pub fn set_icon_size(&mut self, s: u8) {
743 assert!(!self.inner.is_null());
744 unsafe { Fl_File_Chooser_set_iconsize(self.inner, s) }
745 }
746
747 pub fn icon_size(&self) -> u8 {
749 assert!(!self.inner.is_null());
750 unsafe { Fl_File_Chooser_iconsize(self.inner) }
751 }
752
753 pub fn set_label(&mut self, l: &str) {
755 assert!(!self.inner.is_null());
756 let l = CString::safe_new(l);
757 let _old = unsafe { CString::from_raw(Fl_File_Chooser_label(self.inner) as _) };
758 unsafe { Fl_File_Chooser_set_label(self.inner, l.into_raw() as _) }
759 }
760
761 pub fn label(&self) -> Option<String> {
763 assert!(!self.inner.is_null());
764 unsafe {
765 let ptr = Fl_File_Chooser_label(self.inner);
766 if ptr.is_null() {
767 None
768 } else {
769 Some(
770 CStr::from_ptr(ptr as *mut raw::c_char)
771 .to_string_lossy()
772 .to_string(),
773 )
774 }
775 }
776 }
777
778 pub fn set_ok_label(&mut self, l: &'static str) {
780 assert!(!self.inner.is_null());
781 let l = CString::safe_new(l);
782 unsafe { Fl_File_Chooser_set_ok_label(self.inner, l.into_raw() as _) }
783 }
784
785 pub fn ok_label(&self) -> Option<String> {
787 assert!(!self.inner.is_null());
788 unsafe {
789 let ptr = Fl_File_Chooser_ok_label(self.inner);
790 if ptr.is_null() {
791 None
792 } else {
793 Some(
794 CStr::from_ptr(ptr as *mut raw::c_char)
795 .to_string_lossy()
796 .to_string(),
797 )
798 }
799 }
800 }
801
802 pub fn set_preview(&mut self, e: bool) {
804 assert!(!self.inner.is_null());
805 unsafe { Fl_File_Chooser_set_preview(self.inner, i32::from(e)) }
806 }
807
808 pub fn preview(&self) -> bool {
810 assert!(!self.inner.is_null());
811 unsafe { Fl_File_Chooser_preview(self.inner) != 0 }
812 }
813
814 pub fn rescan(&mut self) {
816 assert!(!self.inner.is_null());
817 unsafe { Fl_File_Chooser_rescan(self.inner) }
818 }
819
820 pub fn rescan_keep_filename(&mut self) {
822 assert!(!self.inner.is_null());
823 unsafe { Fl_File_Chooser_rescan_keep_filename(self.inner) }
824 }
825
826 pub fn show(&mut self) {
828 assert!(!self.inner.is_null());
829 unsafe { Fl_File_Chooser_show(self.inner) }
830 }
831
832 pub fn shown(&self) -> bool {
834 assert!(!self.inner.is_null());
835 unsafe { Fl_File_Chooser_shown(self.inner) != 0 }
836 }
837
838 pub fn set_text_color(&mut self, c: Color) {
840 assert!(!self.inner.is_null());
841 unsafe { Fl_File_Chooser_set_text_color(self.inner, c.bits()) }
842 }
843
844 pub fn text_color(&self) -> Color {
846 assert!(!self.inner.is_null());
847 unsafe { mem::transmute(Fl_File_Chooser_text_color(self.inner)) }
848 }
849
850 pub fn set_text_font(&mut self, f: Font) {
852 assert!(!self.inner.is_null());
853 unsafe { Fl_File_Chooser_set_text_font(self.inner, f.bits()) }
854 }
855
856 pub fn text_font(&self) -> Font {
858 assert!(!self.inner.is_null());
859 unsafe { mem::transmute(Fl_File_Chooser_text_font(self.inner)) }
860 }
861
862 pub fn set_text_size(&mut self, s: i32) {
864 assert!(!self.inner.is_null());
865 unsafe { Fl_File_Chooser_set_text_size(self.inner, s) }
866 }
867
868 pub fn text_size(&self) -> i32 {
870 assert!(!self.inner.is_null());
871 unsafe { Fl_File_Chooser_text_size(self.inner) }
872 }
873
874 pub fn set_type(&mut self, t: FileChooserType) {
876 assert!(!self.inner.is_null());
877 unsafe { Fl_File_Chooser_set_type(self.inner, t.bits()) }
878 }
879
880 pub fn get_type(&self) -> FileChooserType {
882 assert!(!self.inner.is_null());
883 unsafe { mem::transmute(Fl_File_Chooser_type(self.inner)) }
884 }
885
886 pub unsafe fn user_data(&self) -> Option<Box<dyn FnMut()>> {
890 unsafe {
891 let ptr = Fl_File_Chooser_user_data(self.inner);
892 if ptr.is_null() {
893 None
894 } else {
895 let x = ptr as *mut Box<dyn FnMut()>;
896 let x = Box::from_raw(x);
897 Fl_File_Chooser_set_callback(self.inner, None, std::ptr::null_mut());
898 Some(*x)
899 }
900 }
901 }
902
903 pub fn value(&mut self, f: i32) -> Option<String> {
905 assert!(!self.inner.is_null());
906 let f = if f == 0 { 1 } else { f };
907 unsafe {
908 let ptr = Fl_File_Chooser_value(self.inner, f);
909 if ptr.is_null() {
910 None
911 } else {
912 Some(
913 CStr::from_ptr(ptr as *mut raw::c_char)
914 .to_string_lossy()
915 .to_string(),
916 )
917 }
918 }
919 }
920
921 pub fn set_value(&mut self, filename: &str) {
923 assert!(!self.inner.is_null());
924 let filename = CString::safe_new(filename);
925 unsafe { Fl_File_Chooser_set_value(self.inner, filename.as_ptr()) }
926 }
927
928 pub fn visible(&self) -> bool {
930 assert!(!self.inner.is_null());
931 unsafe { Fl_File_Chooser_visible(self.inner) != 0 }
932 }
933
934 pub fn window(&self) -> impl WindowExt {
936 unsafe {
938 let win_ptr = self
939 .new_button()
940 .unwrap()
941 .parent()
942 .unwrap()
943 .parent()
944 .unwrap()
945 .as_widget_ptr();
946 crate::window::Window::from_widget_ptr(win_ptr)
947 }
948 }
949
950 pub fn set_add_favorites_label(msg: &'static str) {
952 let msg = CString::safe_new(msg);
953 unsafe { Fl_File_Chooser_set_add_favorites_label(msg.into_raw() as _) }
954 }
955
956 pub fn set_all_files_label(msg: &'static str) {
958 let msg = CString::safe_new(msg);
959 unsafe { Fl_File_Chooser_set_all_files_label(msg.into_raw() as _) }
960 }
961
962 pub fn set_custom_filter_label(msg: &'static str) {
964 let msg = CString::safe_new(msg);
965 unsafe { Fl_File_Chooser_set_custom_filter_label(msg.into_raw() as _) }
966 }
967
968 pub fn set_existing_file_label(msg: &'static str) {
970 let msg = CString::safe_new(msg);
971 unsafe { Fl_File_Chooser_set_existing_file_label(msg.into_raw() as _) }
972 }
973
974 pub fn set_favorites_label(msg: &'static str) {
976 let msg = CString::safe_new(msg);
977 unsafe { Fl_File_Chooser_set_favorites_label(msg.into_raw() as _) }
978 }
979
980 pub fn set_filename_label(msg: &'static str) {
982 let msg = CString::safe_new(msg);
983 unsafe { Fl_File_Chooser_set_filename_label(msg.into_raw() as _) }
984 }
985
986 pub fn set_filesystems_label(msg: &'static str) {
988 let msg = CString::safe_new(msg);
989 unsafe { Fl_File_Chooser_set_filesystems_label(msg.into_raw() as _) }
990 }
991
992 pub fn set_manage_favorites_label(msg: &'static str) {
994 let msg = CString::safe_new(msg);
995 unsafe { Fl_File_Chooser_set_manage_favorites_label(msg.into_raw() as _) }
996 }
997
998 pub fn set_new_directory_label(msg: &'static str) {
1000 let msg = CString::safe_new(msg);
1001 unsafe { Fl_File_Chooser_set_new_directory_label(msg.into_raw() as _) }
1002 }
1003
1004 pub fn set_new_directory_tooltip(msg: &'static str) {
1006 let msg = CString::safe_new(msg);
1007 unsafe { Fl_File_Chooser_set_new_directory_tooltip(msg.into_raw() as _) }
1008 }
1009
1010 pub fn set_preview_label(msg: &'static str) {
1012 let msg = CString::safe_new(msg);
1013 unsafe { Fl_File_Chooser_set_preview_label(msg.into_raw() as _) }
1014 }
1015
1016 pub fn set_save_label(msg: &'static str) {
1018 let msg = CString::safe_new(msg);
1019 unsafe { Fl_File_Chooser_set_save_label(msg.into_raw() as _) }
1020 }
1021
1022 pub fn set_show_label(msg: &'static str) {
1024 let msg = CString::safe_new(msg);
1025 unsafe { Fl_File_Chooser_set_show_label(msg.into_raw() as _) }
1026 }
1027
1028 pub fn set_hidden_label(msg: &'static str) {
1030 let msg = CString::safe_new(msg);
1031 unsafe { Fl_File_Chooser_set_hidden_label(msg.into_raw() as _) }
1032 }
1033
1034 pub fn set_position(&mut self, x: i32, y: i32) {
1036 assert!(!self.inner.is_null());
1037 unsafe { Fl_File_Chooser_set_position(self.inner, x, y) }
1038 }
1039
1040 pub fn set_size(&mut self, w: i32, h: i32) {
1042 assert!(!self.inner.is_null());
1043 unsafe { Fl_File_Chooser_set_size(self.inner, w, h) }
1044 }
1045
1046 pub fn x(&self) -> i32 {
1048 assert!(!self.inner.is_null());
1049 unsafe { Fl_File_Chooser_x(self.inner) }
1050 }
1051
1052 pub fn y(&self) -> i32 {
1054 assert!(!self.inner.is_null());
1055 unsafe { Fl_File_Chooser_y(self.inner) }
1056 }
1057
1058 pub fn w(&self) -> i32 {
1060 assert!(!self.inner.is_null());
1061 unsafe { Fl_File_Chooser_w(self.inner) }
1062 }
1063
1064 pub fn h(&self) -> i32 {
1066 assert!(!self.inner.is_null());
1067 unsafe { Fl_File_Chooser_h(self.inner) }
1068 }
1069
1070 pub fn size(&self) -> (i32, i32) {
1072 (self.w(), self.h())
1073 }
1074
1075 pub fn pos(&self) -> (i32, i32) {
1077 (self.x(), self.y())
1078 }
1079}
1080
1081impl Drop for FileChooser {
1082 fn drop(&mut self) {
1083 unsafe { Fl_File_Chooser_delete(self.inner) }
1084 }
1085}
1086
1087pub fn dir_chooser(message: &str, fname: &str, relative: bool) -> Option<String> {
1089 unsafe {
1090 let message = CString::safe_new(message);
1091 let fname = CString::safe_new(fname);
1092 let ptr = Fl_dir_chooser(message.as_ptr(), fname.as_ptr(), i32::from(relative));
1093 if ptr.is_null() {
1094 None
1095 } else {
1096 Some(
1097 CStr::from_ptr(ptr as *mut raw::c_char)
1098 .to_string_lossy()
1099 .to_string(),
1100 )
1101 }
1102 }
1103}
1104
1105pub fn file_chooser<P: AsRef<Path>>(
1123 message: &str,
1124 pattern: &str,
1125 dir: P,
1126 relative: bool,
1127) -> Option<String> {
1128 file_chooser_(message, pattern, dir.as_ref(), relative)
1129}
1130
1131fn file_chooser_(message: &str, pattern: &str, dir: &Path, relative: bool) -> Option<String> {
1132 if let Some(dir) = dir.to_str() {
1133 let message = CString::safe_new(message);
1134 let pattern = CString::safe_new(pattern);
1135 let dir = CString::safe_new(dir);
1136 unsafe {
1137 let ptr = Fl_file_chooser(
1138 message.as_ptr(),
1139 pattern.as_ptr(),
1140 dir.as_ptr(),
1141 i32::from(relative),
1142 );
1143 if ptr.is_null() {
1144 None
1145 } else {
1146 Some(
1147 CStr::from_ptr(ptr as *mut raw::c_char)
1148 .to_string_lossy()
1149 .to_string(),
1150 )
1151 }
1152 }
1153 } else {
1154 None
1155 }
1156}
1157
1158pub fn color_chooser(name: &str, cmode: ColorMode) -> Option<(u8, u8, u8)> {
1160 unsafe {
1161 let name = CString::safe_new(name);
1162 let mut r = 255;
1163 let mut g = 255;
1164 let mut b = 255;
1165 let ret = Fl_color_chooser(name.as_ptr(), &mut r, &mut g, &mut b, cmode as i32);
1166 if ret == 0 { None } else { Some((r, g, b)) }
1167 }
1168}
1169
1170pub fn color_chooser_with_default(name: &str, cmode: ColorMode, col: (u8, u8, u8)) -> (u8, u8, u8) {
1172 unsafe {
1173 let name = CString::safe_new(name);
1174 let mut r = col.0;
1175 let mut g = col.1;
1176 let mut b = col.2;
1177 let ret = Fl_color_chooser(name.as_ptr(), &mut r, &mut g, &mut b, cmode as i32);
1178 if ret == 0 { col } else { (r, g, b) }
1179 }
1180}
1181
1182pub fn message_title(title: &str) {
1184 let title = CString::safe_new(title);
1185 unsafe { Fl_message_title(title.as_ptr() as _) }
1186}
1187
1188pub fn message_title_default(title: &str) {
1190 let title = CString::safe_new(title);
1191 unsafe { Fl_message_title_default(title.as_ptr() as _) }
1192}
1193
1194pub fn message_icon() -> impl WidgetExt {
1196 unsafe { crate::frame::Frame::from_widget_ptr(Fl_message_icon() as _) }
1197}
1198
1199pub fn message_set_hotspot(enabled: bool) {
1201 unsafe { Fl_message_set_hotspot(enabled.into()) }
1202}
1203
1204pub fn message_hotspot() -> bool {
1206 unsafe { Fl_message_hotspot() != 0 }
1207}
1208
1209pub fn message_set_font(font: Font, sz: i32) {
1211 unsafe { Fl_message_set_font(font.bits(), sz) }
1212}
1213
1214pub fn message_icon_label(label: &str) {
1216 let label = CString::safe_new(label);
1217 unsafe { Fl_message_icon_label(label.into_raw() as _) }
1218}
1219
1220pub fn message_position(x: i32, y: i32) {
1222 unsafe { Fl_message_position(x, y) }
1223}