use crate::{
style_class,
view::View,
views::{self, container, empty, h_stack, Decorators},
IntoView,
};
use floem_reactive::{SignalGet, SignalUpdate};
use super::{create_value_container_signals, value_container, ValueContainer};
style_class!(pub RadioButtonClass);
style_class!(pub RadioButtonDotClass);
style_class!(pub RadioButtonDotSelectedClass);
style_class!(pub LabeledRadioButtonClass);
fn radio_button_svg<T>(represented_value: T, actual_value: impl SignalGet<T> + 'static) -> impl View
where
T: Eq + PartialEq + Clone + 'static,
{
container(empty().class(RadioButtonDotClass).style(move |s| {
s.apply_if(actual_value.get() != represented_value, |s| {
s.display(taffy::style::Display::None)
})
}))
.class(RadioButtonClass)
}
pub struct RadioButton;
impl RadioButton {
#[allow(clippy::new_ret_no_self)]
pub fn new<T>(represented_value: T, actual_value: impl Fn() -> T + 'static) -> ValueContainer<T>
where
T: Eq + PartialEq + Clone + 'static,
{
let (inbound_signal, outbound_signal) = create_value_container_signals(actual_value);
value_container(
radio_button_svg(represented_value.clone(), inbound_signal.read_only())
.keyboard_navigable()
.on_click_stop(move |_| {
outbound_signal.set(represented_value.clone());
}),
move || outbound_signal.get(),
)
}
pub fn new_get<T>(
represented_value: T,
actual_value: impl SignalGet<T> + 'static,
) -> impl IntoView
where
T: Eq + PartialEq + Clone + 'static,
{
radio_button_svg(represented_value, actual_value).keyboard_navigable()
}
pub fn new_rw<T>(
represented_value: T,
actual_value: impl SignalGet<T> + SignalUpdate<T> + Copy + 'static,
) -> impl IntoView
where
T: Eq + PartialEq + Clone + 'static,
{
let cloneable_represented_value = represented_value.clone();
radio_button_svg(cloneable_represented_value.clone(), actual_value)
.keyboard_navigable()
.on_click_stop(move |_| {
actual_value.set(cloneable_represented_value.clone());
})
}
pub fn new_labeled<S: std::fmt::Display + 'static, T>(
represented_value: T,
actual_value: impl Fn() -> T + 'static,
label: impl Fn() -> S + 'static,
) -> ValueContainer<T>
where
T: Eq + PartialEq + Clone + 'static,
{
let (inbound_signal, outbound_signal) = create_value_container_signals(actual_value);
value_container(
h_stack((
radio_button_svg(represented_value.clone(), inbound_signal.read_only()),
views::label(label),
))
.class(LabeledRadioButtonClass)
.style(|s| s.items_center())
.keyboard_navigable()
.on_click_stop(move |_| {
outbound_signal.set(represented_value.clone());
}),
move || outbound_signal.get(),
)
}
pub fn new_labeled_get<S: std::fmt::Display + 'static, T>(
represented_value: T,
actual_value: impl SignalGet<T> + 'static,
label: impl Fn() -> S + 'static,
) -> impl IntoView
where
T: Eq + PartialEq + Clone + 'static,
{
h_stack((
radio_button_svg(represented_value, actual_value),
views::label(label),
))
.class(LabeledRadioButtonClass)
.style(|s| s.items_center())
.keyboard_navigable()
}
pub fn new_labeled_rw<S: std::fmt::Display + 'static, T>(
represented_value: T,
actual_value: impl SignalGet<T> + SignalUpdate<T> + Copy + 'static,
label: impl Fn() -> S + 'static,
) -> impl IntoView
where
T: Eq + PartialEq + Clone + 'static,
{
let cloneable_represented_value = represented_value.clone();
h_stack((
radio_button_svg(cloneable_represented_value.clone(), actual_value),
views::label(label),
))
.class(LabeledRadioButtonClass)
.style(|s| s.items_center())
.keyboard_navigable()
.on_click_stop(move |_| {
actual_value.set(cloneable_represented_value.clone());
})
}
}
pub fn radio_button<T>(
represented_value: T,
actual_value: impl Fn() -> T + 'static,
) -> ValueContainer<T>
where
T: Eq + PartialEq + Clone + 'static,
{
RadioButton::new(represented_value, actual_value)
}
pub fn labeled_radio_button<S: std::fmt::Display + 'static, T>(
represented_value: T,
actual_value: impl Fn() -> T + 'static,
label: impl Fn() -> S + 'static,
) -> ValueContainer<T>
where
T: Eq + PartialEq + Clone + 'static,
{
RadioButton::new_labeled(represented_value, actual_value, label)
}