Skip to content

Commit

Permalink
Refactor radio button to use value container (#292)
Browse files Browse the repository at this point in the history
* Replace Copy with Clone

* Refactor radio button to use value container
  • Loading branch information
pieterdd authored Jan 25, 2024
1 parent 7b86afe commit 48ba307
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 69 deletions.
16 changes: 12 additions & 4 deletions examples/flight_booker/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
111 changes: 61 additions & 50 deletions examples/widget-gallery/src/radio_buttons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,63 +33,68 @@ 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);
},
),
))
.style(|s| s.gap(0.0, 10.0).margin_left(5.0))
}),
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),
))
.style(|s| s.gap(0.0, 10.0).margin_left(5.0))
}),
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);
}),
))
}),
Expand All @@ -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),
))
Expand Down
6 changes: 3 additions & 3 deletions src/views/value_container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ pub fn create_value_container_signals<T>(
producer: impl Fn() -> T + 'static,
) -> (RwSignal<T>, RwSignal<T>)
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);
Expand Down
55 changes: 43 additions & 12 deletions src/widgets/radio_button.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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<T>(represented_value: T, actual_value: ReadSignal<T>) -> impl View
pub fn radio_button<T>(
represented_value: T,
actual_value: impl Fn() -> T + 'static,
) -> ValueContainer<T>
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<S: std::fmt::Display + 'static, T>(
represented_value: T,
actual_value: ReadSignal<T>,
actual_value: impl Fn() -> T + 'static,
label: impl Fn() -> S + 'static,
) -> impl View
) -> ValueContainer<T>
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(),
)
}

0 comments on commit 48ba307

Please sign in to comment.