use std::fmt;
use glib::{Type, translate::*, value::ToValue};
use crate::conv::{gvalue_slice_to_gvalue, ptr_array_gtype};
#[derive(Debug, Clone, PartialEq)]
pub struct ConvError(String);
impl ConvError {
pub fn new<S: AsRef<str>>(message: S) -> Self {
Self(message.as_ref().to_owned())
}
}
impl fmt::Display for ConvError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Value conversion failed: {}", self.0)
}
}
impl std::error::Error for ConvError {}
pub trait TryFromXfconfValue: Sized {
fn try_from_xfconf_value(value: &glib::Value) -> Result<Self, ConvError>;
fn xfconf_display_name() -> &'static str;
}
pub trait ToXfconfValue {
fn to_xfconf_value(&self) -> glib::Value;
}
pub trait XfconfGValueExt {
#[doc(alias = "xfconf_g_value_get_uint16")]
fn get_u16(&self) -> Option<u16>;
#[doc(alias = "xfconf_g_value_get_int16")]
fn get_i16(&self) -> Option<i16>;
}
impl XfconfGValueExt for glib::Value {
fn get_u16(&self) -> Option<u16> {
if self.type_() == XfconfGType::u16() {
Some(unsafe { crate::ffi::xfconf_g_value_get_uint16(self.as_ptr()) })
} else {
None
}
}
fn get_i16(&self) -> Option<i16> {
if self.type_() == XfconfGType::i16() {
Some(unsafe { crate::ffi::xfconf_g_value_get_int16(self.as_ptr()) })
} else {
None
}
}
}
pub struct XfconfGType;
impl XfconfGType {
#[doc(alias = "xfconf_int16_get_type")]
pub fn u16() -> glib::Type {
unsafe { glib::Type::from_glib(ffi::xfconf_uint16_get_type()) }
}
#[doc(alias = "xfconf_g_value_set_uint16")]
pub fn value_from_u16(v: u16) -> glib::Value {
let value = glib::Value::from_type(Self::u16());
unsafe { crate::ffi::xfconf_g_value_set_uint16(value.as_ptr(), v) };
value
}
#[doc(alias = "xfconf_int16_get_type")]
pub fn i16() -> glib::Type {
unsafe { glib::Type::from_glib(ffi::xfconf_int16_get_type()) }
}
#[doc(alias = "xfconf_g_value_set_int16")]
pub fn value_from_i16(v: i16) -> glib::Value {
let value = glib::Value::from_type(Self::i16());
unsafe { crate::ffi::xfconf_g_value_set_int16(value.as_ptr(), v) };
value
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Color {
pub red: f64,
pub green: f64,
pub blue: f64,
pub alpha: f64,
}
impl TryFrom<&glib::Value> for Color {
type Error = ConvError;
fn try_from(value: &glib::Value) -> Result<Self, Self::Error> {
use glib::translate::*;
use glib::{ffi as glib_ffi, gobject_ffi};
if value.type_().into_glib() == unsafe { glib_ffi::g_ptr_array_get_type() } {
eprintln!("it's a gptrarray!");
let array_ptr = unsafe { gobject_ffi::g_value_get_boxed(value.as_ptr()) }
as *mut glib_ffi::GPtrArray;
if !array_ptr.is_null() {
let values: Vec<glib::Value> =
unsafe { FromGlibPtrArrayContainerAsVec::from_glib_none_as_vec(array_ptr) };
let mut iter = values.iter().fuse();
let red = iter.next();
let green = iter.next();
let blue = iter.next();
let alpha = iter.next();
match (red, green, blue, alpha) {
(Some(red), Some(green), Some(blue), Some(alpha)) => {
if red.type_() == Type::F64
&& green.type_() == Type::F64
&& blue.type_() == Type::F64
&& alpha.type_() == Type::F64
{
Ok(Color {
red: red.get().unwrap(),
green: green.get().unwrap(),
blue: blue.get().unwrap(),
alpha: alpha.get().unwrap(),
})
} else {
Err(ConvError::new("Wrong types for color component values"))
}
}
_ => Err(ConvError::new("Too few color components")),
}
} else {
Err(ConvError::new("Color array was NULL"))
}
} else {
Err(ConvError::new("Color array was not a GPtrArray"))
}
}
}
impl ToValue for Color {
fn to_value(&self) -> glib::Value {
let values = vec![self.red, self.green, self.blue, self.alpha];
gvalue_slice_to_gvalue(&values)
}
fn value_type(&self) -> Type {
ptr_array_gtype()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
pub fn test_rgba_color_roundtrip() {
let c = Color {
red: 1.0,
green: 0.5,
blue: 0.25,
alpha: 0.75,
};
let v = c.to_xfconf_value();
let c1 = Color::try_from_xfconf_value(&v).unwrap();
assert_eq!(c, c1);
}
}