Merge 893ad207af into e5aa94132c
This commit is contained in:
commit
a539f97252
@ -2,18 +2,21 @@ use bevy_app::{Plugin, PreUpdate};
|
||||
use bevy_core_widgets::{Callback, CoreButton};
|
||||
use bevy_ecs::{
|
||||
bundle::Bundle,
|
||||
change_detection::DetectChanges,
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
hierarchy::{ChildOf, Children},
|
||||
lifecycle::RemovedComponents,
|
||||
query::{Added, Changed, Has, Or},
|
||||
query::{Added, Changed, Has, Or, With},
|
||||
schedule::IntoScheduleConfigs,
|
||||
spawn::{SpawnRelated, SpawnableList},
|
||||
system::{Commands, Query},
|
||||
system::{Commands, Query, Res},
|
||||
};
|
||||
use bevy_input_focus::tab_navigation::TabIndex;
|
||||
use bevy_input_focus::{tab_navigation::TabIndex, InputFocus};
|
||||
use bevy_picking::{hover::Hovered, PickingSystems};
|
||||
use bevy_ui::{AlignItems, InteractionDisabled, JustifyContent, Node, Pressed, UiRect, Val};
|
||||
use bevy_ui::{
|
||||
AlignItems, InteractionDisabled, JustifyContent, Node, Outline, Pressed, UiRect, Val,
|
||||
};
|
||||
use bevy_winit::cursor::CursorIcon;
|
||||
|
||||
use crate::{
|
||||
@ -21,7 +24,7 @@ use crate::{
|
||||
font_styles::InheritableFont,
|
||||
handle_or_path::HandleOrPath,
|
||||
rounded_corners::RoundedCorners,
|
||||
theme::{ThemeBackgroundColor, ThemeFontColor},
|
||||
theme::{ThemeBackgroundColor, ThemeFontColor, UiTheme},
|
||||
tokens,
|
||||
};
|
||||
|
||||
@ -195,6 +198,27 @@ fn set_button_colors(
|
||||
}
|
||||
}
|
||||
|
||||
fn update_button_focus(
|
||||
mut commands: Commands,
|
||||
focus: Res<InputFocus>,
|
||||
theme: Res<UiTheme>,
|
||||
query: Query<Entity, With<ButtonVariant>>,
|
||||
) {
|
||||
if focus.is_changed() {
|
||||
for button in query.iter() {
|
||||
if focus.0 == Some(button) {
|
||||
commands.entity(button).insert(Outline {
|
||||
color: theme.color(tokens::FOCUS_RING),
|
||||
width: Val::Px(2.0),
|
||||
offset: Val::Px(2.0),
|
||||
});
|
||||
} else {
|
||||
commands.entity(button).remove::<Outline>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Plugin which registers the systems for updating the button styles.
|
||||
pub struct ButtonPlugin;
|
||||
|
||||
@ -202,7 +226,12 @@ impl Plugin for ButtonPlugin {
|
||||
fn build(&self, app: &mut bevy_app::App) {
|
||||
app.add_systems(
|
||||
PreUpdate,
|
||||
(update_button_styles, update_button_styles_remove).in_set(PickingSystems::Last),
|
||||
(
|
||||
update_button_styles,
|
||||
update_button_styles_remove,
|
||||
update_button_focus,
|
||||
)
|
||||
.in_set(PickingSystems::Last),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ use bevy_app::{Plugin, PreUpdate};
|
||||
use bevy_core_widgets::{Callback, CoreCheckbox};
|
||||
use bevy_ecs::{
|
||||
bundle::Bundle,
|
||||
change_detection::DetectChanges,
|
||||
children,
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
@ -10,15 +11,15 @@ use bevy_ecs::{
|
||||
query::{Added, Changed, Has, Or, With},
|
||||
schedule::IntoScheduleConfigs,
|
||||
spawn::{Spawn, SpawnRelated, SpawnableList},
|
||||
system::{Commands, In, Query},
|
||||
system::{Commands, In, Query, Res},
|
||||
};
|
||||
use bevy_input_focus::tab_navigation::TabIndex;
|
||||
use bevy_input_focus::{tab_navigation::TabIndex, InputFocus};
|
||||
use bevy_math::Rot2;
|
||||
use bevy_picking::{hover::Hovered, PickingSystems};
|
||||
use bevy_render::view::Visibility;
|
||||
use bevy_ui::{
|
||||
AlignItems, BorderRadius, Checked, Display, FlexDirection, InteractionDisabled, JustifyContent,
|
||||
Node, PositionType, UiRect, UiTransform, Val,
|
||||
Node, Outline, PositionType, UiRect, UiTransform, Val,
|
||||
};
|
||||
use bevy_winit::cursor::CursorIcon;
|
||||
|
||||
@ -26,7 +27,7 @@ use crate::{
|
||||
constants::{fonts, size},
|
||||
font_styles::InheritableFont,
|
||||
handle_or_path::HandleOrPath,
|
||||
theme::{ThemeBackgroundColor, ThemeBorderColor, ThemeFontColor},
|
||||
theme::{ThemeBackgroundColor, ThemeBorderColor, ThemeFontColor, UiTheme},
|
||||
tokens,
|
||||
};
|
||||
|
||||
@ -296,6 +297,37 @@ fn set_checkbox_colors(
|
||||
}
|
||||
}
|
||||
|
||||
fn update_checkbox_focus(
|
||||
mut commands: Commands,
|
||||
focus: Res<InputFocus>,
|
||||
theme: Res<UiTheme>,
|
||||
q_checkbox: Query<Entity, With<CheckboxFrame>>,
|
||||
q_children: Query<&Children>,
|
||||
q_outline: Query<(), With<CheckboxOutline>>,
|
||||
) {
|
||||
if focus.is_changed() {
|
||||
for checkbox_ent in q_checkbox.iter() {
|
||||
// For a checkbox, we want to outline just the box, not the entire wiget with the label.
|
||||
let Some(outline_ent) = q_children
|
||||
.iter_descendants(checkbox_ent)
|
||||
.find(|en| q_outline.contains(*en))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
if focus.0 == Some(checkbox_ent) {
|
||||
commands.entity(outline_ent).insert(Outline {
|
||||
color: theme.color(tokens::FOCUS_RING),
|
||||
width: Val::Px(2.0),
|
||||
offset: Val::Px(2.0),
|
||||
});
|
||||
} else {
|
||||
commands.entity(outline_ent).remove::<Outline>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Plugin which registers the systems for updating the checkbox styles.
|
||||
pub struct CheckboxPlugin;
|
||||
|
||||
@ -303,7 +335,12 @@ impl Plugin for CheckboxPlugin {
|
||||
fn build(&self, app: &mut bevy_app::App) {
|
||||
app.add_systems(
|
||||
PreUpdate,
|
||||
(update_checkbox_styles, update_checkbox_styles_remove).in_set(PickingSystems::Last),
|
||||
(
|
||||
update_checkbox_styles,
|
||||
update_checkbox_styles_remove,
|
||||
update_checkbox_focus,
|
||||
)
|
||||
.in_set(PickingSystems::Last),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use bevy_app::{Plugin, PreUpdate};
|
||||
use bevy_core_widgets::CoreRadio;
|
||||
use bevy_core_widgets::{CoreRadio, CoreRadioGroup};
|
||||
use bevy_ecs::{
|
||||
bundle::Bundle,
|
||||
change_detection::DetectChanges,
|
||||
children,
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
@ -10,14 +11,14 @@ use bevy_ecs::{
|
||||
query::{Added, Changed, Has, Or, With},
|
||||
schedule::IntoScheduleConfigs,
|
||||
spawn::{Spawn, SpawnRelated, SpawnableList},
|
||||
system::{Commands, Query},
|
||||
system::{Commands, Query, Res},
|
||||
};
|
||||
use bevy_input_focus::tab_navigation::TabIndex;
|
||||
use bevy_input_focus::InputFocus;
|
||||
use bevy_picking::{hover::Hovered, PickingSystems};
|
||||
use bevy_render::view::Visibility;
|
||||
use bevy_ui::{
|
||||
AlignItems, BorderRadius, Checked, Display, FlexDirection, InteractionDisabled, JustifyContent,
|
||||
Node, UiRect, Val,
|
||||
Node, Outline, UiRect, Val,
|
||||
};
|
||||
use bevy_winit::cursor::CursorIcon;
|
||||
|
||||
@ -25,7 +26,7 @@ use crate::{
|
||||
constants::{fonts, size},
|
||||
font_styles::InheritableFont,
|
||||
handle_or_path::HandleOrPath,
|
||||
theme::{ThemeBackgroundColor, ThemeBorderColor, ThemeFontColor},
|
||||
theme::{ThemeBackgroundColor, ThemeBorderColor, ThemeFontColor, UiTheme},
|
||||
tokens,
|
||||
};
|
||||
|
||||
@ -59,7 +60,6 @@ pub fn radio<C: SpawnableList<ChildOf> + Send + Sync + 'static, B: Bundle>(
|
||||
CoreRadio,
|
||||
Hovered::default(),
|
||||
CursorIcon::System(bevy_window::SystemCursorIcon::Pointer),
|
||||
TabIndex(0),
|
||||
ThemeFontColor(tokens::RADIO_TEXT),
|
||||
InheritableFont {
|
||||
font: HandleOrPath::Path(fonts::REGULAR.to_owned()),
|
||||
@ -255,6 +255,27 @@ fn set_radio_colors(
|
||||
}
|
||||
}
|
||||
|
||||
fn update_radio_group_focus(
|
||||
mut commands: Commands,
|
||||
focus: Res<InputFocus>,
|
||||
theme: Res<UiTheme>,
|
||||
q_groups: Query<Entity, With<CoreRadioGroup>>,
|
||||
) {
|
||||
if focus.is_changed() {
|
||||
for group in q_groups.iter() {
|
||||
if focus.0 == Some(group) {
|
||||
commands.entity(group).insert(Outline {
|
||||
color: theme.color(tokens::FOCUS_RING),
|
||||
width: Val::Px(2.0),
|
||||
offset: Val::Px(2.0),
|
||||
});
|
||||
} else {
|
||||
commands.entity(group).remove::<Outline>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Plugin which registers the systems for updating the radio styles.
|
||||
pub struct RadioPlugin;
|
||||
|
||||
@ -262,7 +283,12 @@ impl Plugin for RadioPlugin {
|
||||
fn build(&self, app: &mut bevy_app::App) {
|
||||
app.add_systems(
|
||||
PreUpdate,
|
||||
(update_radio_styles, update_radio_styles_remove).in_set(PickingSystems::Last),
|
||||
(
|
||||
update_radio_styles,
|
||||
update_radio_styles_remove,
|
||||
update_radio_group_focus,
|
||||
)
|
||||
.in_set(PickingSystems::Last),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ use bevy_color::Color;
|
||||
use bevy_core_widgets::{Callback, CoreSlider, SliderRange, SliderValue, TrackClick};
|
||||
use bevy_ecs::{
|
||||
bundle::Bundle,
|
||||
change_detection::DetectChanges,
|
||||
children,
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
@ -13,14 +14,14 @@ use bevy_ecs::{
|
||||
query::{Added, Changed, Has, Or, Spawned, With},
|
||||
schedule::IntoScheduleConfigs,
|
||||
spawn::SpawnRelated,
|
||||
system::{In, Query, Res},
|
||||
system::{Commands, In, Query, Res},
|
||||
};
|
||||
use bevy_input_focus::tab_navigation::TabIndex;
|
||||
use bevy_input_focus::{tab_navigation::TabIndex, InputFocus};
|
||||
use bevy_picking::PickingSystems;
|
||||
use bevy_ui::{
|
||||
widget::Text, AlignItems, BackgroundGradient, ColorStop, Display, FlexDirection, Gradient,
|
||||
InteractionDisabled, InterpolationColorSpace, JustifyContent, LinearGradient, Node, UiRect,
|
||||
Val,
|
||||
InteractionDisabled, InterpolationColorSpace, JustifyContent, LinearGradient, Node, Outline,
|
||||
UiRect, Val,
|
||||
};
|
||||
use bevy_winit::cursor::CursorIcon;
|
||||
|
||||
@ -190,6 +191,27 @@ fn update_slider_pos(
|
||||
}
|
||||
}
|
||||
|
||||
fn update_slider_focus(
|
||||
mut commands: Commands,
|
||||
focus: Res<InputFocus>,
|
||||
theme: Res<UiTheme>,
|
||||
q_sliders: Query<Entity, With<SliderStyle>>,
|
||||
) {
|
||||
if focus.is_changed() {
|
||||
for slider in q_sliders.iter() {
|
||||
if focus.0 == Some(slider) {
|
||||
commands.entity(slider).insert(Outline {
|
||||
color: theme.color(tokens::FOCUS_RING),
|
||||
width: Val::Px(2.0),
|
||||
offset: Val::Px(2.0),
|
||||
});
|
||||
} else {
|
||||
commands.entity(slider).remove::<Outline>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Plugin which registers the systems for updating the slider styles.
|
||||
pub struct SliderPlugin;
|
||||
|
||||
@ -201,6 +223,7 @@ impl Plugin for SliderPlugin {
|
||||
update_slider_colors,
|
||||
update_slider_colors_remove,
|
||||
update_slider_pos,
|
||||
update_slider_focus,
|
||||
)
|
||||
.in_set(PickingSystems::Last),
|
||||
);
|
||||
|
||||
@ -4,6 +4,7 @@ use bevy_app::{Plugin, PreUpdate};
|
||||
use bevy_core_widgets::{Callback, CoreCheckbox};
|
||||
use bevy_ecs::{
|
||||
bundle::Bundle,
|
||||
change_detection::DetectChanges,
|
||||
children,
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
@ -12,17 +13,19 @@ use bevy_ecs::{
|
||||
query::{Added, Changed, Has, Or, With},
|
||||
schedule::IntoScheduleConfigs,
|
||||
spawn::SpawnRelated,
|
||||
system::{Commands, In, Query},
|
||||
system::{Commands, In, Query, Res},
|
||||
world::Mut,
|
||||
};
|
||||
use bevy_input_focus::tab_navigation::TabIndex;
|
||||
use bevy_input_focus::{tab_navigation::TabIndex, InputFocus};
|
||||
use bevy_picking::{hover::Hovered, PickingSystems};
|
||||
use bevy_ui::{BorderRadius, Checked, InteractionDisabled, Node, PositionType, UiRect, Val};
|
||||
use bevy_ui::{
|
||||
BorderRadius, Checked, InteractionDisabled, Node, Outline, PositionType, UiRect, Val,
|
||||
};
|
||||
use bevy_winit::cursor::CursorIcon;
|
||||
|
||||
use crate::{
|
||||
constants::size,
|
||||
theme::{ThemeBackgroundColor, ThemeBorderColor},
|
||||
theme::{ThemeBackgroundColor, ThemeBorderColor, UiTheme},
|
||||
tokens,
|
||||
};
|
||||
|
||||
@ -236,6 +239,27 @@ fn set_switch_colors(
|
||||
}
|
||||
}
|
||||
|
||||
fn update_switch_focus(
|
||||
mut commands: Commands,
|
||||
focus: Res<InputFocus>,
|
||||
theme: Res<UiTheme>,
|
||||
q_switches: Query<Entity, With<ToggleSwitchOutline>>,
|
||||
) {
|
||||
if focus.is_changed() {
|
||||
for switch in q_switches.iter() {
|
||||
if focus.0 == Some(switch) {
|
||||
commands.entity(switch).insert(Outline {
|
||||
color: theme.color(tokens::FOCUS_RING),
|
||||
width: Val::Px(2.0),
|
||||
offset: Val::Px(2.0),
|
||||
});
|
||||
} else {
|
||||
commands.entity(switch).remove::<Outline>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Plugin which registers the systems for updating the toggle switch styles.
|
||||
pub struct ToggleSwitchPlugin;
|
||||
|
||||
@ -243,7 +267,12 @@ impl Plugin for ToggleSwitchPlugin {
|
||||
fn build(&self, app: &mut bevy_app::App) {
|
||||
app.add_systems(
|
||||
PreUpdate,
|
||||
(update_switch_styles, update_switch_styles_remove).in_set(PickingSystems::Last),
|
||||
(
|
||||
update_switch_styles,
|
||||
update_switch_styles_remove,
|
||||
update_switch_focus,
|
||||
)
|
||||
.in_set(PickingSystems::Last),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ pub fn create_dark_theme() -> ThemeProps {
|
||||
ThemeProps {
|
||||
color: HashMap::from([
|
||||
(tokens::WINDOW_BG.into(), palette::GRAY_0),
|
||||
(tokens::FOCUS_RING.into(), palette::ACCENT.with_alpha(0.5)),
|
||||
// Button
|
||||
(tokens::BUTTON_BG.into(), palette::GRAY_3),
|
||||
(
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
//! This example illustrates how to create widgets using the `bevy_core_widgets` widget set.
|
||||
|
||||
use bevy::{
|
||||
color::palettes::basic::*,
|
||||
color::palettes::{self, basic::*},
|
||||
core_widgets::{
|
||||
Callback, CoreButton, CoreCheckbox, CoreRadio, CoreRadioGroup, CoreSlider,
|
||||
CoreSliderDragState, CoreSliderThumb, CoreWidgetsPlugins, SliderRange, SliderValue,
|
||||
@ -9,7 +9,7 @@ use bevy::{
|
||||
},
|
||||
input_focus::{
|
||||
tab_navigation::{TabGroup, TabIndex, TabNavigationPlugin},
|
||||
InputDispatchPlugin,
|
||||
InputDispatchPlugin, InputFocus,
|
||||
},
|
||||
picking::hover::Hovered,
|
||||
prelude::*,
|
||||
@ -43,6 +43,7 @@ fn main() {
|
||||
update_checkbox_or_radio_style.after(update_widget_values),
|
||||
update_checkbox_or_radio_style2.after(update_widget_values),
|
||||
toggle_disabled,
|
||||
focus_system,
|
||||
),
|
||||
)
|
||||
.run();
|
||||
@ -739,6 +740,26 @@ fn radio(asset_server: &AssetServer, value: TrackClick, caption: &str) -> impl B
|
||||
)
|
||||
}
|
||||
|
||||
fn focus_system(
|
||||
mut commands: Commands,
|
||||
focus: Res<InputFocus>,
|
||||
mut query: Query<Entity, With<TabIndex>>,
|
||||
) {
|
||||
if focus.is_changed() {
|
||||
for button in query.iter_mut() {
|
||||
if focus.0 == Some(button) {
|
||||
commands.entity(button).insert(Outline {
|
||||
color: palettes::tailwind::BLUE_700.into(),
|
||||
width: Val::Px(2.0),
|
||||
offset: Val::Px(2.0),
|
||||
});
|
||||
} else {
|
||||
commands.entity(button).remove::<Outline>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn toggle_disabled(
|
||||
input: Res<ButtonInput<KeyCode>>,
|
||||
mut interaction_query: Query<
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
//! This example illustrates how to create widgets using the `bevy_core_widgets` widget set.
|
||||
|
||||
use bevy::{
|
||||
color::palettes::basic::*,
|
||||
color::palettes::{self, basic::*},
|
||||
core_widgets::{
|
||||
Callback, CoreButton, CoreCheckbox, CoreSlider, CoreSliderThumb, CoreWidgetsPlugins,
|
||||
SliderRange, SliderValue,
|
||||
@ -9,7 +9,7 @@ use bevy::{
|
||||
ecs::system::SystemId,
|
||||
input_focus::{
|
||||
tab_navigation::{TabGroup, TabIndex, TabNavigationPlugin},
|
||||
InputDispatchPlugin,
|
||||
InputDispatchPlugin, InputFocus,
|
||||
},
|
||||
picking::hover::Hovered,
|
||||
prelude::*,
|
||||
@ -44,7 +44,10 @@ fn main() {
|
||||
.add_observer(checkbox_on_change_hover)
|
||||
.add_observer(checkbox_on_add_checked)
|
||||
.add_observer(checkbox_on_remove_checked)
|
||||
.add_systems(Update, (update_widget_values, toggle_disabled))
|
||||
.add_systems(
|
||||
Update,
|
||||
(update_widget_values, toggle_disabled, focus_system),
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
@ -730,6 +733,26 @@ fn update_widget_values(
|
||||
}
|
||||
}
|
||||
|
||||
fn focus_system(
|
||||
mut commands: Commands,
|
||||
focus: Res<InputFocus>,
|
||||
mut query: Query<Entity, With<TabIndex>>,
|
||||
) {
|
||||
if focus.is_changed() {
|
||||
for button in query.iter_mut() {
|
||||
if focus.0 == Some(button) {
|
||||
commands.entity(button).insert(Outline {
|
||||
color: palettes::tailwind::BLUE_700.into(),
|
||||
width: Val::Px(2.0),
|
||||
offset: Val::Px(2.0),
|
||||
});
|
||||
} else {
|
||||
commands.entity(button).remove::<Outline>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn toggle_disabled(
|
||||
input: Res<ButtonInput<KeyCode>>,
|
||||
mut interaction_query: Query<
|
||||
|
||||
@ -15,7 +15,7 @@ use bevy::{
|
||||
tokens, FeathersPlugin,
|
||||
},
|
||||
input_focus::{
|
||||
tab_navigation::{TabGroup, TabNavigationPlugin},
|
||||
tab_navigation::{TabGroup, TabIndex, TabNavigationPlugin},
|
||||
InputDispatchPlugin,
|
||||
},
|
||||
prelude::*,
|
||||
@ -215,6 +215,7 @@ fn demo_root(commands: &mut Commands) -> impl Bundle {
|
||||
CoreRadioGroup {
|
||||
on_change: Callback::System(radio_exclusion),
|
||||
},
|
||||
TabIndex(0),
|
||||
children![
|
||||
radio(Checked, Spawn((Text::new("One"), ThemedText))),
|
||||
radio((), Spawn((Text::new("Two"), ThemedText))),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Bevy Feathers
|
||||
authors: ["@viridia", "@Atlas16A"]
|
||||
pull_requests: [19730, 19900, 19928]
|
||||
pull_requests: [19730, 19900, 19928, 20047]
|
||||
---
|
||||
|
||||
To make it easier for Bevy engine developers and third-party tool creators to make comfortable, visually cohesive tooling,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user