mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 13:43:04 +00:00
Correctly feature gate custom_cursor
(#16093)
# Objective Currently there's no way to change the window's cursor icon with the `custom_cursor` feature **disabled**. You should still be able to set system cursor icons. Connections: - https://github.com/bevyengine/bevy/pull/15649 ## Solution Move some `custom_cursor` feature gates around, as to expose the `CursorIcon` type again. Note this refactoring was mainly piloted by hunting after the compiler warnings -- I shouldn't have missed anything, but FYI. ## Testing Disabled the `custom_cursor` feature, ran the `window_settings` example.
This commit is contained in:
parent
17e504812b
commit
565616622b
5 changed files with 48 additions and 16 deletions
|
@ -6,7 +6,6 @@ use bevy_input::{
|
||||||
ButtonState,
|
ButtonState,
|
||||||
};
|
};
|
||||||
use bevy_math::{CompassOctant, Vec2};
|
use bevy_math::{CompassOctant, Vec2};
|
||||||
#[cfg(feature = "custom_cursor")]
|
|
||||||
use bevy_window::SystemCursorIcon;
|
use bevy_window::SystemCursorIcon;
|
||||||
use bevy_window::{EnabledButtons, WindowLevel, WindowTheme};
|
use bevy_window::{EnabledButtons, WindowLevel, WindowTheme};
|
||||||
use winit::keyboard::{Key, NamedKey, NativeKey};
|
use winit::keyboard::{Key, NamedKey, NativeKey};
|
||||||
|
@ -630,7 +629,6 @@ pub fn convert_native_key(native_key: &NativeKey) -> bevy_input::keyboard::Nativ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "custom_cursor")]
|
|
||||||
/// Converts a [`SystemCursorIcon`] to a [`winit::window::CursorIcon`].
|
/// Converts a [`SystemCursorIcon`] to a [`winit::window::CursorIcon`].
|
||||||
pub fn convert_system_cursor_icon(cursor_icon: SystemCursorIcon) -> winit::window::CursorIcon {
|
pub fn convert_system_cursor_icon(cursor_icon: SystemCursorIcon) -> winit::window::CursorIcon {
|
||||||
match cursor_icon {
|
match cursor_icon {
|
||||||
|
|
|
@ -2,11 +2,18 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
converters::convert_system_cursor_icon,
|
converters::convert_system_cursor_icon,
|
||||||
state::{CursorSource, CustomCursorCache, CustomCursorCacheKey, PendingCursor},
|
state::{CursorSource, PendingCursor},
|
||||||
|
};
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
|
use crate::{
|
||||||
|
state::{CustomCursorCache, CustomCursorCacheKey},
|
||||||
WinitCustomCursor,
|
WinitCustomCursor,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Last, Plugin};
|
use bevy_app::{App, Last, Plugin};
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
|
use bevy_ecs::system::Res;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
change_detection::DetectChanges,
|
change_detection::DetectChanges,
|
||||||
component::Component,
|
component::Component,
|
||||||
|
@ -14,21 +21,27 @@ use bevy_ecs::{
|
||||||
observer::Trigger,
|
observer::Trigger,
|
||||||
query::With,
|
query::With,
|
||||||
reflect::ReflectComponent,
|
reflect::ReflectComponent,
|
||||||
system::{Commands, Local, Query, Res},
|
system::{Commands, Local, Query},
|
||||||
world::{OnRemove, Ref},
|
world::{OnRemove, Ref},
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
use bevy_image::Image;
|
use bevy_image::Image;
|
||||||
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
||||||
use bevy_utils::{tracing::warn, HashSet};
|
#[cfg(feature = "custom_cursor")]
|
||||||
|
use bevy_utils::tracing::warn;
|
||||||
|
use bevy_utils::HashSet;
|
||||||
use bevy_window::{SystemCursorIcon, Window};
|
use bevy_window::{SystemCursorIcon, Window};
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
use wgpu_types::TextureFormat;
|
use wgpu_types::TextureFormat;
|
||||||
|
|
||||||
pub(crate) struct CursorPlugin;
|
pub(crate) struct CursorPlugin;
|
||||||
|
|
||||||
impl Plugin for CursorPlugin {
|
impl Plugin for CursorPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
|
app.init_resource::<CustomCursorCache>();
|
||||||
|
|
||||||
app.register_type::<CursorIcon>()
|
app.register_type::<CursorIcon>()
|
||||||
.init_resource::<CustomCursorCache>()
|
|
||||||
.add_systems(Last, update_cursors);
|
.add_systems(Last, update_cursors);
|
||||||
|
|
||||||
app.add_observer(on_remove_cursor_icon);
|
app.add_observer(on_remove_cursor_icon);
|
||||||
|
@ -39,6 +52,7 @@ impl Plugin for CursorPlugin {
|
||||||
#[derive(Component, Debug, Clone, Reflect, PartialEq, Eq)]
|
#[derive(Component, Debug, Clone, Reflect, PartialEq, Eq)]
|
||||||
#[reflect(Component, Debug, Default, PartialEq)]
|
#[reflect(Component, Debug, Default, PartialEq)]
|
||||||
pub enum CursorIcon {
|
pub enum CursorIcon {
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
/// Custom cursor image.
|
/// Custom cursor image.
|
||||||
Custom(CustomCursor),
|
Custom(CustomCursor),
|
||||||
/// System provided cursor icon.
|
/// System provided cursor icon.
|
||||||
|
@ -57,12 +71,14 @@ impl From<SystemCursorIcon> for CursorIcon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
impl From<CustomCursor> for CursorIcon {
|
impl From<CustomCursor> for CursorIcon {
|
||||||
fn from(cursor: CustomCursor) -> Self {
|
fn from(cursor: CustomCursor) -> Self {
|
||||||
CursorIcon::Custom(cursor)
|
CursorIcon::Custom(cursor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
/// Custom cursor image data.
|
/// Custom cursor image data.
|
||||||
#[derive(Debug, Clone, Reflect, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Reflect, PartialEq, Eq, Hash)]
|
||||||
pub enum CustomCursor {
|
pub enum CustomCursor {
|
||||||
|
@ -90,8 +106,8 @@ pub enum CustomCursor {
|
||||||
fn update_cursors(
|
fn update_cursors(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
windows: Query<(Entity, Ref<CursorIcon>), With<Window>>,
|
windows: Query<(Entity, Ref<CursorIcon>), With<Window>>,
|
||||||
cursor_cache: Res<CustomCursorCache>,
|
#[cfg(feature = "custom_cursor")] cursor_cache: Res<CustomCursorCache>,
|
||||||
images: Res<Assets<Image>>,
|
#[cfg(feature = "custom_cursor")] images: Res<Assets<Image>>,
|
||||||
mut queue: Local<HashSet<Entity>>,
|
mut queue: Local<HashSet<Entity>>,
|
||||||
) {
|
) {
|
||||||
for (entity, cursor) in windows.iter() {
|
for (entity, cursor) in windows.iter() {
|
||||||
|
@ -100,6 +116,7 @@ fn update_cursors(
|
||||||
}
|
}
|
||||||
|
|
||||||
let cursor_source = match cursor.as_ref() {
|
let cursor_source = match cursor.as_ref() {
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
CursorIcon::Custom(CustomCursor::Image { handle, hotspot }) => {
|
CursorIcon::Custom(CustomCursor::Image { handle, hotspot }) => {
|
||||||
let cache_key = CustomCursorCacheKey::Asset(handle.id());
|
let cache_key = CustomCursorCacheKey::Asset(handle.id());
|
||||||
|
|
||||||
|
@ -170,6 +187,7 @@ fn on_remove_cursor_icon(trigger: Trigger<OnRemove, CursorIcon>, mut commands: C
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
/// Returns the image data as a `Vec<u8>`.
|
/// Returns the image data as a `Vec<u8>`.
|
||||||
/// Only supports rgba8 and rgba32float formats.
|
/// Only supports rgba8 and rgba32float formats.
|
||||||
fn image_to_rgba_pixels(image: &Image) -> Option<Vec<u8>> {
|
fn image_to_rgba_pixels(image: &Image) -> Option<Vec<u8>> {
|
||||||
|
|
|
@ -44,7 +44,6 @@ use crate::{
|
||||||
|
|
||||||
pub mod accessibility;
|
pub mod accessibility;
|
||||||
mod converters;
|
mod converters;
|
||||||
#[cfg(feature = "custom_cursor")]
|
|
||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
mod state;
|
mod state;
|
||||||
mod system;
|
mod system;
|
||||||
|
@ -136,7 +135,6 @@ impl<T: Event> Plugin for WinitPlugin<T> {
|
||||||
);
|
);
|
||||||
|
|
||||||
app.add_plugins(AccessKitPlugin);
|
app.add_plugins(AccessKitPlugin);
|
||||||
#[cfg(feature = "custom_cursor")]
|
|
||||||
app.add_plugins(cursor::CursorPlugin);
|
app.add_plugins(cursor::CursorPlugin);
|
||||||
|
|
||||||
let event_loop = event_loop_builder
|
let event_loop = event_loop_builder
|
||||||
|
|
|
@ -158,19 +158,19 @@ pub enum CustomCursorCacheKey {
|
||||||
#[derive(Debug, Clone, Default, Resource)]
|
#[derive(Debug, Clone, Default, Resource)]
|
||||||
pub struct CustomCursorCache(pub HashMap<CustomCursorCacheKey, winit::window::CustomCursor>);
|
pub struct CustomCursorCache(pub HashMap<CustomCursorCacheKey, winit::window::CustomCursor>);
|
||||||
|
|
||||||
#[cfg(feature = "custom_cursor")]
|
|
||||||
/// A source for a cursor. Consumed by the winit event loop.
|
/// A source for a cursor. Consumed by the winit event loop.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum CursorSource {
|
pub enum CursorSource {
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
/// A custom cursor was identified to be cached, no reason to recreate it.
|
/// A custom cursor was identified to be cached, no reason to recreate it.
|
||||||
CustomCached(CustomCursorCacheKey),
|
CustomCached(CustomCursorCacheKey),
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
/// A custom cursor was not cached, so it needs to be created by the winit event loop.
|
/// A custom cursor was not cached, so it needs to be created by the winit event loop.
|
||||||
Custom((CustomCursorCacheKey, winit::window::CustomCursorSource)),
|
Custom((CustomCursorCacheKey, winit::window::CustomCursorSource)),
|
||||||
/// A system cursor was requested.
|
/// A system cursor was requested.
|
||||||
System(winit::window::CursorIcon),
|
System(winit::window::CursorIcon),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "custom_cursor")]
|
|
||||||
/// Component that indicates what cursor should be used for a window. Inserted
|
/// Component that indicates what cursor should be used for a window. Inserted
|
||||||
/// automatically after changing `CursorIcon` and consumed by the winit event
|
/// automatically after changing `CursorIcon` and consumed by the winit event
|
||||||
/// loop.
|
/// loop.
|
||||||
|
@ -560,6 +560,8 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
||||||
self.run_app_update();
|
self.run_app_update();
|
||||||
#[cfg(feature = "custom_cursor")]
|
#[cfg(feature = "custom_cursor")]
|
||||||
self.update_cursors(event_loop);
|
self.update_cursors(event_loop);
|
||||||
|
#[cfg(not(feature = "custom_cursor"))]
|
||||||
|
self.update_cursors();
|
||||||
self.ran_update_since_last_redraw = true;
|
self.ran_update_since_last_redraw = true;
|
||||||
} else {
|
} else {
|
||||||
self.redraw_requested = true;
|
self.redraw_requested = true;
|
||||||
|
@ -787,15 +789,23 @@ impl<T: Event> WinitAppRunnerState<T> {
|
||||||
.send_batch(buffered_events);
|
.send_batch(buffered_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "custom_cursor")]
|
fn update_cursors(&mut self, #[cfg(feature = "custom_cursor")] event_loop: &ActiveEventLoop) {
|
||||||
fn update_cursors(&mut self, event_loop: &ActiveEventLoop) {
|
#[cfg(feature = "custom_cursor")]
|
||||||
let mut windows_state: SystemState<(
|
let mut windows_state: SystemState<(
|
||||||
NonSendMut<WinitWindows>,
|
NonSendMut<WinitWindows>,
|
||||||
ResMut<CustomCursorCache>,
|
ResMut<CustomCursorCache>,
|
||||||
Query<(Entity, &mut PendingCursor), Changed<PendingCursor>>,
|
Query<(Entity, &mut PendingCursor), Changed<PendingCursor>>,
|
||||||
)> = SystemState::new(self.world_mut());
|
)> = SystemState::new(self.world_mut());
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
let (winit_windows, mut cursor_cache, mut windows) =
|
let (winit_windows, mut cursor_cache, mut windows) =
|
||||||
windows_state.get_mut(self.world_mut());
|
windows_state.get_mut(self.world_mut());
|
||||||
|
#[cfg(not(feature = "custom_cursor"))]
|
||||||
|
let mut windows_state: SystemState<(
|
||||||
|
NonSendMut<WinitWindows>,
|
||||||
|
Query<(Entity, &mut PendingCursor), Changed<PendingCursor>>,
|
||||||
|
)> = SystemState::new(self.world_mut());
|
||||||
|
#[cfg(not(feature = "custom_cursor"))]
|
||||||
|
let (winit_windows, mut windows) = windows_state.get_mut(self.world_mut());
|
||||||
|
|
||||||
for (entity, mut pending_cursor) in windows.iter_mut() {
|
for (entity, mut pending_cursor) in windows.iter_mut() {
|
||||||
let Some(winit_window) = winit_windows.get_window(entity) else {
|
let Some(winit_window) = winit_windows.get_window(entity) else {
|
||||||
|
@ -806,6 +816,7 @@ impl<T: Event> WinitAppRunnerState<T> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let final_cursor: winit::window::Cursor = match pending_cursor {
|
let final_cursor: winit::window::Cursor = match pending_cursor {
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
CursorSource::CustomCached(cache_key) => {
|
CursorSource::CustomCached(cache_key) => {
|
||||||
let Some(cached_cursor) = cursor_cache.0.get(&cache_key) else {
|
let Some(cached_cursor) = cursor_cache.0.get(&cache_key) else {
|
||||||
error!("Cursor should have been cached, but was not found");
|
error!("Cursor should have been cached, but was not found");
|
||||||
|
@ -813,6 +824,7 @@ impl<T: Event> WinitAppRunnerState<T> {
|
||||||
};
|
};
|
||||||
cached_cursor.clone().into()
|
cached_cursor.clone().into()
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
CursorSource::Custom((cache_key, cursor)) => {
|
CursorSource::Custom((cache_key, cursor)) => {
|
||||||
let custom_cursor = event_loop.create_custom_cursor(cursor);
|
let custom_cursor = event_loop.create_custom_cursor(cursor);
|
||||||
cursor_cache.0.insert(cache_key, custom_cursor.clone());
|
cursor_cache.0.insert(cache_key, custom_cursor.clone());
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
//! Illustrates how to change window settings and shows how to affect
|
//! Illustrates how to change window settings and shows how to affect
|
||||||
//! the mouse pointer in various ways.
|
//! the mouse pointer in various ways.
|
||||||
|
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
|
use bevy::winit::cursor::CustomCursor;
|
||||||
use bevy::{
|
use bevy::{
|
||||||
core::FrameCount,
|
core::FrameCount,
|
||||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
window::{CursorGrabMode, PresentMode, SystemCursorIcon, WindowLevel, WindowTheme},
|
window::{CursorGrabMode, PresentMode, SystemCursorIcon, WindowLevel, WindowTheme},
|
||||||
winit::cursor::{CursorIcon, CustomCursor},
|
winit::cursor::CursorIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -152,12 +154,16 @@ fn toggle_theme(mut window: Single<&mut Window>, input: Res<ButtonInput<KeyCode>
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
struct CursorIcons(Vec<CursorIcon>);
|
struct CursorIcons(Vec<CursorIcon>);
|
||||||
|
|
||||||
fn init_cursor_icons(mut commands: Commands, asset_server: Res<AssetServer>) {
|
fn init_cursor_icons(
|
||||||
|
mut commands: Commands,
|
||||||
|
#[cfg(feature = "custom_cursor")] asset_server: Res<AssetServer>,
|
||||||
|
) {
|
||||||
commands.insert_resource(CursorIcons(vec![
|
commands.insert_resource(CursorIcons(vec![
|
||||||
SystemCursorIcon::Default.into(),
|
SystemCursorIcon::Default.into(),
|
||||||
SystemCursorIcon::Pointer.into(),
|
SystemCursorIcon::Pointer.into(),
|
||||||
SystemCursorIcon::Wait.into(),
|
SystemCursorIcon::Wait.into(),
|
||||||
SystemCursorIcon::Text.into(),
|
SystemCursorIcon::Text.into(),
|
||||||
|
#[cfg(feature = "custom_cursor")]
|
||||||
CustomCursor::Image {
|
CustomCursor::Image {
|
||||||
handle: asset_server.load("branding/icon.png"),
|
handle: asset_server.load("branding/icon.png"),
|
||||||
hotspot: (128, 128),
|
hotspot: (128, 128),
|
||||||
|
|
Loading…
Reference in a new issue