use crate::{IntoFFI, IntoRust, WuiEnv, ffi_computed, ffi_computed_ctor, reactive::WuiComputed};
use waterui::{Color, Signal};
use waterui_core::{Environment, resolve::Resolvable};
use waterui_graphics::color::ResolvedColor;
opaque!(WuiColor, Color);
into_ffi!(
ResolvedColor,
pub struct WuiResolvedColor {
red: f32,
green: f32,
blue: f32,
opacity: f32,
headroom: f32,
}
);
impl IntoRust for WuiResolvedColor {
type Rust = ResolvedColor;
unsafe fn into_rust(self) -> Self::Rust {
ResolvedColor {
red: self.red,
green: self.green,
blue: self.blue,
opacity: self.opacity,
headroom: self.headroom,
}
}
}
ffi_computed!(ResolvedColor, WuiResolvedColor);
ffi_computed_ctor!(ResolvedColor, WuiResolvedColor);
crate::ffi_binding!(Color, *mut WuiColor, color);
#[cfg(feature = "c-api")]
crate::ffi_watcher!(Color, *mut WuiColor, color);
ffi_view!(ResolvedColor, WuiResolvedColor, resolved_color);
#[cfg(feature = "c-api")]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_force_as_color(view: *mut crate::WuiAnyView) -> *mut WuiColor {
let any: waterui::AnyView = unsafe { IntoRust::into_rust(view) };
let native = unsafe { *any.downcast_unchecked::<waterui_core::Native<Color>>() };
native.into_ffi()
}
#[cfg(feature = "c-api")]
#[unsafe(no_mangle)]
pub extern "C" fn waterui_color_id() -> crate::WuiTypeId {
crate::WuiTypeId::of::<waterui_core::Native<Color>>()
}
#[cfg(feature = "android-jni")]
#[unsafe(no_mangle)]
extern "system" fn Java_dev_waterui_android_ffi_WatcherJni_colorId<'local>(
mut env: crate::jni::JNIEnv<'local>,
_class: crate::jni::JClass<'local>,
) -> crate::jni::jobject {
crate::jni::with_env(&mut env, |env| {
crate::jni::type_id_to_java(env, crate::WuiTypeId::of::<waterui_core::Native<Color>>())
.into_raw()
})
}
#[cfg(feature = "android-jni")]
#[unsafe(no_mangle)]
unsafe extern "system" fn Java_dev_waterui_android_ffi_WatcherJni_forceAsColor<'local>(
_env: crate::jni::JNIEnv<'local>,
_class: crate::jni::JClass<'local>,
view_ptr: crate::jni::jlong,
) -> crate::jni::jlong {
let view = view_ptr as *mut crate::WuiAnyView;
let any: waterui::AnyView = unsafe { IntoRust::into_rust(view) };
let native = unsafe { *any.downcast_unchecked::<waterui_core::Native<Color>>() };
native.into_ffi() as crate::jni::jlong
}
#[cfg(feature = "android-jni")]
impl crate::jni::JniPrimitive for Color {
type Jni = jni::sys::jlong;
fn to_jni(self) -> Self::Jni {
self.into_ffi() as Self::Jni
}
fn from_jni(val: Self::Jni) -> Self {
unsafe { IntoRust::into_rust(val as *mut WuiColor) }
}
}
crate::jni_binding_primitive!(Color, color);
#[derive(Debug, Clone)]
struct LinearResolvedColor {
resolved: ResolvedColor,
}
impl Resolvable for LinearResolvedColor {
type Resolved = ResolvedColor;
fn resolve(&self, _env: &Environment) -> impl Signal<Output = Self::Resolved> {
self.resolved
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_color_from_linear_rgba_headroom(
red: f32,
green: f32,
blue: f32,
alpha: f32,
headroom: f32,
) -> *mut WuiColor {
let resolved = ResolvedColor {
red,
green,
blue,
opacity: alpha.clamp(0.0, 1.0),
headroom: headroom.max(0.0),
};
Color::new(LinearResolvedColor { resolved }).into_ffi()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_color_from_srgba(
red: f32,
green: f32,
blue: f32,
alpha: f32,
) -> *mut WuiColor {
let mut resolved =
ResolvedColor::from_srgb(waterui_graphics::color::Srgb::new(red, green, blue));
resolved.opacity = alpha.clamp(0.0, 1.0);
Color::new(LinearResolvedColor { resolved }).into_ffi()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_resolve_color(
color: *const WuiColor,
env: *const WuiEnv,
) -> *mut WuiComputed<ResolvedColor> {
unsafe {
let color = &*color;
let env = &*env;
let resolved = color.resolve(env);
resolved.into_ffi()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn srgba_constructor_decodes_transfer_function() {
let pointer = unsafe { waterui_color_from_srgba(0.5, 0.5, 0.5, 0.25) };
let color: Color = unsafe { IntoRust::into_rust(pointer) };
let resolved = color.resolve(&Environment::new()).get();
assert!((resolved.red - 0.214_041_14).abs() < 1.0e-6);
assert!((resolved.green - 0.214_041_14).abs() < 1.0e-6);
assert!((resolved.blue - 0.214_041_14).abs() < 1.0e-6);
assert!((resolved.opacity - 0.25).abs() < f32::EPSILON);
}
}