Skip to content

Commit

Permalink
Correctly feature gate custom_cursor (#16093)
Browse files Browse the repository at this point in the history
# 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:

- #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.
  • Loading branch information
Friz64 authored Nov 2, 2024
1 parent 17e5048 commit 5656166
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 16 deletions.
2 changes: 0 additions & 2 deletions crates/bevy_winit/src/converters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use bevy_input::{
ButtonState,
};
use bevy_math::{CompassOctant, Vec2};
#[cfg(feature = "custom_cursor")]
use bevy_window::SystemCursorIcon;
use bevy_window::{EnabledButtons, WindowLevel, WindowTheme};
use winit::keyboard::{Key, NamedKey, NativeKey};
Expand Down Expand Up @@ -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`].
pub fn convert_system_cursor_icon(cursor_icon: SystemCursorIcon) -> winit::window::CursorIcon {
match cursor_icon {
Expand Down
30 changes: 24 additions & 6 deletions crates/bevy_winit/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,46 @@

use crate::{
converters::convert_system_cursor_icon,
state::{CursorSource, CustomCursorCache, CustomCursorCacheKey, PendingCursor},
state::{CursorSource, PendingCursor},
};
#[cfg(feature = "custom_cursor")]
use crate::{
state::{CustomCursorCache, CustomCursorCacheKey},
WinitCustomCursor,
};
use bevy_app::{App, Last, Plugin};
#[cfg(feature = "custom_cursor")]
use bevy_asset::{Assets, Handle};
#[cfg(feature = "custom_cursor")]
use bevy_ecs::system::Res;
use bevy_ecs::{
change_detection::DetectChanges,
component::Component,
entity::Entity,
observer::Trigger,
query::With,
reflect::ReflectComponent,
system::{Commands, Local, Query, Res},
system::{Commands, Local, Query},
world::{OnRemove, Ref},
};
#[cfg(feature = "custom_cursor")]
use bevy_image::Image;
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};
#[cfg(feature = "custom_cursor")]
use wgpu_types::TextureFormat;

pub(crate) struct CursorPlugin;

impl Plugin for CursorPlugin {
fn build(&self, app: &mut App) {
#[cfg(feature = "custom_cursor")]
app.init_resource::<CustomCursorCache>();

app.register_type::<CursorIcon>()
.init_resource::<CustomCursorCache>()
.add_systems(Last, update_cursors);

app.add_observer(on_remove_cursor_icon);
Expand All @@ -39,6 +52,7 @@ impl Plugin for CursorPlugin {
#[derive(Component, Debug, Clone, Reflect, PartialEq, Eq)]
#[reflect(Component, Debug, Default, PartialEq)]
pub enum CursorIcon {
#[cfg(feature = "custom_cursor")]
/// Custom cursor image.
Custom(CustomCursor),
/// System provided cursor icon.
Expand All @@ -57,12 +71,14 @@ impl From<SystemCursorIcon> for CursorIcon {
}
}

#[cfg(feature = "custom_cursor")]
impl From<CustomCursor> for CursorIcon {
fn from(cursor: CustomCursor) -> Self {
CursorIcon::Custom(cursor)
}
}

#[cfg(feature = "custom_cursor")]
/// Custom cursor image data.
#[derive(Debug, Clone, Reflect, PartialEq, Eq, Hash)]
pub enum CustomCursor {
Expand Down Expand Up @@ -90,8 +106,8 @@ pub enum CustomCursor {
fn update_cursors(
mut commands: Commands,
windows: Query<(Entity, Ref<CursorIcon>), With<Window>>,
cursor_cache: Res<CustomCursorCache>,
images: Res<Assets<Image>>,
#[cfg(feature = "custom_cursor")] cursor_cache: Res<CustomCursorCache>,
#[cfg(feature = "custom_cursor")] images: Res<Assets<Image>>,
mut queue: Local<HashSet<Entity>>,
) {
for (entity, cursor) in windows.iter() {
Expand All @@ -100,6 +116,7 @@ fn update_cursors(
}

let cursor_source = match cursor.as_ref() {
#[cfg(feature = "custom_cursor")]
CursorIcon::Custom(CustomCursor::Image { handle, hotspot }) => {
let cache_key = CustomCursorCacheKey::Asset(handle.id());

Expand Down Expand Up @@ -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>`.
/// Only supports rgba8 and rgba32float formats.
fn image_to_rgba_pixels(image: &Image) -> Option<Vec<u8>> {
Expand Down
2 changes: 0 additions & 2 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ use crate::{

pub mod accessibility;
mod converters;
#[cfg(feature = "custom_cursor")]
pub mod cursor;
mod state;
mod system;
Expand Down Expand Up @@ -136,7 +135,6 @@ impl<T: Event> Plugin for WinitPlugin<T> {
);

app.add_plugins(AccessKitPlugin);
#[cfg(feature = "custom_cursor")]
app.add_plugins(cursor::CursorPlugin);

let event_loop = event_loop_builder
Expand Down
20 changes: 16 additions & 4 deletions crates/bevy_winit/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,19 @@ pub enum CustomCursorCacheKey {
#[derive(Debug, Clone, Default, Resource)]
pub struct CustomCursorCache(pub HashMap<CustomCursorCacheKey, winit::window::CustomCursor>);

#[cfg(feature = "custom_cursor")]
/// A source for a cursor. Consumed by the winit event loop.
#[derive(Debug)]
pub enum CursorSource {
#[cfg(feature = "custom_cursor")]
/// A custom cursor was identified to be cached, no reason to recreate it.
CustomCached(CustomCursorCacheKey),
#[cfg(feature = "custom_cursor")]
/// A custom cursor was not cached, so it needs to be created by the winit event loop.
Custom((CustomCursorCacheKey, winit::window::CustomCursorSource)),
/// A system cursor was requested.
System(winit::window::CursorIcon),
}

#[cfg(feature = "custom_cursor")]
/// Component that indicates what cursor should be used for a window. Inserted
/// automatically after changing `CursorIcon` and consumed by the winit event
/// loop.
Expand Down Expand Up @@ -560,6 +560,8 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
self.run_app_update();
#[cfg(feature = "custom_cursor")]
self.update_cursors(event_loop);
#[cfg(not(feature = "custom_cursor"))]
self.update_cursors();
self.ran_update_since_last_redraw = true;
} else {
self.redraw_requested = true;
Expand Down Expand Up @@ -787,15 +789,23 @@ impl<T: Event> WinitAppRunnerState<T> {
.send_batch(buffered_events);
}

#[cfg(feature = "custom_cursor")]
fn update_cursors(&mut self, event_loop: &ActiveEventLoop) {
fn update_cursors(&mut self, #[cfg(feature = "custom_cursor")] event_loop: &ActiveEventLoop) {
#[cfg(feature = "custom_cursor")]
let mut windows_state: SystemState<(
NonSendMut<WinitWindows>,
ResMut<CustomCursorCache>,
Query<(Entity, &mut PendingCursor), Changed<PendingCursor>>,
)> = SystemState::new(self.world_mut());
#[cfg(feature = "custom_cursor")]
let (winit_windows, mut cursor_cache, mut windows) =
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() {
let Some(winit_window) = winit_windows.get_window(entity) else {
Expand All @@ -806,13 +816,15 @@ impl<T: Event> WinitAppRunnerState<T> {
};

let final_cursor: winit::window::Cursor = match pending_cursor {
#[cfg(feature = "custom_cursor")]
CursorSource::CustomCached(cache_key) => {
let Some(cached_cursor) = cursor_cache.0.get(&cache_key) else {
error!("Cursor should have been cached, but was not found");
continue;
};
cached_cursor.clone().into()
}
#[cfg(feature = "custom_cursor")]
CursorSource::Custom((cache_key, cursor)) => {
let custom_cursor = event_loop.create_custom_cursor(cursor);
cursor_cache.0.insert(cache_key, custom_cursor.clone());
Expand Down
10 changes: 8 additions & 2 deletions examples/window/window_settings.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//! Illustrates how to change window settings and shows how to affect
//! the mouse pointer in various ways.

#[cfg(feature = "custom_cursor")]
use bevy::winit::cursor::CustomCursor;
use bevy::{
core::FrameCount,
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
prelude::*,
window::{CursorGrabMode, PresentMode, SystemCursorIcon, WindowLevel, WindowTheme},
winit::cursor::{CursorIcon, CustomCursor},
winit::cursor::CursorIcon,
};

fn main() {
Expand Down Expand Up @@ -152,12 +154,16 @@ fn toggle_theme(mut window: Single<&mut Window>, input: Res<ButtonInput<KeyCode>
#[derive(Resource)]
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![
SystemCursorIcon::Default.into(),
SystemCursorIcon::Pointer.into(),
SystemCursorIcon::Wait.into(),
SystemCursorIcon::Text.into(),
#[cfg(feature = "custom_cursor")]
CustomCursor::Image {
handle: asset_server.load("branding/icon.png"),
hotspot: (128, 128),
Expand Down

0 comments on commit 5656166

Please sign in to comment.