Skip to content

Commit f1a6b87

Browse files
authored
Change feathers bsn APIs to make captions an explicit parameter. (#23787)
# Objective As discussed in [this discord thread](https://discord.com/channels/691052431525675048/1492688648360165406), using the `Children` relation to append caption elements to feathers widgets is dodgy. ## Solution Make `caption` an explicit parameter for button, radio, and checkbox widgets. Also fixed some erroneous docs. ## Testing Manual testing of feathers and bevy_city examples. Note that there's no migration guide because this only affects the bsn functions, which are new.
1 parent f8bdd2b commit f1a6b87

File tree

7 files changed

+169
-56
lines changed

7 files changed

+169
-56
lines changed

crates/bevy_feathers/src/controls/button.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,26 @@ pub enum ButtonVariant {
4343
}
4444

4545
/// Parameters for the button template, passed to [`button`] function.
46-
#[derive(Default)]
4746
pub struct ButtonProps {
47+
/// Label for this button. This can contain multiple entities, which will be contained
48+
/// in a horizontal flexbox.
49+
pub caption: Box<dyn SceneList>,
4850
/// Color variant for the button.
4951
pub variant: ButtonVariant,
5052
/// Rounded corners options
5153
pub corners: RoundedCorners,
5254
}
5355

56+
impl Default for ButtonProps {
57+
fn default() -> Self {
58+
Self {
59+
caption: Box::new(bsn_list!()),
60+
variant: ButtonVariant::default(),
61+
corners: Default::default(),
62+
}
63+
}
64+
}
65+
5466
/// Scene function to spawn a button.
5567
///
5668
/// # Arguments
@@ -85,15 +97,25 @@ pub fn button(props: ButtonProps) -> impl Scene {
8597
font_size: FontSize::Px(14.0),
8698
weight: FontWeight::NORMAL,
8799
}
100+
Children [
101+
{props.caption}
102+
]
88103
}
89104
}
90105

106+
/// Parameters for the [`button_bundle`] template.
107+
#[derive(Default)]
108+
pub struct ButtonBundleProps {
109+
/// Color variant for the button.
110+
pub variant: ButtonVariant,
111+
/// Rounded corners options
112+
pub corners: RoundedCorners,
113+
}
114+
91115
/// Template function to spawn a button.
92116
///
93117
/// # Arguments
94118
/// * `props` - construction properties for the button.
95-
/// * `overrides` - a bundle of components that are merged in with the normal button components.
96-
/// * `children` - a [`SpawnableList`] of child elements, such as a label or icon for the button.
97119
///
98120
/// # Emitted events
99121
/// * [`bevy_ui_widgets::Activate`] when any of the following happens:
@@ -103,7 +125,7 @@ pub fn button(props: ButtonProps) -> impl Scene {
103125
/// These events can be disabled by adding an [`bevy_ui::InteractionDisabled`] component to the entity
104126
#[deprecated(since = "0.19.0", note = "Use the button() BSN function")]
105127
pub fn button_bundle<C: SpawnableList<ChildOf> + Send + Sync + 'static, B: Bundle>(
106-
props: ButtonProps,
128+
props: ButtonBundleProps,
107129
overrides: B,
108130
children: C,
109131
) -> impl Bundle {

crates/bevy_feathers/src/controls/checkbox.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ use crate::{
3434
tokens,
3535
};
3636

37+
/// Parameters for the checkbox template, passed to [`checkbox`] function.
38+
pub struct CheckboxProps {
39+
/// Label for this checkbox. This can contain multiple entities, which will be contained
40+
/// in a flexbox.
41+
pub caption: Box<dyn SceneList>,
42+
}
43+
44+
impl Default for CheckboxProps {
45+
fn default() -> Self {
46+
Self {
47+
caption: Box::new(bsn_list!()),
48+
}
49+
}
50+
}
51+
3752
/// Marker for the checkbox frame (contains both checkbox and label)
3853
#[derive(Component, Default, Clone, Reflect)]
3954
#[reflect(Component, Clone, Default)]
@@ -55,7 +70,7 @@ struct CheckboxMark;
5570
/// * [`bevy_ui_widgets::ValueChange<bool>`] with the new value when the checkbox changes state.
5671
///
5772
/// These events can be disabled by adding an [`bevy_ui::InteractionDisabled`] component to the entity
58-
pub fn checkbox() -> impl Scene {
73+
pub fn checkbox(props: CheckboxProps) -> impl Scene {
5974
bsn! {
6075
Node {
6176
display: Display::Flex,
@@ -102,22 +117,20 @@ pub fn checkbox() -> impl Scene {
102117
UiTransform::from_rotation(Rot2::FRAC_PI_4)
103118
CheckboxMark
104119
ThemeBorderColor(tokens::CHECKBOX_MARK)
105-
)]
106-
)]
120+
)]),
121+
{props.caption}
122+
]
107123
}
108124
}
109125

110126
/// Template function to spawn a checkbox.
111127
///
112-
/// # Arguments
113-
/// * `props` - construction properties for the checkbox.
114-
/// * `overrides` - a bundle of components that are merged in with the normal checkbox components.
115-
/// * `label` - the label of the checkbox.
128+
/// This version does not take any props. A caption can be set by appending a child entity.
116129
///
117130
/// # Emitted events
118131
/// * [`bevy_ui_widgets::ValueChange<bool>`] with the new value when the checkbox changes state.
119132
///
120-
/// These events can be disabled by adding an [`bevy_ui::InteractionDisabled`] component to the entity
133+
/// These events can be disabled by adding an [`bevy_ui::InteractionDisabled`] component to the entity
121134
#[deprecated(since = "0.19.0", note = "Use the checkbox() BSN function")]
122135
pub fn checkbox_bundle<C: SpawnableList<ChildOf> + Send + Sync + 'static, B: Bundle>(
123136
overrides: B,

crates/bevy_feathers/src/controls/menu.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,15 @@ fn on_menu_event(
166166
pub fn menu_button(props: MenuButtonProps) -> impl Scene {
167167
bsn! {
168168
:button(ButtonProps {
169+
caption: props.caption,
169170
variant: ButtonVariant::Normal,
170171
corners: props.corners,
171172
})
172173
ActivateOnPress
173174
MenuButton
174175
FeathersMenuButton
176+
// Additional children for menu chevron
175177
Children [
176-
{props.caption},
177178
{
178179
if props.arrow {
179180
Box::new(bsn_list!(

crates/bevy_feathers/src/controls/radio.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,29 @@ struct RadioOutline;
4343
#[reflect(Component, Clone, Default)]
4444
struct RadioMark;
4545

46+
/// Parameters for the radio button template, passed to [`radio`] function.
47+
pub struct RadioProps {
48+
/// Label for this radio button. This can contain multiple entities, which will be contained
49+
/// in a flexbox.
50+
pub caption: Box<dyn SceneList>,
51+
}
52+
53+
impl Default for RadioProps {
54+
fn default() -> Self {
55+
Self {
56+
caption: Box::new(bsn_list!()),
57+
}
58+
}
59+
}
60+
4661
/// Scene function to spawn a radio.
4762
///
4863
/// # Emitted events
4964
/// * [`bevy_ui_widgets::ValueChange<bool>`] with the value true when it becomes checked.
5065
/// * [`bevy_ui_widgets::ValueChange<Entity>`] with the selected entity's id when a new radio button is selected.
5166
///
5267
/// These events can be disabled by adding an [`bevy_ui::InteractionDisabled`] component to the entity
53-
pub fn radio() -> impl Scene {
68+
pub fn radio(props: RadioProps) -> impl Scene {
5469
bsn! {
5570
Node {
5671
display: Display::Flex,
@@ -91,17 +106,15 @@ pub fn radio() -> impl Scene {
91106
}
92107
RadioMark
93108
ThemeBackgroundColor(tokens::RADIO_MARK)
94-
)]
95-
)]
109+
)]),
110+
{props.caption}
111+
]
96112
}
97113
}
98114

99115
/// Template function to spawn a radio.
100116
///
101-
/// # Arguments
102-
/// * `props` - construction properties for the radio.
103-
/// * `overrides` - a bundle of components that are merged in with the normal radio components.
104-
/// * `label` - the label of the radio.
117+
/// This version does not take any props. A caption can be set by appending a child entity.
105118
///
106119
/// # Emitted events
107120
/// * [`bevy_ui_widgets::ValueChange<bool>`] with the value true when it becomes checked.

crates/bevy_feathers/src/controls/virtual_keyboard.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use bevy_ui::Val;
66
use bevy_ui::{widget::Text, FlexDirection};
77
use bevy_ui_widgets::{observe, Activate};
88

9-
use crate::controls::button::{button, ButtonProps};
9+
use crate::controls::button::{button, ButtonBundleProps, ButtonProps};
1010
use crate::controls::button_bundle;
1111

1212
/// Fired whenever a virtual key is pressed.
@@ -104,7 +104,11 @@ where
104104
},
105105
Children::spawn(SpawnIter(row.into_iter().map(move |key| {
106106
(
107-
button_bundle(ButtonProps::default(), (), Spawn(Text::new(key.as_ref()))),
107+
button_bundle(
108+
ButtonBundleProps::default(),
109+
(),
110+
Spawn(Text::new(key.as_ref())),
111+
),
108112
observe(
109113
move |activate: On<Activate>,
110114
mut commands: Commands,

examples/large_scenes/bevy_city/src/settings.rs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use bevy::{
33
camera_controller::free_camera::FreeCameraState,
44
feathers::{
55
self,
6-
controls::{button, checkbox, ButtonProps},
6+
controls::{button, checkbox, ButtonProps, CheckboxProps},
77
theme::{ThemeBackgroundColor, ThemedText},
88
},
99
pbr::wireframe::WireframeConfig,
@@ -67,16 +67,23 @@ pub fn settings_ui() -> impl Scene {
6767
Children [
6868
Text("Settings"),
6969
(
70-
checkbox()
70+
checkbox(CheckboxProps {
71+
caption: Box::new(bsn_list!(
72+
(Text("Simulate Cars") ThemedText),
73+
)),
74+
})
7175
Checked
7276
on(checkbox_self_update)
7377
on(|change: On<ValueChange<bool>>, mut settings: ResMut<Settings>| {
7478
settings.simulate_cars = change.value;
7579
})
76-
Children [ (Text("Simulate Cars") ThemedText) ]
7780
),
7881
(
79-
checkbox()
82+
checkbox(CheckboxProps {
83+
caption: Box::new(bsn_list!(
84+
(Text("Shadow maps enabled") ThemedText),
85+
)),
86+
})
8087
Checked
8188
on(checkbox_self_update)
8289
on(
@@ -90,10 +97,13 @@ pub fn settings_ui() -> impl Scene {
9097
}
9198
}
9299
)
93-
Children [ (Text("Shadow maps enabled") ThemedText) ]
94100
),
95101
(
96-
checkbox()
102+
checkbox(CheckboxProps {
103+
caption: Box::new(bsn_list!(
104+
(Text("Contact shadows enabled") ThemedText),
105+
)),
106+
})
97107
Checked
98108
on(checkbox_self_update)
99109
on(
@@ -107,10 +117,13 @@ pub fn settings_ui() -> impl Scene {
107117
}
108118
}
109119
)
110-
Children [ (Text("Contact shadows enabled") ThemedText) ]
111120
),
112121
(
113-
checkbox()
122+
checkbox(CheckboxProps {
123+
caption: Box::new(bsn_list!(
124+
(Text("Wireframe Enabled") ThemedText),
125+
)),
126+
})
114127
on(checkbox_self_update)
115128
on(
116129
|change: On<ValueChange<bool>>,
@@ -120,10 +133,13 @@ pub fn settings_ui() -> impl Scene {
120133
wireframe_config.global = change.value;
121134
}
122135
)
123-
Children [ (Text("Wireframe Enabled") ThemedText) ]
124136
),
125137
(
126-
checkbox()
138+
checkbox(CheckboxProps {
139+
caption: Box::new(bsn_list!(
140+
(Text("CPU culling") ThemedText),
141+
)),
142+
})
127143
Checked
128144
on(checkbox_self_update)
129145
on(
@@ -142,10 +158,14 @@ pub fn settings_ui() -> impl Scene {
142158
}
143159
}
144160
)
145-
Children [ (Text("CPU culling") ThemedText) ]
146161
),
147162
(
148-
button(ButtonProps::default())
163+
button(ButtonProps {
164+
caption: Box::new(bsn_list!(
165+
(Text("Regenerate City") ThemedText),
166+
)),
167+
..Default::default()
168+
})
149169
on(
150170
|_activate: On<Activate>,
151171
mut commands: Commands,
@@ -159,7 +179,6 @@ pub fn settings_ui() -> impl Scene {
159179
spawn_city(&mut commands, &assets, seed, 32);
160180
}
161181
)
162-
Children [ (Text("Regenerate City") ThemedText) ]
163182
),
164183
]
165184
)]

0 commit comments

Comments
 (0)