diff --git a/examples/flight_booker/src/main.rs b/examples/flight_booker/src/main.rs index 8d580714..f573eec1 100644 --- a/examples/flight_booker/src/main.rs +++ b/examples/flight_booker/src/main.rs @@ -54,10 +54,18 @@ pub fn app_view() -> impl View { let did_booking = create_rw_signal(false); let mode_picker = h_stack(( - labeled_radio_button(FlightMode::OneWay, flight_mode, || "One way flight") - .on_click_stop(move |_| flight_mode_set.set(FlightMode::OneWay)), - labeled_radio_button(FlightMode::Return, flight_mode, || "Return flight") - .on_click_stop(move |_| flight_mode_set.set(FlightMode::Return)), + labeled_radio_button( + FlightMode::OneWay, + move || flight_mode.get(), + || "One way flight", + ) + .on_click_stop(move |_| flight_mode_set.set(FlightMode::OneWay)), + labeled_radio_button( + FlightMode::Return, + move || flight_mode.get(), + || "Return flight", + ) + .on_click_stop(move |_| flight_mode_set.set(FlightMode::Return)), )); let start_date_input = text_input(start_text) diff --git a/examples/widget-gallery/src/radio_buttons.rs b/examples/widget-gallery/src/radio_buttons.rs index 6e66ed29..a54b318e 100644 --- a/examples/widget-gallery/src/radio_buttons.rs +++ b/examples/widget-gallery/src/radio_buttons.rs @@ -33,19 +33,18 @@ pub fn radio_buttons_view() -> impl View { ( form_item("Radio Buttons:".to_string(), width, move || { v_stack(( - radio_button(OperatingSystem::Windows, operating_system).on_click_stop( - move |_| { - set_operating_system.set(OperatingSystem::Windows); + radio_button(OperatingSystem::Windows, move || operating_system.get()) + .on_update(move |value| { + set_operating_system.set(value); + }), + radio_button(OperatingSystem::MacOS, move || operating_system.get()).on_update( + move |value| { + set_operating_system.set(value); }, ), - radio_button(OperatingSystem::MacOS, operating_system).on_click_stop( - move |_| { - set_operating_system.set(OperatingSystem::MacOS); - }, - ), - radio_button(OperatingSystem::Linux, operating_system).on_click_stop( - move |_| { - set_operating_system.set(OperatingSystem::Linux); + radio_button(OperatingSystem::Linux, move || operating_system.get()).on_update( + move |value| { + set_operating_system.set(value); }, ), )) @@ -53,19 +52,19 @@ pub fn radio_buttons_view() -> impl View { }), form_item("Disabled Radio Buttons:".to_string(), width, move || { v_stack(( - radio_button(OperatingSystem::Windows, operating_system) - .on_click_stop(move |_| { - set_operating_system.set(OperatingSystem::Windows); + radio_button(OperatingSystem::Windows, move || operating_system.get()) + .on_update(move |value| { + set_operating_system.set(value); }) .disabled(|| true), - radio_button(OperatingSystem::MacOS, operating_system) - .on_click_stop(move |_| { - set_operating_system.set(OperatingSystem::MacOS); + radio_button(OperatingSystem::MacOS, move || operating_system.get()) + .on_update(move |value| { + set_operating_system.set(value); }) .disabled(|| true), - radio_button(OperatingSystem::Linux, operating_system) - .on_click_stop(move |_| { - set_operating_system.set(OperatingSystem::Linux); + radio_button(OperatingSystem::Linux, move || operating_system.get()) + .on_update(move |value| { + set_operating_system.set(value); }) .disabled(|| true), )) @@ -73,23 +72,29 @@ pub fn radio_buttons_view() -> impl View { }), form_item("Labelled Radio Buttons:".to_string(), width, move || { v_stack(( - labeled_radio_button(OperatingSystem::Windows, operating_system, || { - OperatingSystem::Windows - }) - .on_click_stop(move |_| { - set_operating_system.set(OperatingSystem::Windows); + labeled_radio_button( + OperatingSystem::Windows, + move || operating_system.get(), + || OperatingSystem::Windows, + ) + .on_update(move |value| { + set_operating_system.set(value); }), - labeled_radio_button(OperatingSystem::MacOS, operating_system, || { - OperatingSystem::MacOS - }) - .on_click_stop(move |_| { - set_operating_system.set(OperatingSystem::MacOS); + labeled_radio_button( + OperatingSystem::MacOS, + move || operating_system.get(), + || OperatingSystem::MacOS, + ) + .on_update(move |value| { + set_operating_system.set(value); }), - labeled_radio_button(OperatingSystem::Linux, operating_system, || { - OperatingSystem::Linux - }) - .on_click_stop(move |_| { - set_operating_system.set(OperatingSystem::Linux); + labeled_radio_button( + OperatingSystem::Linux, + move || operating_system.get(), + || OperatingSystem::Linux, + ) + .on_update(move |value| { + set_operating_system.set(value); }), )) }), @@ -98,25 +103,31 @@ pub fn radio_buttons_view() -> impl View { width, move || { v_stack(( - labeled_radio_button(OperatingSystem::Windows, operating_system, || { - OperatingSystem::Windows - }) - .on_click_stop(move |_| { - set_operating_system.set(OperatingSystem::Windows); + labeled_radio_button( + OperatingSystem::Windows, + move || operating_system.get(), + || OperatingSystem::Windows, + ) + .on_update(move |value| { + set_operating_system.set(value); }) .disabled(|| true), - labeled_radio_button(OperatingSystem::MacOS, operating_system, || { - OperatingSystem::MacOS - }) - .on_click_stop(move |_| { - set_operating_system.set(OperatingSystem::MacOS); + labeled_radio_button( + OperatingSystem::MacOS, + move || operating_system.get(), + || OperatingSystem::MacOS, + ) + .on_update(move |value| { + set_operating_system.set(value); }) .disabled(|| true), - labeled_radio_button(OperatingSystem::Linux, operating_system, || { - OperatingSystem::Linux - }) - .on_click_stop(move |_| { - set_operating_system.set(OperatingSystem::Linux); + labeled_radio_button( + OperatingSystem::Linux, + move || operating_system.get(), + || OperatingSystem::Linux, + ) + .on_update(move |value| { + set_operating_system.set(value); }) .disabled(|| true), )) diff --git a/src/views/value_container.rs b/src/views/value_container.rs index 4b583e7e..2ab0b526 100644 --- a/src/views/value_container.rs +++ b/src/views/value_container.rs @@ -24,17 +24,17 @@ pub fn create_value_container_signals( producer: impl Fn() -> T + 'static, ) -> (RwSignal, RwSignal) where - T: Copy + 'static, + T: Clone + 'static, { let initial_value = producer(); - let inbound_signal = create_rw_signal(initial_value); + let inbound_signal = create_rw_signal(initial_value.clone()); create_effect(move |_| { let checked = producer(); inbound_signal.set(checked); }); - let outbound_signal = create_rw_signal(initial_value); + let outbound_signal = create_rw_signal(initial_value.clone()); create_effect(move |_| { let checked = outbound_signal.get(); inbound_signal.set(checked); diff --git a/src/widgets/radio_button.rs b/src/widgets/radio_button.rs index 658cfa10..7c7aa4cc 100644 --- a/src/widgets/radio_button.rs +++ b/src/widgets/radio_button.rs @@ -1,7 +1,10 @@ use crate::{ style_class, view::View, - views::{self, container, empty, h_stack, Decorators}, + views::{ + self, container, create_value_container_signals, empty, h_stack, value_container, + Decorators, ValueContainer, + }, }; use floem_reactive::ReadSignal; @@ -24,27 +27,55 @@ where /// Renders a radio button that appears as selected if the signal equals the given enum value. /// Can be combined with a label and a stack with a click event (as in `examples/widget-gallery`). -pub fn radio_button(represented_value: T, actual_value: ReadSignal) -> impl View +pub fn radio_button( + represented_value: T, + actual_value: impl Fn() -> T + 'static, +) -> ValueContainer where T: Eq + PartialEq + Clone + 'static, { - radio_button_svg(represented_value, actual_value).keyboard_navigatable() + let (inbound_signal, outbound_signal) = create_value_container_signals(actual_value); + let cloneable_represented_value = represented_value.clone(); + + value_container( + radio_button_svg( + cloneable_represented_value.clone(), + inbound_signal.read_only(), + ) + .keyboard_navigatable() + .on_click_stop(move |_| { + outbound_signal.set(cloneable_represented_value.clone()); + }), + move || outbound_signal.get(), + ) } /// Renders a radio button that appears as selected if the signal equals the given enum value. pub fn labeled_radio_button( represented_value: T, - actual_value: ReadSignal, + actual_value: impl Fn() -> T + 'static, label: impl Fn() -> S + 'static, -) -> impl View +) -> ValueContainer 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_navigatable() + let (inbound_signal, outbound_signal) = create_value_container_signals(actual_value); + let cloneable_represented_value = represented_value.clone(); + + value_container( + h_stack(( + radio_button_svg( + cloneable_represented_value.clone(), + inbound_signal.read_only(), + ), + views::label(label), + )) + .class(LabeledRadioButtonClass) + .style(|s| s.items_center()) + .keyboard_navigatable() + .on_click_stop(move |_| { + outbound_signal.set(cloneable_represented_value.clone()); + }), + move || outbound_signal.get(), + ) }