fltk/app/
prefs.rs

1use crate::{
2    prelude::{FltkError, FltkErrorKind},
3    utils::FlString,
4};
5use fltk_sys::prefs::*;
6use std::ffi::{CStr, CString};
7use std::os::raw::c_char;
8
9bitflags::bitflags! {
10    /// Defines whether preferences are system-wide or not
11    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12    pub struct Root: i32 {
13        /// Returned if storage could not be determined.
14        const UNKNOWN_ROOT_TYPE = -1;
15        /// Preferences are used system-wide. Deprecated, see SYSTEM_L
16        #[doc(hidden)]
17        const SYSTEM        =  0;
18        /// Preferences apply only to the current user. Deprecated, see USER_L
19        #[doc(hidden)]
20        const USER          = 1;
21        /// Returned if querying memory mapped preferences
22        const MEMORY        = 2;
23        /// Mask for the values above
24        const ROOT_MASK     = 0x00FF;
25        /// OR'd by FLTK to read and write core library preferences and options
26        const CORE          = 0x0100;
27        /// This flag should always be set, it makes sure that floating point
28        const C_LOCALE      = 0x1000;
29        /// values are written correctly independently of the current locale
30        /// Preferences are used system-wide, locale independent
31        const SYSTEM_L      = Root::SYSTEM.bits() | Root::C_LOCALE.bits();
32        /// Preferences apply only to the current user, locale independent
33        const USER_L        = Root::USER.bits() | Root::C_LOCALE.bits();
34        /// Same as CORE | SYSTEM | C_LOCALE
35        const CORE_SYSTEM_L = Root::CORE.bits() | Root::SYSTEM_L.bits();
36        /// Same as CORE | USER | C_LOCALE
37        const CORE_USER_L   = Root::CORE.bits() | Root::USER_L.bits();
38        // /// Deprecated, same as CORE | SYSTEM. Use CORE_SYSTEM_L instead.
39        // const CORE_SYSTEM   = Root::CORE.bits() | Root::SYSTEM.bits();
40        // /// Deprecated, same as CORE | USER. Use CORE_USER_L instead.
41        // const CORE_USER     = Root::CORE.bits() | Root::USER.bits();
42    }
43}
44
45bitflags::bitflags! {
46    /// Defines whether preferences are system-wide or not
47    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
48    pub struct FileAccess: u32 {
49        /// None
50        const NONE = 0x0000;
51        /// Set this if it is OK for applications to read user preference files.
52        const USER_READ_OK = 0x0001;
53        /// Set this if it is OK for applications to create and write user preference files.
54        const USER_WRITE_OK = 0x0002;
55        /// Set this if it is OK for applications to read, create, and write user preference files.
56        const USER_OK = FileAccess::USER_READ_OK.bits() | FileAccess::USER_WRITE_OK.bits();
57        /// Set this if it is OK for applications to read system wide preference files.
58        const SYSTEM_READ_OK = 0x0004;
59        /// Set this if it is OK for applications to create and write system wide preference files.
60        const SYSTEM_WRITE_OK = 0x0008;
61        /// Set this if it is OK for applications to read, create, and write system wide preference files.
62        const SYSTEM_OK = FileAccess::SYSTEM_READ_OK.bits() | FileAccess::SYSTEM_WRITE_OK.bits();
63        /// Set this if it is OK for applications to read, create, and write any kind of preference files.
64        const APP_OK = FileAccess::SYSTEM_OK.bits() | FileAccess::USER_OK.bits();
65        /// Set this if it is OK for FLTK to read preference files. USER_READ_OK and/or SYSTEM_READ_OK must also be set.
66        const CORE_READ_OK = 0x0010;
67        /// Set this if it is OK for FLTK to create or write preference files. USER_WRITE_OK and/or SYSTEM_WRITE_OK must also be set.
68        const CORE_WRITE_OK = 0x0020;
69        /// Set this if it is OK for FLTK to read, create, or write preference files.
70        const CORE_OK = FileAccess::CORE_READ_OK.bits() | FileAccess::CORE_WRITE_OK.bits();
71        /// Set this to allow FLTK and applications to read preference files.
72        const ALL_READ_OK = FileAccess::USER_READ_OK.bits() | FileAccess::SYSTEM_READ_OK.bits() | FileAccess::CORE_READ_OK.bits();
73        /// Set this to allow FLTK and applications to create and write preference files.
74        const ALL_WRITE_OK = FileAccess::USER_WRITE_OK.bits() | FileAccess::SYSTEM_WRITE_OK.bits() | FileAccess::CORE_WRITE_OK.bits();
75        /// Set this to give FLTK and applications permission to read, write, and create preference files.
76        const ALL = FileAccess::ALL_READ_OK.bits() | FileAccess::ALL_WRITE_OK.bits();
77    }
78}
79
80/// Provides methods to store user settings between application starts
81#[derive(Debug)]
82pub struct Preferences {
83    inner: *mut Fl_Preferences,
84}
85
86impl Drop for Preferences {
87    fn drop(&mut self) {
88        unsafe { Fl_Preferences_delete(self.inner) }
89    }
90}
91
92impl Clone for Preferences {
93    fn clone(&self) -> Self {
94        let inner = unsafe { Fl_Preferences_copy(self.inner) };
95        assert!(!inner.is_null());
96        Self { inner }
97    }
98}
99
100impl Preferences {
101    /// Set filesystem access
102    pub fn set_file_access(flags: FileAccess) {
103        unsafe { Fl_Preferences_set_file_access(flags.bits()) }
104    }
105
106    /// Get filesystem access flags
107    pub fn file_access() -> FileAccess {
108        let ret = unsafe { Fl_Preferences_file_access() };
109        FileAccess::from_bits_retain(ret)
110    }
111
112    /// Create a new Preferences object
113    pub fn new(root: Root, vendor: &str, application: &str) -> Option<Self> {
114        unsafe {
115            let vendor = CString::safe_new(vendor);
116            let application = CString::safe_new(application);
117            let inner = Fl_Preferences_new(root.bits(), vendor.as_ptr(), application.as_ptr());
118            if inner.is_null() {
119                None
120            } else {
121                Some(Self { inner })
122            }
123        }
124    }
125
126    /// Create a preferences object entry inside the group
127    pub fn new_group(parent: &mut Preferences, group: &str) -> Option<Self> {
128        unsafe {
129            let group = CString::safe_new(group);
130            let inner = Fl_Preferences_from_parent_group(parent.inner, group.as_ptr());
131            if inner.is_null() {
132                None
133            } else {
134                Some(Self { inner })
135            }
136        }
137    }
138
139    /// Get the prefs path
140    pub fn path(&self) -> String {
141        unsafe {
142            let path = Fl_Preferences_path(self.inner);
143            CStr::from_ptr(path).to_string_lossy().to_string()
144        }
145    }
146
147    /// Get the filename
148    pub fn filename(&self) -> Result<(std::path::PathBuf, Root), FltkError> {
149        unsafe {
150            let mut v: Vec<c_char> = vec![0; 250];
151            let ret = Fl_Preferences_filename(self.inner, v.as_mut_ptr(), 250);
152            if ret == -1 {
153                Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
154            } else {
155                Ok((
156                    std::path::PathBuf::from(
157                        CStr::from_ptr(v.as_ptr()).to_string_lossy().to_string(),
158                    ),
159                    Root::from_bits_retain(ret),
160                ))
161            }
162        }
163    }
164
165    /// Get the userdata path
166    pub fn get_userdata_path(&self) -> Result<std::path::PathBuf, FltkError> {
167        unsafe {
168            let mut v: Vec<c_char> = vec![0; 250];
169            let ret = Fl_Preferences_filename(self.inner, v.as_mut_ptr(), 250);
170            if ret == 0 {
171                Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
172            } else {
173                Ok(std::path::PathBuf::from(
174                    CStr::from_ptr(v.as_ptr()).to_string_lossy().to_string(),
175                ))
176            }
177        }
178    }
179
180    /// Set the value of an entry
181    pub fn set_int(&mut self, entry: &str, val: i32) -> Result<(), FltkError> {
182        unsafe {
183            let entry = CString::safe_new(entry);
184            let ret = Fl_Preferences_seti(self.inner, entry.as_ptr(), val);
185            if ret == 0 {
186                Err(FltkError::Unknown(String::from("Failed to set entry")))
187            } else {
188                Ok(())
189            }
190        }
191    }
192
193    /// Get the value of an entry
194    pub fn get_int(&mut self, entry: &str) -> Result<i32, FltkError> {
195        unsafe {
196            let entry = CString::safe_new(entry);
197            let mut i = 0;
198            let ret = Fl_Preferences_geti(self.inner, entry.as_ptr(), &mut i, 0);
199            if ret == 0 {
200                Err(FltkError::Unknown(String::from("Failed to get entry")))
201            } else {
202                Ok(i)
203            }
204        }
205    }
206
207    /// Set the value of an entry
208    pub fn set_float(&mut self, entry: &str, val: f32) -> Result<(), FltkError> {
209        unsafe {
210            let entry = CString::safe_new(entry);
211            let ret = Fl_Preferences_setf(self.inner, entry.as_ptr(), val);
212            if ret == 0 {
213                Err(FltkError::Unknown(String::from("Failed to set entry")))
214            } else {
215                Ok(())
216            }
217        }
218    }
219
220    /// Set the value of an entry
221    pub fn set_float_with_precision(
222        &mut self,
223        entry: &str,
224        val: f32,
225        precision: u16,
226    ) -> Result<(), FltkError> {
227        unsafe {
228            let entry = CString::safe_new(entry);
229            let ret = Fl_Preferences_setfp(self.inner, entry.as_ptr(), val, i32::from(precision));
230            if ret == 0 {
231                Err(FltkError::Unknown(String::from("Failed to set entry")))
232            } else {
233                Ok(())
234            }
235        }
236    }
237
238    /// Get the value of an entry
239    pub fn get_float(&mut self, entry: &str) -> Result<f32, FltkError> {
240        unsafe {
241            let entry = CString::safe_new(entry);
242            let mut i = 0.0;
243            let ret = Fl_Preferences_getf(self.inner, entry.as_ptr(), &mut i, 0.0);
244            if ret == 0 {
245                Err(FltkError::Unknown(String::from("Failed to get entry")))
246            } else {
247                Ok(i)
248            }
249        }
250    }
251
252    /// Set the value of an entry
253    pub fn set_double(&mut self, entry: &str, val: f64) -> Result<(), FltkError> {
254        unsafe {
255            let entry = CString::safe_new(entry);
256            let ret = Fl_Preferences_setd(self.inner, entry.as_ptr(), val);
257            if ret == 0 {
258                Err(FltkError::Unknown(String::from("Failed to set entry")))
259            } else {
260                Ok(())
261            }
262        }
263    }
264
265    /// Set the value of an entry
266    pub fn set_double_with_precision(
267        &mut self,
268        entry: &str,
269        val: f64,
270        precision: u16,
271    ) -> Result<(), FltkError> {
272        unsafe {
273            let entry = CString::safe_new(entry);
274            let ret = Fl_Preferences_setdp(self.inner, entry.as_ptr(), val, i32::from(precision));
275            if ret == 0 {
276                Err(FltkError::Unknown(String::from("Failed to set entry")))
277            } else {
278                Ok(())
279            }
280        }
281    }
282
283    /// Get the value of an entry
284    pub fn get_double(&mut self, entry: &str) -> Result<f64, FltkError> {
285        unsafe {
286            let entry = CString::safe_new(entry);
287            let mut i = 0.0;
288            let ret = Fl_Preferences_getd(self.inner, entry.as_ptr(), &mut i, 0.0);
289            if ret == 0 {
290                Err(FltkError::Unknown(String::from("Failed to get entry")))
291            } else {
292                Ok(i)
293            }
294        }
295    }
296
297    /// Set the value of an entry
298    pub fn set_str(&mut self, entry: &str, val: &str) -> Result<(), FltkError> {
299        unsafe {
300            let entry = CString::safe_new(entry);
301            let val = CString::safe_new(val);
302            let ret = Fl_Preferences_sets(self.inner, entry.as_ptr(), val.as_ptr());
303            if ret == 0 {
304                Err(FltkError::Unknown(String::from("Failed to set entry")))
305            } else {
306                Ok(())
307            }
308        }
309    }
310
311    /// Get the value of an entry
312    pub fn get_str(&mut self, entry: &str) -> Result<String, FltkError> {
313        unsafe {
314            let entry = CString::safe_new(entry);
315            let sz = Fl_Preferences_size(self.inner, entry.as_ptr());
316            let mut val: Vec<c_char> = vec![0; (sz + 1) as usize];
317            let ret = Fl_Preferences_gets(
318                self.inner,
319                entry.as_ptr(),
320                val.as_mut_ptr(),
321                c"".as_ptr() as _,
322                sz + 1,
323            );
324            if ret == 0 {
325                Err(FltkError::Unknown(String::from("Failed to get entry")))
326            } else {
327                Ok(CStr::from_ptr(val.as_ptr()).to_string_lossy().to_string())
328            }
329        }
330    }
331
332    /// Return the pref's name
333    pub fn name(&mut self) -> Option<String> {
334        unsafe {
335            let ptr = Fl_Preferences_name(self.inner);
336            if ptr.is_null() {
337                None
338            } else {
339                Some(CStr::from_ptr(ptr).to_string_lossy().to_string())
340            }
341        }
342    }
343
344    /// Return the number of groups
345    pub fn groups(&mut self) -> i32 {
346        unsafe { Fl_Preferences_groups(self.inner) }
347    }
348
349    /// Check whether a group exists
350    pub fn group_exists(&mut self, key: &str) -> bool {
351        unsafe {
352            let key = CString::safe_new(key);
353            Fl_Preferences_group_exists(self.inner, key.as_ptr()) != 0
354        }
355    }
356
357    /// Delete a group
358    pub fn delete_group(&mut self, group: &str) -> Result<(), FltkError> {
359        unsafe {
360            let group = CString::safe_new(group);
361            let ret = Fl_Preferences_delete_group(self.inner, group.as_ptr());
362            if ret == 0 {
363                Err(FltkError::Internal(FltkErrorKind::FailedOperation))
364            } else {
365                Ok(())
366            }
367        }
368    }
369
370    /// Delete all groups
371    pub fn delete_all_groups(&mut self) -> Result<(), FltkError> {
372        unsafe {
373            let ret = Fl_Preferences_delete_all_groups(self.inner);
374            if ret == 0 {
375                Err(FltkError::Internal(FltkErrorKind::FailedOperation))
376            } else {
377                Ok(())
378            }
379        }
380    }
381
382    /// Return the number of entries
383    pub fn entries(&mut self) -> i32 {
384        unsafe { Fl_Preferences_entries(self.inner) }
385    }
386
387    /// Check whether an entry exists
388    pub fn entry_exists(&mut self, key: &str) -> bool {
389        unsafe {
390            let key = CString::safe_new(key);
391            Fl_Preferences_entry_exists(self.inner, key.as_ptr()) != 0
392        }
393    }
394
395    /// Delete an entry
396    pub fn delete_entry(&mut self, entry: &str) -> Result<(), FltkError> {
397        unsafe {
398            let entry = CString::safe_new(entry);
399            let ret = Fl_Preferences_delete_entry(self.inner, entry.as_ptr());
400            if ret == 0 {
401                Err(FltkError::Internal(FltkErrorKind::FailedOperation))
402            } else {
403                Ok(())
404            }
405        }
406    }
407
408    /// Delete all entries
409    pub fn delete_all_entries(&mut self) -> Result<(), FltkError> {
410        unsafe {
411            let ret = Fl_Preferences_delete_all_entries(self.inner);
412            if ret == 0 {
413                Err(FltkError::Internal(FltkErrorKind::FailedOperation))
414            } else {
415                Ok(())
416            }
417        }
418    }
419
420    /// Clear prefs
421    pub fn clear(&mut self) -> Result<(), FltkError> {
422        unsafe {
423            let ret = Fl_Preferences_clear(self.inner);
424            if ret == 0 {
425                Err(FltkError::Internal(FltkErrorKind::FailedOperation))
426            } else {
427                Ok(())
428            }
429        }
430    }
431}