use std::rc::Rc;
use day_core::*;
use day_reactive::{Signal, bind_seeded};
use day_spec::props::*;
pub enum TextSource {
Static(String),
Dyn(Rc<dyn Fn() -> String>),
}
impl Clone for TextSource {
fn clone(&self) -> Self {
match self {
TextSource::Static(s) => TextSource::Static(s.clone()),
TextSource::Dyn(f) => TextSource::Dyn(f.clone()),
}
}
}
impl TextSource {
pub fn initial(&self) -> String {
match self {
TextSource::Static(s) => s.clone(),
TextSource::Dyn(f) => day_reactive::untrack(|| f()),
}
}
pub(crate) fn resolve(&self) -> String {
match self {
TextSource::Static(s) => s.clone(),
TextSource::Dyn(f) => f(),
}
}
pub(crate) fn bind_to(
self,
node: RNode,
make_patch: impl Fn(String) -> Box<dyn std::any::Any> + 'static,
affects_size: bool,
) {
if let TextSource::Dyn(f) = self {
let seed = day_reactive::untrack(|| f());
bind_seeded(
seed,
move || f(),
move |t: &String| {
let patch = make_patch(t.clone());
with_tree(|tr| tr.patch(node, patch, affects_size));
},
);
}
}
}
pub trait IntoText<M> {
fn into_text(self) -> TextSource;
}
pub struct StaticMark;
pub struct SignalMark;
pub struct FnMark;
pub struct SourceMark;
impl IntoText<SourceMark> for TextSource {
fn into_text(self) -> TextSource {
self
}
}
pub trait IntoFocusBinding<M> {
#[allow(clippy::type_complexity)]
fn into_focus_binding(self) -> (Box<dyn Fn() -> bool>, Box<dyn Fn(bool)>);
}
pub struct FocusBoolMark;
pub struct FocusGroupMark;
impl IntoFocusBinding<FocusBoolMark> for Signal<bool> {
fn into_focus_binding(self) -> (Box<dyn Fn() -> bool>, Box<dyn Fn(bool)>) {
(Box::new(move || self.get()), Box::new(move |f| self.set(f)))
}
}
impl<K: Copy + PartialEq + 'static> IntoFocusBinding<FocusGroupMark> for (Signal<Option<K>>, K) {
fn into_focus_binding(self) -> (Box<dyn Fn() -> bool>, Box<dyn Fn(bool)>) {
let (sig, key) = self;
(
Box::new(move || sig.get() == Some(key)),
Box::new(move |f| {
if f {
sig.set(Some(key));
} else if sig.get_untracked() == Some(key) {
sig.set(None);
}
}),
)
}
}
impl IntoText<StaticMark> for &str {
fn into_text(self) -> TextSource {
TextSource::Static(self.to_owned())
}
}
impl IntoText<StaticMark> for String {
fn into_text(self) -> TextSource {
TextSource::Static(self)
}
}
impl IntoText<SignalMark> for Signal<String> {
fn into_text(self) -> TextSource {
TextSource::Dyn(Rc::new(move || self.get()))
}
}
impl<F, S> IntoText<FnMark> for F
where
F: Fn() -> S + 'static,
S: Into<String>,
{
fn into_text(self) -> TextSource {
TextSource::Dyn(Rc::new(move || self().into()))
}
}
pub enum FractionSource {
Static(f64),
Dyn(Rc<dyn Fn() -> f64>),
}
impl FractionSource {
pub fn initial(&self) -> f64 {
let v = match self {
FractionSource::Static(v) => *v,
FractionSource::Dyn(f) => day_reactive::untrack(|| f()),
};
v.clamp(0.0, 1.0)
}
pub(crate) fn bind_to(self, node: RNode) {
if let FractionSource::Dyn(f) = self {
let seed = day_reactive::untrack(|| f()).clamp(0.0, 1.0);
bind_seeded(
seed,
move || f().clamp(0.0, 1.0),
move |v: &f64| {
with_tree(|tr| tr.patch(node, Box::new(ProgressPatch::Value(Some(*v))), false));
},
);
}
}
}
pub trait IntoFraction<M> {
fn into_fraction(self) -> FractionSource;
}
impl IntoFraction<StaticMark> for f64 {
fn into_fraction(self) -> FractionSource {
FractionSource::Static(self)
}
}
impl IntoFraction<SignalMark> for Signal<f64> {
fn into_fraction(self) -> FractionSource {
FractionSource::Dyn(Rc::new(move || self.get()))
}
}
impl<F> IntoFraction<FnMark> for F
where
F: Fn() -> f64 + 'static,
{
fn into_fraction(self) -> FractionSource {
FractionSource::Dyn(Rc::new(self))
}
}
pub use day_reactive::Binding;