use alloc::boxed::Box;
use crate::color::WuiResolvedColor;
use crate::components::text::WuiResolvedFont;
use crate::{IntoFFI, IntoRust, WuiEnv, ffi_computed, ffi_computed_ctor, reactive::WuiComputed};
use nami::SignalExt;
use waterui::theme::{
self, color, install_color_scheme, install_color_signal, install_font_signal,
};
use waterui_core::resolve::Resolvable;
use waterui_graphics::color::ResolvedColor;
use waterui_text::font::{Body, Caption, Footnote, Headline, ResolvedFont, Subheadline, Title};
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WuiColorScheme {
Light = 0,
Dark = 1,
}
impl From<WuiColorScheme> for theme::ColorScheme {
fn from(value: WuiColorScheme) -> Self {
match value {
WuiColorScheme::Light => Self::Light,
WuiColorScheme::Dark => Self::Dark,
}
}
}
impl From<theme::ColorScheme> for WuiColorScheme {
fn from(value: theme::ColorScheme) -> Self {
match value {
theme::ColorScheme::Light => Self::Light,
theme::ColorScheme::Dark => Self::Dark,
}
}
}
impl IntoFFI for theme::ColorScheme {
type FFI = WuiColorScheme;
fn into_ffi(self) -> Self::FFI {
self.into()
}
}
impl IntoRust for WuiColorScheme {
type Rust = theme::ColorScheme;
unsafe fn into_rust(self) -> Self::Rust {
self.into()
}
}
ffi_computed!(theme::ColorScheme, WuiColorScheme, color_scheme);
ffi_computed_ctor!(theme::ColorScheme, WuiColorScheme, color_scheme);
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_theme_install_color_scheme(
env: *mut WuiEnv,
signal: *mut WuiComputed<theme::ColorScheme>,
) {
let env = unsafe { crate::borrow_ffi_mut(env) };
let computed = unsafe { Box::from_raw(signal) }.0;
install_color_scheme(env, computed);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_theme_color_scheme(
env: *const WuiEnv,
) -> *mut WuiComputed<theme::ColorScheme> {
let env = unsafe { crate::borrow_ffi(env) };
let computed = theme::current_color_scheme(env);
computed.into_ffi()
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WuiColorSlot {
Background = 0,
Surface = 1,
SurfaceVariant = 2,
Border = 3,
Foreground = 4,
MutedForeground = 5,
Accent = 6,
AccentForeground = 7,
AccentContainer = 8,
Tertiary = 9,
TertiaryContainer = 10,
SelectionContainer = 11,
SelectionForeground = 12,
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_theme_install_color(
env: *mut WuiEnv,
slot: WuiColorSlot,
signal: *mut WuiComputed<ResolvedColor>,
) {
let env = unsafe { crate::borrow_ffi_mut(env) };
let computed = unsafe { Box::from_raw(signal) }.0;
match slot {
WuiColorSlot::Background => install_color_signal::<color::Background>(env, computed),
WuiColorSlot::Surface => install_color_signal::<color::Surface>(env, computed),
WuiColorSlot::SurfaceVariant => {
install_color_signal::<color::SurfaceVariant>(env, computed);
}
WuiColorSlot::Border => install_color_signal::<color::Border>(env, computed),
WuiColorSlot::Foreground => install_color_signal::<color::Foreground>(env, computed),
WuiColorSlot::MutedForeground => {
install_color_signal::<color::MutedForeground>(env, computed);
}
WuiColorSlot::Accent => install_color_signal::<color::Accent>(env, computed),
WuiColorSlot::AccentForeground => {
install_color_signal::<color::AccentForeground>(env, computed);
}
WuiColorSlot::AccentContainer => {
install_color_signal::<color::AccentContainer>(env, computed);
}
WuiColorSlot::Tertiary => install_color_signal::<color::Tertiary>(env, computed),
WuiColorSlot::TertiaryContainer => {
install_color_signal::<color::TertiaryContainer>(env, computed);
}
WuiColorSlot::SelectionContainer => {
install_color_signal::<color::SelectionContainer>(env, computed);
}
WuiColorSlot::SelectionForeground => {
install_color_signal::<color::SelectionForeground>(env, computed);
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_theme_color(
env: *const WuiEnv,
slot: WuiColorSlot,
) -> *mut WuiComputed<ResolvedColor> {
let env = unsafe { crate::borrow_ffi(env) };
let computed = match slot {
WuiColorSlot::Background => color::Background.resolve(env).computed(),
WuiColorSlot::Surface => color::Surface.resolve(env).computed(),
WuiColorSlot::SurfaceVariant => color::SurfaceVariant.resolve(env).computed(),
WuiColorSlot::Border => color::Border.resolve(env).computed(),
WuiColorSlot::Foreground => color::Foreground.resolve(env).computed(),
WuiColorSlot::MutedForeground => color::MutedForeground.resolve(env).computed(),
WuiColorSlot::Accent => color::Accent.resolve(env).computed(),
WuiColorSlot::AccentForeground => color::AccentForeground.resolve(env).computed(),
WuiColorSlot::AccentContainer => color::AccentContainer.resolve(env).computed(),
WuiColorSlot::Tertiary => color::Tertiary.resolve(env).computed(),
WuiColorSlot::TertiaryContainer => color::TertiaryContainer.resolve(env).computed(),
WuiColorSlot::SelectionContainer => color::SelectionContainer.resolve(env).computed(),
WuiColorSlot::SelectionForeground => color::SelectionForeground.resolve(env).computed(),
};
computed.into_ffi()
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WuiFontSlot {
Body = 0,
Title = 1,
Headline = 2,
Subheadline = 3,
Caption = 4,
Footnote = 5,
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_theme_install_font(
env: *mut WuiEnv,
slot: WuiFontSlot,
signal: *mut WuiComputed<ResolvedFont>,
) {
let env = unsafe { crate::borrow_ffi_mut(env) };
let computed = unsafe { Box::from_raw(signal) }.0;
match slot {
WuiFontSlot::Body => install_font_signal::<Body>(env, computed),
WuiFontSlot::Title => install_font_signal::<Title>(env, computed),
WuiFontSlot::Headline => install_font_signal::<Headline>(env, computed),
WuiFontSlot::Subheadline => install_font_signal::<Subheadline>(env, computed),
WuiFontSlot::Caption => install_font_signal::<Caption>(env, computed),
WuiFontSlot::Footnote => install_font_signal::<Footnote>(env, computed),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn waterui_theme_font(
env: *const WuiEnv,
slot: WuiFontSlot,
) -> *mut WuiComputed<ResolvedFont> {
let env = unsafe { crate::borrow_ffi(env) };
let computed = match slot {
WuiFontSlot::Body => Body.resolve(env).computed(),
WuiFontSlot::Title => Title.resolve(env).computed(),
WuiFontSlot::Headline => Headline.resolve(env).computed(),
WuiFontSlot::Subheadline => Subheadline.resolve(env).computed(),
WuiFontSlot::Caption => Caption.resolve(env).computed(),
WuiFontSlot::Footnote => Footnote.resolve(env).computed(),
};
computed.into_ffi()
}
crate::ffi_watcher_notify!(theme::ColorScheme, WuiColorScheme, color_scheme);
crate::ffi_watcher_notify!(ResolvedColor, WuiResolvedColor, resolved_color);
crate::ffi_watcher_notify!(ResolvedFont, WuiResolvedFont, resolved_font);
#[cfg(all(test, feature = "c-api"))]
mod tests {
use super::*;
use crate::WuiEnv;
#[test]
fn color_scheme_roundtrip() {
let ptr = waterui::Computed::constant(theme::ColorScheme::Dark).into_ffi();
assert!(!ptr.is_null());
let value = unsafe { waterui_read_computed_color_scheme(ptr) };
assert_eq!(value, WuiColorScheme::Dark);
unsafe {
waterui_drop_computed_color_scheme(ptr);
}
}
#[test]
fn slot_based_color_install_and_query() {
let mut env = WuiEnv(waterui::Environment::new());
let fg_signal = waterui::Computed::constant(ResolvedColor {
red: 1.0,
green: 0.0,
blue: 0.0,
headroom: 0.0,
opacity: 1.0,
});
let fg_ptr = fg_signal.into_ffi();
unsafe {
waterui_theme_install_color(&raw mut env, WuiColorSlot::Foreground, fg_ptr);
}
let queried = unsafe { waterui_theme_color(&raw const env, WuiColorSlot::Foreground) };
assert!(!queried.is_null());
let value = unsafe { crate::color::waterui_read_computed_resolved_color(queried) };
assert!((value.red - 1.0).abs() < 0.001);
unsafe {
crate::color::waterui_drop_computed_resolved_color(queried);
}
}
}