diff --git a/crates/bevy_feathers/src/controls/button.rs b/crates/bevy_feathers/src/controls/button.rs index 1067792097d5c..38695f679f373 100644 --- a/crates/bevy_feathers/src/controls/button.rs +++ b/crates/bevy_feathers/src/controls/button.rs @@ -9,13 +9,13 @@ use bevy_ecs::{ reflect::ReflectComponent, schedule::IntoScheduleConfigs, spawn::{SpawnRelated, SpawnableList}, - system::{Commands, In, Query}, + system::{Commands, Query}, }; use bevy_input_focus::tab_navigation::TabIndex; use bevy_picking::{hover::Hovered, PickingSystems}; use bevy_reflect::{prelude::ReflectDefault, Reflect}; use bevy_ui::{AlignItems, InteractionDisabled, JustifyContent, Node, Pressed, UiRect, Val}; -use bevy_ui_widgets::{Activate, Button, Callback}; +use bevy_ui_widgets::Button; use crate::{ constants::{fonts, size}, @@ -47,8 +47,6 @@ pub struct ButtonProps { pub variant: ButtonVariant, /// Rounded corners options pub corners: RoundedCorners, - /// Click handler - pub on_click: Callback>, } /// Template function to spawn a button. @@ -71,9 +69,7 @@ pub fn button + Send + Sync + 'static, B: Bundle>( flex_grow: 1.0, ..Default::default() }, - Button { - on_activate: props.on_click, - }, + Button, props.variant, Hovered::default(), EntityCursor::System(bevy_window::SystemCursorIcon::Pointer), diff --git a/crates/bevy_feathers/src/controls/checkbox.rs b/crates/bevy_feathers/src/controls/checkbox.rs index ebeff7fe3b171..01dec1edd645e 100644 --- a/crates/bevy_feathers/src/controls/checkbox.rs +++ b/crates/bevy_feathers/src/controls/checkbox.rs @@ -11,7 +11,7 @@ use bevy_ecs::{ reflect::ReflectComponent, schedule::IntoScheduleConfigs, spawn::{Spawn, SpawnRelated, SpawnableList}, - system::{Commands, In, Query}, + system::{Commands, Query}, }; use bevy_input_focus::tab_navigation::TabIndex; use bevy_math::Rot2; @@ -21,7 +21,7 @@ use bevy_ui::{ AlignItems, BorderRadius, Checked, Display, FlexDirection, InteractionDisabled, JustifyContent, Node, PositionType, UiRect, UiTransform, Val, }; -use bevy_ui_widgets::{Callback, Checkbox, ValueChange}; +use bevy_ui_widgets::Checkbox; use crate::{ constants::{fonts, size}, @@ -32,13 +32,6 @@ use crate::{ tokens, }; -/// Parameters for the checkbox template, passed to [`checkbox`] function. -#[derive(Default)] -pub struct CheckboxProps { - /// Change handler - pub on_change: Callback>>, -} - /// Marker for the checkbox frame (contains both checkbox and label) #[derive(Component, Default, Clone, Reflect)] #[reflect(Component, Clone, Default)] @@ -61,7 +54,6 @@ struct CheckboxMark; /// * `overrides` - a bundle of components that are merged in with the normal checkbox components. /// * `label` - the label of the checkbox. pub fn checkbox + Send + Sync + 'static, B: Bundle>( - props: CheckboxProps, overrides: B, label: C, ) -> impl Bundle { @@ -74,9 +66,7 @@ pub fn checkbox + Send + Sync + 'static, B: Bundle>( column_gap: Val::Px(4.0), ..Default::default() }, - Checkbox { - on_change: props.on_change, - }, + Checkbox, CheckboxFrame, Hovered::default(), EntityCursor::System(bevy_window::SystemCursorIcon::Pointer), diff --git a/crates/bevy_feathers/src/controls/color_slider.rs b/crates/bevy_feathers/src/controls/color_slider.rs index 0ef776e3b7808..b4dcdcbc7e02a 100644 --- a/crates/bevy_feathers/src/controls/color_slider.rs +++ b/crates/bevy_feathers/src/controls/color_slider.rs @@ -12,7 +12,7 @@ use bevy_ecs::{ query::{Changed, Or, With}, schedule::IntoScheduleConfigs, spawn::SpawnRelated, - system::{In, Query}, + system::Query, }; use bevy_input_focus::tab_navigation::TabIndex; use bevy_log::warn_once; @@ -23,9 +23,7 @@ use bevy_ui::{ UiRect, UiTransform, Val, Val2, ZIndex, }; use bevy_ui_render::ui_material::MaterialNode; -use bevy_ui_widgets::{ - Callback, Slider, SliderRange, SliderThumb, SliderValue, TrackClick, ValueChange, -}; +use bevy_ui_widgets::{Slider, SliderRange, SliderThumb, SliderValue, TrackClick}; use crate::{ alpha_pattern::{AlphaPattern, AlphaPatternMaterial}, @@ -146,8 +144,6 @@ pub struct SliderBaseColor(pub Color); pub struct ColorSliderProps { /// Slider current value pub value: f32, - /// On-change handler - pub on_change: Callback>>, /// Which color component we're editing pub channel: ColorChannel, } @@ -156,7 +152,6 @@ impl Default for ColorSliderProps { fn default() -> Self { Self { value: 0.0, - on_change: Callback::Ignore, channel: ColorChannel::Alpha, } } @@ -195,7 +190,6 @@ pub fn color_slider(props: ColorSliderProps, overrides: B) -> impl Bu ..Default::default() }, Slider { - on_change: props.on_change, track_click: TrackClick::Snap, }, ColorSlider { diff --git a/crates/bevy_feathers/src/controls/mod.rs b/crates/bevy_feathers/src/controls/mod.rs index f5b9ef4c43dd5..8adf2b5911659 100644 --- a/crates/bevy_feathers/src/controls/mod.rs +++ b/crates/bevy_feathers/src/controls/mod.rs @@ -11,15 +11,15 @@ mod toggle_switch; mod virtual_keyboard; pub use button::{button, ButtonPlugin, ButtonProps, ButtonVariant}; -pub use checkbox::{checkbox, CheckboxPlugin, CheckboxProps}; +pub use checkbox::{checkbox, CheckboxPlugin}; pub use color_slider::{ color_slider, ColorChannel, ColorSlider, ColorSliderPlugin, ColorSliderProps, SliderBaseColor, }; pub use color_swatch::{color_swatch, ColorSwatch, ColorSwatchFg}; pub use radio::{radio, RadioPlugin}; pub use slider::{slider, SliderPlugin, SliderProps}; -pub use toggle_switch::{toggle_switch, ToggleSwitchPlugin, ToggleSwitchProps}; -pub use virtual_keyboard::virtual_keyboard; +pub use toggle_switch::{toggle_switch, ToggleSwitchPlugin}; +pub use virtual_keyboard::{virtual_keyboard, VirtualKeyPressed}; use crate::alpha_pattern::AlphaPatternPlugin; diff --git a/crates/bevy_feathers/src/controls/slider.rs b/crates/bevy_feathers/src/controls/slider.rs index fbad8c7a362b5..1bcb2449f9370 100644 --- a/crates/bevy_feathers/src/controls/slider.rs +++ b/crates/bevy_feathers/src/controls/slider.rs @@ -13,7 +13,7 @@ use bevy_ecs::{ reflect::ReflectComponent, schedule::IntoScheduleConfigs, spawn::SpawnRelated, - system::{Commands, In, Query, Res}, + system::{Commands, Query, Res}, }; use bevy_input_focus::tab_navigation::TabIndex; use bevy_picking::PickingSystems; @@ -23,7 +23,7 @@ use bevy_ui::{ InteractionDisabled, InterpolationColorSpace, JustifyContent, LinearGradient, Node, PositionType, UiRect, Val, }; -use bevy_ui_widgets::{Callback, Slider, SliderRange, SliderValue, TrackClick, ValueChange}; +use bevy_ui_widgets::{Slider, SliderRange, SliderValue, TrackClick}; use crate::{ constants::{fonts, size}, @@ -43,8 +43,6 @@ pub struct SliderProps { pub min: f32, /// Slider maximum value pub max: f32, - /// On-change handler - pub on_change: Callback>>, } impl Default for SliderProps { @@ -53,7 +51,6 @@ impl Default for SliderProps { value: 0.0, min: 0.0, max: 1.0, - on_change: Callback::Ignore, } } } @@ -86,7 +83,6 @@ pub fn slider(props: SliderProps, overrides: B) -> impl Bundle { ..Default::default() }, Slider { - on_change: props.on_change, track_click: TrackClick::Drag, }, SliderStyle, diff --git a/crates/bevy_feathers/src/controls/toggle_switch.rs b/crates/bevy_feathers/src/controls/toggle_switch.rs index 94a49ca1972b5..dea53f169f0f8 100644 --- a/crates/bevy_feathers/src/controls/toggle_switch.rs +++ b/crates/bevy_feathers/src/controls/toggle_switch.rs @@ -12,14 +12,14 @@ use bevy_ecs::{ reflect::ReflectComponent, schedule::IntoScheduleConfigs, spawn::SpawnRelated, - system::{Commands, In, Query}, + system::{Commands, Query}, world::Mut, }; use bevy_input_focus::tab_navigation::TabIndex; use bevy_picking::{hover::Hovered, PickingSystems}; use bevy_reflect::{prelude::ReflectDefault, Reflect}; use bevy_ui::{BorderRadius, Checked, InteractionDisabled, Node, PositionType, UiRect, Val}; -use bevy_ui_widgets::{Callback, Checkbox, ValueChange}; +use bevy_ui_widgets::Checkbox; use crate::{ constants::size, @@ -28,13 +28,6 @@ use crate::{ tokens, }; -/// Parameters for the toggle switch template, passed to [`toggle_switch`] function. -#[derive(Default)] -pub struct ToggleSwitchProps { - /// Change handler - pub on_change: Callback>>, -} - /// Marker for the toggle switch outline #[derive(Component, Default, Clone, Reflect)] #[reflect(Component, Clone, Default)] @@ -50,7 +43,7 @@ struct ToggleSwitchSlide; /// # Arguments /// * `props` - construction properties for the toggle switch. /// * `overrides` - a bundle of components that are merged in with the normal toggle switch components. -pub fn toggle_switch(props: ToggleSwitchProps, overrides: B) -> impl Bundle { +pub fn toggle_switch(overrides: B) -> impl Bundle { ( Node { width: size::TOGGLE_WIDTH, @@ -58,9 +51,7 @@ pub fn toggle_switch(props: ToggleSwitchProps, overrides: B) -> impl border: UiRect::all(Val::Px(2.0)), ..Default::default() }, - Checkbox { - on_change: props.on_change, - }, + Checkbox, ToggleSwitchOutline, BorderRadius::all(Val::Px(5.0)), ThemeBackgroundColor(tokens::SWITCH_BG), diff --git a/crates/bevy_feathers/src/controls/virtual_keyboard.rs b/crates/bevy_feathers/src/controls/virtual_keyboard.rs index acc62afc82478..0e95a41956137 100644 --- a/crates/bevy_feathers/src/controls/virtual_keyboard.rs +++ b/crates/bevy_feathers/src/controls/virtual_keyboard.rs @@ -1,26 +1,27 @@ -use bevy_ecs::{ - bundle::Bundle, - component::Component, - hierarchy::{ChildOf, Children}, - relationship::RelatedSpawner, - spawn::{Spawn, SpawnRelated, SpawnWith}, - system::{In, SystemId}, -}; +use bevy_ecs::prelude::*; use bevy_input_focus::tab_navigation::TabGroup; use bevy_ui::Node; use bevy_ui::Val; use bevy_ui::{widget::Text, FlexDirection}; -use bevy_ui_widgets::{Activate, Callback}; +use bevy_ui_widgets::{observe, Activate}; use crate::controls::{button, ButtonProps}; +/// Fired whenever a virtual key is pressed. +#[derive(EntityEvent)] +pub struct VirtualKeyPressed { + /// The virtual keyboard entity + pub entity: Entity, + /// The pressed virtual key + pub key: T, +} + /// Function to spawn a virtual keyboard pub fn virtual_keyboard( - keys: impl Iterator> + Send + Sync + 'static, - on_key_press: SystemId>, + keys: impl Iterator> + Send + Sync + 'static, ) -> impl Bundle where - T: Component, + T: AsRef + Clone + Send + Sync + 'static, { ( Node { @@ -29,28 +30,33 @@ where ..Default::default() }, TabGroup::new(0), - Children::spawn((SpawnWith(move |parent: &mut RelatedSpawner| { - for row in keys { - parent.spawn(( - Node { - flex_direction: FlexDirection::Row, - column_gap: Val::Px(4.), - ..Default::default() - }, - Children::spawn(SpawnWith(move |parent: &mut RelatedSpawner| { - for (label, key_id) in row.into_iter() { - parent.spawn(button( - ButtonProps { - on_click: Callback::System(on_key_press), - ..Default::default() - }, - (key_id,), - Spawn(Text::new(label)), - )); - } - })), - )); - } - }),)), + Children::spawn(SpawnIter(keys.map(move |row| { + ( + Node { + flex_direction: FlexDirection::Row, + column_gap: Val::Px(4.), + ..Default::default() + }, + Children::spawn(SpawnIter(row.into_iter().map(move |key| { + ( + button(ButtonProps::default(), (), Spawn(Text::new(key.as_ref()))), + observe( + move |activate: On, + mut commands: Commands, + query: Query<&ChildOf>| + -> Result { + let virtual_keyboard = + query.get(query.get(activate.entity)?.parent())?.parent(); + commands.trigger(VirtualKeyPressed { + entity: virtual_keyboard, + key: key.clone(), + }); + Ok(()) + }, + ), + ) + }))), + ) + }))), ) } diff --git a/crates/bevy_ui_widgets/src/button.rs b/crates/bevy_ui_widgets/src/button.rs index 46fea109ac62d..4c98f6063d8d6 100644 --- a/crates/bevy_ui_widgets/src/button.rs +++ b/crates/bevy_ui_widgets/src/button.rs @@ -2,7 +2,6 @@ use accesskit::Role; use bevy_a11y::AccessibilityNode; use bevy_app::{App, Plugin}; use bevy_ecs::query::Has; -use bevy_ecs::system::In; use bevy_ecs::{ component::Component, entity::Entity, @@ -16,25 +15,21 @@ use bevy_input_focus::FocusedInput; use bevy_picking::events::{Cancel, Click, DragEnd, Pointer, Press, Release}; use bevy_ui::{InteractionDisabled, Pressed}; -use crate::{Activate, Callback, Notify}; +use crate::Activate; /// Headless button widget. This widget maintains a "pressed" state, which is used to -/// indicate whether the button is currently being pressed by the user. It emits a `ButtonClicked` +/// indicate whether the button is currently being pressed by the user. It emits an [`Activate`] /// event when the button is un-pressed. #[derive(Component, Default, Debug)] #[require(AccessibilityNode(accesskit::Node::new(Role::Button)))] -pub struct Button { - /// Callback to invoke when the button is clicked, or when the `Enter` or `Space` key - /// is pressed while the button is focused. - pub on_activate: Callback>, -} +pub struct Button; fn button_on_key_event( mut event: On>, - q_state: Query<(&Button, Has)>, + q_state: Query, With