use crate::{
prelude::{FltkError, FltkErrorKind},
utils::FlString,
};
use fltk_sys::prefs::*;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Root: i32 {
const UNKNOWN_ROOT_TYPE = -1;
#[doc(hidden)]
const SYSTEM = 0;
#[doc(hidden)]
const USER = 1;
const MEMORY = 2;
const ROOT_MASK = 0x00FF;
const CORE = 0x0100;
const C_LOCALE = 0x1000;
const SYSTEM_L = Root::SYSTEM.bits() | Root::C_LOCALE.bits();
const USER_L = Root::USER.bits() | Root::C_LOCALE.bits();
const CORE_SYSTEM_L = Root::CORE.bits() | Root::SYSTEM_L.bits();
const CORE_USER_L = Root::CORE.bits() | Root::USER_L.bits();
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileAccess: u32 {
const NONE = 0x0000;
const USER_READ_OK = 0x0001;
const USER_WRITE_OK = 0x0002;
const USER_OK = FileAccess::USER_READ_OK.bits() | FileAccess::USER_WRITE_OK.bits();
const SYSTEM_READ_OK = 0x0004;
const SYSTEM_WRITE_OK = 0x0008;
const SYSTEM_OK = FileAccess::SYSTEM_READ_OK.bits() | FileAccess::SYSTEM_WRITE_OK.bits();
const APP_OK = FileAccess::SYSTEM_OK.bits() | FileAccess::USER_OK.bits();
const CORE_READ_OK = 0x0010;
const CORE_WRITE_OK = 0x0020;
const CORE_OK = FileAccess::CORE_READ_OK.bits() | FileAccess::CORE_WRITE_OK.bits();
const ALL_READ_OK = FileAccess::USER_READ_OK.bits() | FileAccess::SYSTEM_READ_OK.bits() | FileAccess::CORE_READ_OK.bits();
const ALL_WRITE_OK = FileAccess::USER_WRITE_OK.bits() | FileAccess::SYSTEM_WRITE_OK.bits() | FileAccess::CORE_WRITE_OK.bits();
const ALL = FileAccess::ALL_READ_OK.bits() | FileAccess::ALL_WRITE_OK.bits();
}
}
#[derive(Debug)]
pub struct Preferences {
inner: *mut Fl_Preferences,
}
impl Drop for Preferences {
fn drop(&mut self) {
unsafe { Fl_Preferences_delete(self.inner) }
}
}
impl Clone for Preferences {
fn clone(&self) -> Self {
let inner = unsafe { Fl_Preferences_copy(self.inner) };
assert!(!inner.is_null());
Self { inner }
}
}
impl Preferences {
pub fn set_file_access(flags: FileAccess) {
unsafe { Fl_Preferences_set_file_access(flags.bits()) }
}
pub fn file_access() -> FileAccess {
let ret = unsafe { Fl_Preferences_file_access() };
FileAccess::from_bits_retain(ret)
}
pub fn new(root: Root, vendor: &str, application: &str) -> Option<Self> {
unsafe {
let vendor = CString::safe_new(vendor);
let application = CString::safe_new(application);
let inner = Fl_Preferences_new(root.bits(), vendor.as_ptr(), application.as_ptr());
if inner.is_null() {
None
} else {
Some(Self { inner })
}
}
}
pub fn new_group(parent: &mut Preferences, group: &str) -> Option<Self> {
unsafe {
let group = CString::safe_new(group);
let inner = Fl_Preferences_from_parent_group(parent.inner, group.as_ptr());
if inner.is_null() {
None
} else {
Some(Self { inner })
}
}
}
pub fn path(&self) -> String {
unsafe {
let path = Fl_Preferences_path(self.inner);
CStr::from_ptr(path).to_string_lossy().to_string()
}
}
pub fn filename(&self) -> Result<(std::path::PathBuf, Root), FltkError> {
unsafe {
let mut v: Vec<c_char> = vec![0; 250];
let ret = Fl_Preferences_filename(self.inner, v.as_mut_ptr(), 250);
if ret == -1 {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
Ok((
std::path::PathBuf::from(
CStr::from_ptr(v.as_ptr()).to_string_lossy().to_string(),
),
Root::from_bits_retain(ret),
))
}
}
}
pub fn get_userdata_path(&self) -> Result<std::path::PathBuf, FltkError> {
unsafe {
let mut v: Vec<c_char> = vec![0; 250];
let ret = Fl_Preferences_filename(self.inner, v.as_mut_ptr(), 250);
if ret == 0 {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
Ok(std::path::PathBuf::from(
CStr::from_ptr(v.as_ptr()).to_string_lossy().to_string(),
))
}
}
}
pub fn set_int(&mut self, entry: &str, val: i32) -> Result<(), FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let ret = Fl_Preferences_seti(self.inner, entry.as_ptr(), val);
if ret == 0 {
Err(FltkError::Unknown(String::from("Failed to set entry")))
} else {
Ok(())
}
}
}
pub fn get_int(&mut self, entry: &str) -> Result<i32, FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let mut i = 0;
let ret = Fl_Preferences_geti(self.inner, entry.as_ptr(), &mut i, 0);
if ret == 0 {
Err(FltkError::Unknown(String::from("Failed to get entry")))
} else {
Ok(i)
}
}
}
pub fn set_float(&mut self, entry: &str, val: f32) -> Result<(), FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let ret = Fl_Preferences_setf(self.inner, entry.as_ptr(), val);
if ret == 0 {
Err(FltkError::Unknown(String::from("Failed to set entry")))
} else {
Ok(())
}
}
}
pub fn set_float_with_precision(
&mut self,
entry: &str,
val: f32,
precision: u16,
) -> Result<(), FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let ret = Fl_Preferences_setfp(self.inner, entry.as_ptr(), val, precision as i32);
if ret == 0 {
Err(FltkError::Unknown(String::from("Failed to set entry")))
} else {
Ok(())
}
}
}
pub fn get_float(&mut self, entry: &str) -> Result<f32, FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let mut i = 0.0;
let ret = Fl_Preferences_getf(self.inner, entry.as_ptr(), &mut i, 0.0);
if ret == 0 {
Err(FltkError::Unknown(String::from("Failed to get entry")))
} else {
Ok(i)
}
}
}
pub fn set_double(&mut self, entry: &str, val: f64) -> Result<(), FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let ret = Fl_Preferences_setd(self.inner, entry.as_ptr(), val);
if ret == 0 {
Err(FltkError::Unknown(String::from("Failed to set entry")))
} else {
Ok(())
}
}
}
pub fn set_double_with_precision(
&mut self,
entry: &str,
val: f64,
precision: u16,
) -> Result<(), FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let ret = Fl_Preferences_setdp(self.inner, entry.as_ptr(), val, precision as i32);
if ret == 0 {
Err(FltkError::Unknown(String::from("Failed to set entry")))
} else {
Ok(())
}
}
}
pub fn get_double(&mut self, entry: &str) -> Result<f64, FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let mut i = 0.0;
let ret = Fl_Preferences_getd(self.inner, entry.as_ptr(), &mut i, 0.0);
if ret == 0 {
Err(FltkError::Unknown(String::from("Failed to get entry")))
} else {
Ok(i)
}
}
}
pub fn set_str(&mut self, entry: &str, val: &str) -> Result<(), FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let val = CString::safe_new(val);
let ret = Fl_Preferences_sets(self.inner, entry.as_ptr(), val.as_ptr());
if ret == 0 {
Err(FltkError::Unknown(String::from("Failed to set entry")))
} else {
Ok(())
}
}
}
pub fn get_str(&mut self, entry: &str) -> Result<String, FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let sz = Fl_Preferences_size(self.inner, entry.as_ptr());
let mut val: Vec<c_char> = vec![0; (sz + 1) as usize];
let ret = Fl_Preferences_gets(
self.inner,
entry.as_ptr(),
val.as_mut_ptr(),
"\0".as_ptr() as _,
sz + 1,
);
if ret == 0 {
Err(FltkError::Unknown(String::from("Failed to get entry")))
} else {
Ok(CStr::from_ptr(val.as_ptr()).to_string_lossy().to_string())
}
}
}
pub fn name(&mut self) -> Option<String> {
unsafe {
let ptr = Fl_Preferences_name(self.inner);
if ptr.is_null() {
None
} else {
Some(CStr::from_ptr(ptr).to_string_lossy().to_string())
}
}
}
pub fn groups(&mut self) -> i32 {
unsafe { Fl_Preferences_groups(self.inner) }
}
pub fn group_exists(&mut self, key: &str) -> bool {
unsafe {
let key = CString::safe_new(key);
Fl_Preferences_group_exists(self.inner, key.as_ptr()) != 0
}
}
pub fn delete_group(&mut self, group: &str) -> Result<(), FltkError> {
unsafe {
let group = CString::safe_new(group);
let ret = Fl_Preferences_delete_group(self.inner, group.as_ptr());
if ret == 0 {
Err(FltkError::Internal(FltkErrorKind::FailedOperation))
} else {
Ok(())
}
}
}
pub fn delete_all_groups(&mut self) -> Result<(), FltkError> {
unsafe {
let ret = Fl_Preferences_delete_all_groups(self.inner);
if ret == 0 {
Err(FltkError::Internal(FltkErrorKind::FailedOperation))
} else {
Ok(())
}
}
}
pub fn entries(&mut self) -> i32 {
unsafe { Fl_Preferences_entries(self.inner) }
}
pub fn entry_exists(&mut self, key: &str) -> bool {
unsafe {
let key = CString::safe_new(key);
Fl_Preferences_entry_exists(self.inner, key.as_ptr()) != 0
}
}
pub fn delete_entry(&mut self, entry: &str) -> Result<(), FltkError> {
unsafe {
let entry = CString::safe_new(entry);
let ret = Fl_Preferences_delete_entry(self.inner, entry.as_ptr());
if ret == 0 {
Err(FltkError::Internal(FltkErrorKind::FailedOperation))
} else {
Ok(())
}
}
}
pub fn delete_all_entries(&mut self) -> Result<(), FltkError> {
unsafe {
let ret = Fl_Preferences_delete_all_entries(self.inner);
if ret == 0 {
Err(FltkError::Internal(FltkErrorKind::FailedOperation))
} else {
Ok(())
}
}
}
pub fn clear(&mut self) -> Result<(), FltkError> {
unsafe {
let ret = Fl_Preferences_clear(self.inner);
if ret == 0 {
Err(FltkError::Internal(FltkErrorKind::FailedOperation))
} else {
Ok(())
}
}
}
}