Merge bb9dd8e0f2
into 877d278785
This commit is contained in:
commit
b6d4da6203
@ -22,6 +22,7 @@ bevy_math = { path = "../bevy_math", version = "0.17.0-dev" }
|
|||||||
bevy_picking = { path = "../bevy_picking", version = "0.17.0-dev" }
|
bevy_picking = { path = "../bevy_picking", version = "0.17.0-dev" }
|
||||||
bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev" }
|
bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev" }
|
||||||
bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
|
bevy_render = { path = "../bevy_render", version = "0.17.0-dev" }
|
||||||
|
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev" }
|
||||||
bevy_text = { path = "../bevy_text", version = "0.17.0-dev" }
|
bevy_text = { path = "../bevy_text", version = "0.17.0-dev" }
|
||||||
bevy_ui = { path = "../bevy_ui", version = "0.17.0-dev", features = [
|
bevy_ui = { path = "../bevy_ui", version = "0.17.0-dev", features = [
|
||||||
"bevy_ui_picking_backend",
|
"bevy_ui_picking_backend",
|
||||||
@ -34,6 +35,7 @@ accesskit = "0.19"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
custom_cursor = ["bevy_winit/custom_cursor"]
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
@ -14,10 +14,10 @@ use bevy_ecs::{
|
|||||||
use bevy_input_focus::tab_navigation::TabIndex;
|
use bevy_input_focus::tab_navigation::TabIndex;
|
||||||
use bevy_picking::{hover::Hovered, PickingSystems};
|
use bevy_picking::{hover::Hovered, PickingSystems};
|
||||||
use bevy_ui::{AlignItems, InteractionDisabled, JustifyContent, Node, Pressed, UiRect, Val};
|
use bevy_ui::{AlignItems, InteractionDisabled, JustifyContent, Node, Pressed, UiRect, Val};
|
||||||
use bevy_winit::cursor::CursorIcon;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{fonts, size},
|
constants::{fonts, size},
|
||||||
|
cursor::EntityCursor,
|
||||||
font_styles::InheritableFont,
|
font_styles::InheritableFont,
|
||||||
handle_or_path::HandleOrPath,
|
handle_or_path::HandleOrPath,
|
||||||
rounded_corners::RoundedCorners,
|
rounded_corners::RoundedCorners,
|
||||||
@ -73,7 +73,7 @@ pub fn button<C: SpawnableList<ChildOf> + Send + Sync + 'static, B: Bundle>(
|
|||||||
},
|
},
|
||||||
props.variant,
|
props.variant,
|
||||||
Hovered::default(),
|
Hovered::default(),
|
||||||
CursorIcon::System(bevy_window::SystemCursorIcon::Pointer),
|
EntityCursor::System(bevy_window::SystemCursorIcon::Pointer),
|
||||||
TabIndex(0),
|
TabIndex(0),
|
||||||
props.corners.to_border_radius(4.0),
|
props.corners.to_border_radius(4.0),
|
||||||
ThemeBackgroundColor(tokens::BUTTON_BG),
|
ThemeBackgroundColor(tokens::BUTTON_BG),
|
||||||
|
@ -20,10 +20,10 @@ use bevy_ui::{
|
|||||||
AlignItems, BorderRadius, Checked, Display, FlexDirection, InteractionDisabled, JustifyContent,
|
AlignItems, BorderRadius, Checked, Display, FlexDirection, InteractionDisabled, JustifyContent,
|
||||||
Node, PositionType, UiRect, UiTransform, Val,
|
Node, PositionType, UiRect, UiTransform, Val,
|
||||||
};
|
};
|
||||||
use bevy_winit::cursor::CursorIcon;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{fonts, size},
|
constants::{fonts, size},
|
||||||
|
cursor::EntityCursor,
|
||||||
font_styles::InheritableFont,
|
font_styles::InheritableFont,
|
||||||
handle_or_path::HandleOrPath,
|
handle_or_path::HandleOrPath,
|
||||||
theme::{ThemeBackgroundColor, ThemeBorderColor, ThemeFontColor},
|
theme::{ThemeBackgroundColor, ThemeBorderColor, ThemeFontColor},
|
||||||
@ -74,7 +74,7 @@ pub fn checkbox<C: SpawnableList<ChildOf> + Send + Sync + 'static, B: Bundle>(
|
|||||||
},
|
},
|
||||||
CheckboxFrame,
|
CheckboxFrame,
|
||||||
Hovered::default(),
|
Hovered::default(),
|
||||||
CursorIcon::System(bevy_window::SystemCursorIcon::Pointer),
|
EntityCursor::System(bevy_window::SystemCursorIcon::Pointer),
|
||||||
TabIndex(0),
|
TabIndex(0),
|
||||||
ThemeFontColor(tokens::CHECKBOX_TEXT),
|
ThemeFontColor(tokens::CHECKBOX_TEXT),
|
||||||
InheritableFont {
|
InheritableFont {
|
||||||
|
@ -19,10 +19,10 @@ use bevy_ui::{
|
|||||||
AlignItems, BorderRadius, Checked, Display, FlexDirection, InteractionDisabled, JustifyContent,
|
AlignItems, BorderRadius, Checked, Display, FlexDirection, InteractionDisabled, JustifyContent,
|
||||||
Node, UiRect, Val,
|
Node, UiRect, Val,
|
||||||
};
|
};
|
||||||
use bevy_winit::cursor::CursorIcon;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{fonts, size},
|
constants::{fonts, size},
|
||||||
|
cursor::EntityCursor,
|
||||||
font_styles::InheritableFont,
|
font_styles::InheritableFont,
|
||||||
handle_or_path::HandleOrPath,
|
handle_or_path::HandleOrPath,
|
||||||
theme::{ThemeBackgroundColor, ThemeBorderColor, ThemeFontColor},
|
theme::{ThemeBackgroundColor, ThemeBorderColor, ThemeFontColor},
|
||||||
@ -58,7 +58,7 @@ pub fn radio<C: SpawnableList<ChildOf> + Send + Sync + 'static, B: Bundle>(
|
|||||||
},
|
},
|
||||||
CoreRadio,
|
CoreRadio,
|
||||||
Hovered::default(),
|
Hovered::default(),
|
||||||
CursorIcon::System(bevy_window::SystemCursorIcon::Pointer),
|
EntityCursor::System(bevy_window::SystemCursorIcon::Pointer),
|
||||||
TabIndex(0),
|
TabIndex(0),
|
||||||
ThemeFontColor(tokens::RADIO_TEXT),
|
ThemeFontColor(tokens::RADIO_TEXT),
|
||||||
InheritableFont {
|
InheritableFont {
|
||||||
|
@ -22,10 +22,10 @@ use bevy_ui::{
|
|||||||
InteractionDisabled, InterpolationColorSpace, JustifyContent, LinearGradient, Node, UiRect,
|
InteractionDisabled, InterpolationColorSpace, JustifyContent, LinearGradient, Node, UiRect,
|
||||||
Val,
|
Val,
|
||||||
};
|
};
|
||||||
use bevy_winit::cursor::CursorIcon;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{fonts, size},
|
constants::{fonts, size},
|
||||||
|
cursor::EntityCursor,
|
||||||
font_styles::InheritableFont,
|
font_styles::InheritableFont,
|
||||||
handle_or_path::HandleOrPath,
|
handle_or_path::HandleOrPath,
|
||||||
rounded_corners::RoundedCorners,
|
rounded_corners::RoundedCorners,
|
||||||
@ -87,7 +87,7 @@ pub fn slider<B: Bundle>(props: SliderProps, overrides: B) -> impl Bundle {
|
|||||||
SliderStyle,
|
SliderStyle,
|
||||||
SliderValue(props.value),
|
SliderValue(props.value),
|
||||||
SliderRange::new(props.min, props.max),
|
SliderRange::new(props.min, props.max),
|
||||||
CursorIcon::System(bevy_window::SystemCursorIcon::EwResize),
|
EntityCursor::System(bevy_window::SystemCursorIcon::EwResize),
|
||||||
TabIndex(0),
|
TabIndex(0),
|
||||||
RoundedCorners::All.to_border_radius(6.0),
|
RoundedCorners::All.to_border_radius(6.0),
|
||||||
// Use a gradient to draw the moving bar
|
// Use a gradient to draw the moving bar
|
||||||
|
@ -18,10 +18,10 @@ use bevy_ecs::{
|
|||||||
use bevy_input_focus::tab_navigation::TabIndex;
|
use bevy_input_focus::tab_navigation::TabIndex;
|
||||||
use bevy_picking::{hover::Hovered, PickingSystems};
|
use bevy_picking::{hover::Hovered, PickingSystems};
|
||||||
use bevy_ui::{BorderRadius, Checked, InteractionDisabled, Node, PositionType, UiRect, Val};
|
use bevy_ui::{BorderRadius, Checked, InteractionDisabled, Node, PositionType, UiRect, Val};
|
||||||
use bevy_winit::cursor::CursorIcon;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::size,
|
constants::size,
|
||||||
|
cursor::EntityCursor,
|
||||||
theme::{ThemeBackgroundColor, ThemeBorderColor},
|
theme::{ThemeBackgroundColor, ThemeBorderColor},
|
||||||
tokens,
|
tokens,
|
||||||
};
|
};
|
||||||
@ -63,7 +63,7 @@ pub fn toggle_switch<B: Bundle>(props: ToggleSwitchProps, overrides: B) -> impl
|
|||||||
ThemeBorderColor(tokens::SWITCH_BORDER),
|
ThemeBorderColor(tokens::SWITCH_BORDER),
|
||||||
AccessibilityNode(accesskit::Node::new(Role::Switch)),
|
AccessibilityNode(accesskit::Node::new(Role::Switch)),
|
||||||
Hovered::default(),
|
Hovered::default(),
|
||||||
CursorIcon::System(bevy_window::SystemCursorIcon::Pointer),
|
EntityCursor::System(bevy_window::SystemCursorIcon::Pointer),
|
||||||
TabIndex(0),
|
TabIndex(0),
|
||||||
overrides,
|
overrides,
|
||||||
children![(
|
children![(
|
||||||
|
@ -1,31 +1,82 @@
|
|||||||
//! Provides a way to automatically set the mouse cursor based on hovered entity.
|
//! Provides a way to automatically set the mouse cursor based on hovered entity.
|
||||||
use bevy_app::{App, Plugin, PreUpdate};
|
use bevy_app::{App, Plugin, PreUpdate};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
hierarchy::ChildOf,
|
hierarchy::ChildOf,
|
||||||
|
reflect::ReflectComponent,
|
||||||
resource::Resource,
|
resource::Resource,
|
||||||
schedule::IntoScheduleConfigs,
|
schedule::IntoScheduleConfigs,
|
||||||
system::{Commands, Query, Res},
|
system::{Commands, Query, Res},
|
||||||
};
|
};
|
||||||
use bevy_picking::{hover::HoverMap, pointer::PointerId, PickingSystems};
|
use bevy_picking::{hover::HoverMap, pointer::PointerId, PickingSystems};
|
||||||
use bevy_window::Window;
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||||
|
use bevy_window::{SystemCursorIcon, Window};
|
||||||
use bevy_winit::cursor::CursorIcon;
|
use bevy_winit::cursor::CursorIcon;
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
|
use bevy_winit::cursor::CustomCursor;
|
||||||
|
|
||||||
/// A component that specifies the cursor icon to be used when the mouse is not hovering over
|
/// A resource that specifies the cursor icon to be used when the mouse is not hovering over
|
||||||
/// any other entity. This is used to set the default cursor icon for the window.
|
/// any other entity. This is used to set the default cursor icon for the window.
|
||||||
#[derive(Resource, Debug, Clone, Default)]
|
#[derive(Resource, Debug, Clone, Default)]
|
||||||
pub struct DefaultCursorIcon(pub CursorIcon);
|
pub struct DefaultCursor(pub EntityCursor);
|
||||||
|
|
||||||
|
/// A component that specifies the cursor shape to be used when the pointer hovers over an entity.
|
||||||
|
/// This is copied to the windows's [`CursorIcon`] component.
|
||||||
|
///
|
||||||
|
/// This is effectively the same type as [`CustomCursor`] but with different methods, and used
|
||||||
|
/// in different places.
|
||||||
|
#[derive(Component, Debug, Clone, Reflect, PartialEq, Eq)]
|
||||||
|
#[reflect(Component, Debug, Default, PartialEq, Clone)]
|
||||||
|
pub enum EntityCursor {
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
|
/// Custom cursor image.
|
||||||
|
Custom(CustomCursor),
|
||||||
|
/// System provided cursor icon.
|
||||||
|
System(SystemCursorIcon),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EntityCursor {
|
||||||
|
/// Convert the [`EntityCursor`] to a [`CursorIcon`] so that it can be inserted into a
|
||||||
|
/// window.
|
||||||
|
pub fn to_cursor_icon(&self) -> CursorIcon {
|
||||||
|
match self {
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
|
EntityCursor::Custom(custom_cursor) => CursorIcon::Custom(custom_cursor.clone()),
|
||||||
|
EntityCursor::System(icon) => CursorIcon::from(*icon),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compare the [`EntityCursor`] to a [`CursorIcon`] so that we can see whether or not
|
||||||
|
/// the window cursor needs to be changed.
|
||||||
|
pub fn eq_cursor_icon(&self, cursor_icon: &CursorIcon) -> bool {
|
||||||
|
match (self, cursor_icon) {
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
|
(EntityCursor::Custom(custom), CursorIcon::Custom(other)) => custom == other,
|
||||||
|
(EntityCursor::System(system), CursorIcon::System(cursor_icon)) => {
|
||||||
|
*system == *cursor_icon
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EntityCursor {
|
||||||
|
fn default() -> Self {
|
||||||
|
EntityCursor::System(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// System which updates the window cursor icon whenever the mouse hovers over an entity with
|
/// System which updates the window cursor icon whenever the mouse hovers over an entity with
|
||||||
/// a [`CursorIcon`] component. If no entity is hovered, the cursor icon is set to
|
/// a [`CursorIcon`] component. If no entity is hovered, the cursor icon is set to
|
||||||
/// the cursor in the [`DefaultCursorIcon`] resource.
|
/// the cursor in the [`DefaultCursor`] resource.
|
||||||
pub(crate) fn update_cursor(
|
pub(crate) fn update_cursor(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
hover_map: Option<Res<HoverMap>>,
|
hover_map: Option<Res<HoverMap>>,
|
||||||
parent_query: Query<&ChildOf>,
|
parent_query: Query<&ChildOf>,
|
||||||
cursor_query: Query<&CursorIcon>,
|
cursor_query: Query<&EntityCursor>,
|
||||||
mut q_windows: Query<(Entity, &mut Window, Option<&CursorIcon>)>,
|
mut q_windows: Query<(Entity, &mut Window, Option<&CursorIcon>)>,
|
||||||
r_default_cursor: Res<DefaultCursorIcon>,
|
r_default_cursor: Res<DefaultCursor>,
|
||||||
) {
|
) {
|
||||||
let cursor = hover_map.and_then(|hover_map| match hover_map.get(&PointerId::Mouse) {
|
let cursor = hover_map.and_then(|hover_map| match hover_map.get(&PointerId::Mouse) {
|
||||||
Some(hover_set) => hover_set.keys().find_map(|entity| {
|
Some(hover_set) => hover_set.keys().find_map(|entity| {
|
||||||
@ -41,7 +92,7 @@ pub(crate) fn update_cursor(
|
|||||||
let mut windows_to_change: Vec<Entity> = Vec::new();
|
let mut windows_to_change: Vec<Entity> = Vec::new();
|
||||||
for (entity, _window, prev_cursor) in q_windows.iter_mut() {
|
for (entity, _window, prev_cursor) in q_windows.iter_mut() {
|
||||||
match (cursor, prev_cursor) {
|
match (cursor, prev_cursor) {
|
||||||
(Some(cursor), Some(prev_cursor)) if cursor == prev_cursor => continue,
|
(Some(cursor), Some(prev_cursor)) if cursor.eq_cursor_icon(prev_cursor) => continue,
|
||||||
(None, None) => continue,
|
(None, None) => continue,
|
||||||
_ => {
|
_ => {
|
||||||
windows_to_change.push(entity);
|
windows_to_change.push(entity);
|
||||||
@ -50,9 +101,11 @@ pub(crate) fn update_cursor(
|
|||||||
}
|
}
|
||||||
windows_to_change.iter().for_each(|entity| {
|
windows_to_change.iter().for_each(|entity| {
|
||||||
if let Some(cursor) = cursor {
|
if let Some(cursor) = cursor {
|
||||||
commands.entity(*entity).insert(cursor.clone());
|
commands.entity(*entity).insert(cursor.to_cursor_icon());
|
||||||
} else {
|
} else {
|
||||||
commands.entity(*entity).insert(r_default_cursor.0.clone());
|
commands
|
||||||
|
.entity(*entity)
|
||||||
|
.insert(r_default_cursor.0.to_cursor_icon());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -62,8 +115,8 @@ pub struct CursorIconPlugin;
|
|||||||
|
|
||||||
impl Plugin for CursorIconPlugin {
|
impl Plugin for CursorIconPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
if app.world().get_resource::<DefaultCursorIcon>().is_none() {
|
if app.world().get_resource::<DefaultCursor>().is_none() {
|
||||||
app.init_resource::<DefaultCursorIcon>();
|
app.init_resource::<DefaultCursor>();
|
||||||
}
|
}
|
||||||
app.add_systems(PreUpdate, update_cursor.in_set(PickingSystems::Last));
|
app.add_systems(PreUpdate, update_cursor.in_set(PickingSystems::Last));
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,10 @@ use bevy_app::{HierarchyPropagatePlugin, Plugin, PostUpdate};
|
|||||||
use bevy_asset::embedded_asset;
|
use bevy_asset::embedded_asset;
|
||||||
use bevy_ecs::query::With;
|
use bevy_ecs::query::With;
|
||||||
use bevy_text::{TextColor, TextFont};
|
use bevy_text::{TextColor, TextFont};
|
||||||
use bevy_winit::cursor::CursorIcon;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
controls::ControlsPlugin,
|
controls::ControlsPlugin,
|
||||||
cursor::{CursorIconPlugin, DefaultCursorIcon},
|
cursor::{CursorIconPlugin, DefaultCursor, EntityCursor},
|
||||||
theme::{ThemedText, UiTheme},
|
theme::{ThemedText, UiTheme},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,7 +60,7 @@ impl Plugin for FeathersPlugin {
|
|||||||
HierarchyPropagatePlugin::<TextFont, With<ThemedText>>::default(),
|
HierarchyPropagatePlugin::<TextFont, With<ThemedText>>::default(),
|
||||||
));
|
));
|
||||||
|
|
||||||
app.insert_resource(DefaultCursorIcon(CursorIcon::System(
|
app.insert_resource(DefaultCursor(EntityCursor::System(
|
||||||
bevy_window::SystemCursorIcon::Default,
|
bevy_window::SystemCursorIcon::Default,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: Bevy Feathers
|
title: Bevy Feathers
|
||||||
authors: ["@viridia", "@Atlas16A"]
|
authors: ["@viridia", "@Atlas16A"]
|
||||||
pull_requests: [19730, 19900, 19928]
|
pull_requests: [19730, 19900, 19928, 20169]
|
||||||
---
|
---
|
||||||
|
|
||||||
To make it easier for Bevy engine developers and third-party tool creators to make comfortable, visually cohesive tooling,
|
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