Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ bevy_log = ["bevy_internal/bevy_log"]
bevy_input_focus = ["bevy_internal/bevy_input_focus"]

# Headless widget collection for Bevy UI.
bevy_ui_widgets = ["bevy_internal/bevy_ui_widgets"]
bevy_ui_widgets = ["bevy_internal/bevy_ui_widgets", "bevy_input_focus"]

# Feathers widget collection.
experimental_bevy_feathers = ["bevy_internal/bevy_feathers", "bevy_ui_widgets"]
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_input_focus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ impl Traversal<AcquireFocus> for WindowTraversal {
///
/// To add bubbling to your own input events, add the [`dispatch_focused_input::<MyEvent>`](dispatch_focused_input) system to your app,
/// as described in the docs for [`FocusedInput`].
#[derive(Default)]
pub struct InputDispatchPlugin;

impl Plugin for InputDispatchPlugin {
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_internal/src/default_plugins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ plugin_group! {
bevy_transform:::TransformPlugin,
bevy_diagnostic:::DiagnosticsPlugin,
bevy_input:::InputPlugin,
// NOTE: Assuming FeathersPlugin is added when "bevy_feathers" is enabled,
// This is not included due to the redundancy.
#[custom(cfg(all(feature = "bevy_input_focus", not(feature = "bevy_feathers"))))]
bevy_input_focus:::InputDispatchPlugin,
#[custom(cfg(not(feature = "bevy_window")))]
bevy_app:::ScheduleRunnerPlugin,
#[cfg(feature = "bevy_window")]
Expand Down Expand Up @@ -65,6 +69,8 @@ plugin_group! {
bevy_ui:::UiPlugin,
#[cfg(feature = "bevy_ui_render")]
bevy_ui_render:::UiRenderPlugin,
#[custom(cfg(any(feature = "bevy_ui_widgets", feature = "bevy_feathers")))]
bevy_ui_widgets:::UiWidgetsButtonPlugin,
#[cfg(feature = "bevy_gltf")]
bevy_gltf:::GltfPlugin,
#[cfg(feature = "bevy_pbr")]
Expand Down
5 changes: 3 additions & 2 deletions crates/bevy_ui_widgets/src/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,10 @@ fn button_on_pointer_cancel(
}

/// Plugin that adds the observers for the [`Button`] widget.
pub struct ButtonPlugin;
#[derive(Default)]
pub struct UiWidgetsButtonPlugin;

impl Plugin for ButtonPlugin {
impl Plugin for UiWidgetsButtonPlugin {
fn build(&self, app: &mut App) {
app.add_observer(button_on_key_event)
.add_observer(button_on_pointer_down)
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_ui_widgets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ use crate::popover::PopoverPlugin;

/// A plugin group that registers the observers for all of the widgets in this crate. If you don't want to
/// use all of the widgets, you can import the individual widget plugins instead.
/// [`button::UiWidgetsButtonPlugin`] is part of [`DefaultPlugins`].
#[derive(Default)]
pub struct UiWidgetsPlugins;

impl PluginGroup for UiWidgetsPlugins {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>()
.add(PopoverPlugin)
.add(ButtonPlugin)
.add(CheckboxPlugin)
.add(MenuPlugin)
.add(RadioGroupPlugin)
Expand Down
13 changes: 4 additions & 9 deletions examples/2d/dynamic_mip_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,22 +225,17 @@ fn main() {
.add_systems(Update, animate_image_scale)
.add_systems(
Update,
(
widgets::handle_ui_interactions::<AppSetting>,
update_radio_buttons,
)
.chain(),
update_radio_buttons.run_if(resource_changed::<AppStatus>),
)
.add_systems(
Update,
(handle_window_resize_events, regenerate_image_when_requested).chain(),
)
.add_systems(
Update,
handle_app_setting_change
.after(widgets::handle_ui_interactions::<AppSetting>)
.before(regenerate_image_when_requested),
);
handle_app_setting_change.before(regenerate_image_when_requested),
)
.add_observer(widgets::handle_ui_button_interaction_on_click::<AppSetting>);

// Because `MipGenerationJobs` is part of the render app, we need to add the
// associated systems to that app, not the main one.
Expand Down
12 changes: 5 additions & 7 deletions examples/3d/clustered_decal_maps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,12 @@ fn main() {
.add_systems(
Update,
(
widgets::handle_ui_interactions::<AppSetting>,
update_radio_buttons,
),
)
.add_systems(
Update,
handle_emission_type_change.after(widgets::handle_ui_interactions::<AppSetting>),
handle_emission_type_change,
update_radio_buttons.run_if(resource_changed::<AppStatus>),
)
.chain(),
)
.add_observer(widgets::handle_ui_button_interaction_on_click::<AppSetting>)
.insert_resource(SeededRng(ChaCha8Rng::seed_from_u64(19878367467712)))
.run();
}
Expand Down
18 changes: 12 additions & 6 deletions examples/3d/clustered_decals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use bevy::{
input::mouse::AccumulatedMouseMotion,
light::ClusteredDecal,
pbr::{decal, ExtendedMaterial, MaterialExtension},
picking::hover::Hovered,
prelude::*,
render::{
render_resource::AsBindGroup,
Expand Down Expand Up @@ -135,18 +136,21 @@ fn main() {
.add_systems(Startup, setup)
.add_systems(Update, draw_gizmos)
.add_systems(Update, rotate_cube)
.add_systems(Update, widgets::handle_ui_interactions::<Selection>)
.add_systems(
Update,
(handle_selection_change, update_radio_buttons)
.after(widgets::handle_ui_interactions::<Selection>),
(
handle_selection_change,
update_radio_buttons.run_if(resource_changed::<AppStatus>),
)
.chain(),
)
.add_systems(Update, process_move_input)
.add_systems(Update, process_scale_input)
.add_systems(Update, process_roll_input)
.add_systems(Update, switch_drag_mode)
.add_systems(Update, update_help_text)
.add_systems(Update, update_button_visibility)
.add_observer(widgets::handle_ui_button_interaction_on_click::<Selection>)
.run();
}

Expand Down Expand Up @@ -288,6 +292,8 @@ fn drag_button(label: &str) -> impl Bundle {
},
Button,
BackgroundColor(Color::BLACK),
// Detect the hover.
Hovered::default(),
BUTTON_BORDER_COLOR,
children![widgets::ui_text(label, Color::WHITE)],
)
Expand Down Expand Up @@ -490,7 +496,7 @@ fn create_help_string(app_status: &AppStatus) -> String {
/// mode back to its default value of [`DragMode::Move`].
fn switch_drag_mode(
mut commands: Commands,
mut interactions: Query<(&Interaction, &DragMode)>,
mut button_interactions: Query<(&Hovered, &DragMode), With<Button>>,
mut windows: Query<Entity, With<Window>>,
mouse_buttons: Res<ButtonInput<MouseButton>>,
mut app_status: ResMut<AppStatus>,
Expand All @@ -499,8 +505,8 @@ fn switch_drag_mode(
return;
}

for (interaction, drag_mode) in &mut interactions {
if *interaction != Interaction::Hovered {
for (hovered, drag_mode) in &mut button_interactions {
if !hovered.0 {
continue;
}

Expand Down
23 changes: 9 additions & 14 deletions examples/3d/color_grading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,9 @@ fn main() {
.add_systems(Startup, setup)
.add_systems(
Update,
(
handle_button_presses,
adjust_color_grading_option,
update_ui_state,
)
.chain(),
(adjust_color_grading_option, update_ui_state).chain(),
)
.add_observer(handle_button_presses)
.run();
}

Expand Down Expand Up @@ -508,16 +504,15 @@ impl SelectedColorGradingOption {

/// Handles mouse clicks on the buttons when the user clicks on a new one.
fn handle_button_presses(
mut interactions: Query<(&Interaction, &ColorGradingOptionWidget), Changed<Interaction>>,
press: On<Pointer<Click>>,
mut color_grading_option_widget_query: Query<&ColorGradingOptionWidget>,
mut currently_selected_option: ResMut<SelectedColorGradingOption>,
) {
for (interaction, widget) in interactions.iter_mut() {
if widget.widget_type == ColorGradingOptionWidgetType::Button
&& *interaction == Interaction::Pressed
{
*currently_selected_option = widget.option;
}
}
let Ok(widget) = color_grading_option_widget_query.get_mut(press.event_target()) else {
return;
};

*currently_selected_option = widget.option;
}

/// Updates the state of the UI based on the current state.
Expand Down
9 changes: 5 additions & 4 deletions examples/3d/contact_shadows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,12 @@ fn main() {
.add_systems(
Update,
(
widgets::handle_ui_interactions::<ExampleSetting>,
update_radio_buttons.after(widgets::handle_ui_interactions::<ExampleSetting>),
handle_setting_change.after(widgets::handle_ui_interactions::<ExampleSetting>),
),
handle_setting_change,
update_radio_buttons.run_if(resource_changed::<AppStatus>),
)
.chain(),
)
.add_observer(widgets::handle_ui_button_interaction_on_click::<ExampleSetting>)
.run();
}

Expand Down
29 changes: 6 additions & 23 deletions examples/3d/light_probe_blending.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,36 +166,19 @@ fn main() {
.add_systems(
Update,
(
widgets::handle_ui_interactions::<GizmosEnabled>,
handle_gizmos_enabled_change,
)
.chain(),
)
.add_systems(
Update,
(
widgets::handle_ui_interactions::<ObjectToShow>,
handle_object_to_show_change,
)
.chain(),
)
.add_systems(
Update,
(
widgets::handle_ui_interactions::<CameraMode>,
handle_camera_mode_change,
)
.chain()
.after(free_camera::run_freecamera_controller),
handle_camera_mode_change.after(free_camera::run_freecamera_controller),
),
)
.add_systems(
Update,
update_radio_buttons
.after(widgets::handle_ui_interactions::<GizmosEnabled>)
.after(widgets::handle_ui_interactions::<ObjectToShow>)
.after(widgets::handle_ui_interactions::<CameraMode>),
update_radio_buttons.run_if(resource_changed::<AppStatus>),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that some of these examples have these update_* systems to after the handle_* systems in a .chain() since the handle_ systems seem to be the ones that actually change AppStatus.

Should these update_* always be set up to run .after every handle* system in that case? It doesn’t seem to be applied uniformly across all the examples if it’s an intentional change. I would think they have to be so that update_radio_buttons runs only after AppStatus was potentially changed but I’m not an ECS scheduling expert

)
.add_systems(Update, draw_gizmos)
.add_observer(widgets::handle_ui_button_interaction_on_click::<GizmosEnabled>)
.add_observer(widgets::handle_ui_button_interaction_on_click::<ObjectToShow>)
.add_observer(widgets::handle_ui_button_interaction_on_click::<CameraMode>)
.run();
}

Expand Down
21 changes: 13 additions & 8 deletions examples/3d/light_textures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use bevy::{
input::mouse::AccumulatedMouseMotion,
light::{DirectionalLightTexture, NotShadowCaster, PointLightTexture, SpotLightTexture},
pbr::decal,
picking::hover::Hovered,
prelude::*,
render::renderer::{RenderAdapter, RenderDevice},
window::{CursorIcon, SystemCursorIcon},
Expand Down Expand Up @@ -120,13 +121,13 @@ fn main() {
.add_systems(Update, draw_gizmos)
.add_systems(Update, rotate_cube)
.add_systems(Update, hide_shadows)
.add_systems(Update, widgets::handle_ui_interactions::<Selection>)
.add_systems(Update, widgets::handle_ui_interactions::<Visibility>)
.add_systems(
Update,
(handle_selection_change, update_radio_buttons)
.after(widgets::handle_ui_interactions::<Selection>)
.after(widgets::handle_ui_interactions::<Visibility>),
(
handle_selection_change,
update_radio_buttons.run_if(resource_changed::<AppStatus>),
)
.chain(),
)
.add_systems(Update, toggle_visibility)
.add_systems(Update, update_directional_light)
Expand All @@ -136,6 +137,8 @@ fn main() {
.add_systems(Update, switch_drag_mode)
.add_systems(Update, update_help_text)
.add_systems(Update, update_button_visibility)
.add_observer(widgets::handle_ui_button_interaction_on_click::<Selection>)
.add_observer(widgets::handle_ui_button_interaction_on_click::<Visibility>)
.run();
}

Expand Down Expand Up @@ -334,6 +337,8 @@ fn drag_button(label: &str) -> impl Bundle {
},
Button,
BackgroundColor(Color::BLACK),
// Detect the hover.
Hovered::default(),
BUTTON_BORDER_COLOR,
children![widgets::ui_text(label, Color::WHITE),],
)
Expand Down Expand Up @@ -583,7 +588,7 @@ fn create_help_string(app_status: &AppStatus) -> String {
/// mode back to its default value of [`DragMode::Move`].
fn switch_drag_mode(
mut commands: Commands,
mut interactions: Query<(&Interaction, &DragMode)>,
mut button_interactions: Query<(&Hovered, &DragMode), With<Button>>,
mut windows: Query<Entity, With<Window>>,
mouse_buttons: Res<ButtonInput<MouseButton>>,
mut app_status: ResMut<AppStatus>,
Expand All @@ -592,8 +597,8 @@ fn switch_drag_mode(
return;
}

for (interaction, drag_mode) in &mut interactions {
if *interaction != Interaction::Hovered {
for (hovered, drag_mode) in &mut button_interactions {
if !hovered.0 {
continue;
}

Expand Down
Loading
Loading