Skip to content

Commit

Permalink
some custom cursors stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
amytimed committed Jul 6, 2024
1 parent 3452781 commit 1f3a21a
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 45 deletions.
60 changes: 56 additions & 4 deletions crates/bevy_window/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,73 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};

/// The icon to display for a [`Window`](crate::window::Window)'s [`Cursor`](crate::window::Cursor).
///
/// Examples of all of these cursors can be found [here](https://www.w3schools.com/cssref/playit.php?filename=playcss_cursor&preval=crosshair).
/// This `enum` is simply a copy of a similar `enum` found in [`winit`](https://docs.rs/winit/latest/winit/window/enum.CursorIcon.html).
/// `winit`, in turn, is based upon the [CSS3 UI spec](https://www.w3.org/TR/css-ui-3/#cursor).
/// Bevy supports two types of cursors, system cursors and custom ones.
///
/// See the [`window_settings`] example for usage.
///
/// [`window_settings`]: https://github.com/bevyengine/bevy/blob/latest/examples/window/window_settings.rs
#[derive(Default, Debug, Hash, PartialEq, Eq, Clone, Copy, Reflect)]
#[derive(Debug, Hash, PartialEq, Eq, Clone, Reflect)]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize)
)]
#[reflect(Debug, PartialEq, Default)]
pub enum CursorIcon {
/// Represents a system cursor.
System(SystemCursor),
/// Represents a custom cursor image.
Custom(CustomCursor),
}

impl Default for CursorIcon {
fn default() -> Self {
Self::System(SystemCursor::default())
}
}

impl From<SystemCursor> for CursorIcon {
fn from(system: SystemCursor) -> Self {
Self::System(system)
}
}

impl From<CustomCursor> for CursorIcon {
fn from(custom: CustomCursor) -> Self {
Self::Custom(custom)
}
}

/// Represents a custom cursor image.
///
/// This `struct` matches the arguments to [`winit`'s `CustomCursor::from_rgba`](https://docs.rs/winit/latest/winit/window/struct.CustomCursor.html#method.from_rgba).
///
/// See the [`window_settings`] example for usage.
///
/// [`window_settings`]: https://github.com/bevyengine/bevy/blob/latest/examples/window/window_settings.rs
#[derive(Debug, Hash, PartialEq, Eq, Clone, Reflect)]
pub struct CustomCursor {
/// RGBA values for custom cursor
pub rgba: Vec<u8>,
/// Width of the cursor image
pub width: u16,
/// Height of the cursor image
pub height: u16,
/// The hotspot of the cursor is where the user is pointing, relative to the top-left of the cursor
pub hotspot: (u16, u16),
}

/// Represents a system cursor.
///
/// Examples of all of these cursors can be found [here](https://www.w3schools.com/cssref/playit.php?filename=playcss_cursor&preval=crosshair).
/// This `enum` is simply a copy of a similar `enum` found in [`winit`](https://docs.rs/winit/latest/winit/window/enum.CursorIcon.html).
/// `winit`, in turn, is based upon the [CSS3 UI spec](https://www.w3.org/TR/css-ui-3/#cursor).
///
/// See the [`window_settings`] example for usage.
///
/// [`window_settings`]: https://github.com/bevyengine/bevy/blob/latest/examples/window/window_settings.rs
#[derive(Default, Debug, Hash, PartialEq, Eq, Clone, Copy, Reflect)]
pub enum SystemCursor {
/// The platform-dependent default cursor. Often rendered as arrow.
#[default]
Default,
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_window/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ impl WindowResizeConstraints {
}

/// Cursor data for a [`Window`].
#[derive(Debug, Copy, Clone, Reflect)]
#[derive(Debug, Clone, Reflect)]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
Expand Down Expand Up @@ -585,7 +585,7 @@ pub struct Cursor {
impl Default for Cursor {
fn default() -> Self {
Cursor {
icon: CursorIcon::Default,
icon: crate::SystemCursor::Default.into(),
visible: true,
grab_mode: CursorGrabMode::None,
hit_test: true,
Expand Down
93 changes: 55 additions & 38 deletions crates/bevy_winit/src/converters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use bevy_input::{
ButtonState,
};
use bevy_math::Vec2;
use bevy_window::{CursorIcon, EnabledButtons, WindowLevel, WindowTheme};
use bevy_window::{CursorIcon, EnabledButtons, SystemCursor, WindowLevel, WindowTheme};
use winit::keyboard::{Key, NamedKey, NativeKey};

pub fn convert_keyboard_input(
Expand Down Expand Up @@ -627,43 +627,60 @@ pub fn convert_native_key(native_key: &NativeKey) -> bevy_input::keyboard::Nativ
}
}

pub fn convert_cursor_icon(cursor_icon: CursorIcon) -> winit::window::CursorIcon {
match cursor_icon {
CursorIcon::Crosshair => winit::window::CursorIcon::Crosshair,
CursorIcon::Pointer => winit::window::CursorIcon::Pointer,
CursorIcon::Move => winit::window::CursorIcon::Move,
CursorIcon::Text => winit::window::CursorIcon::Text,
CursorIcon::Wait => winit::window::CursorIcon::Wait,
CursorIcon::Help => winit::window::CursorIcon::Help,
CursorIcon::Progress => winit::window::CursorIcon::Progress,
CursorIcon::NotAllowed => winit::window::CursorIcon::NotAllowed,
CursorIcon::ContextMenu => winit::window::CursorIcon::ContextMenu,
CursorIcon::Cell => winit::window::CursorIcon::Cell,
CursorIcon::VerticalText => winit::window::CursorIcon::VerticalText,
CursorIcon::Alias => winit::window::CursorIcon::Alias,
CursorIcon::Copy => winit::window::CursorIcon::Copy,
CursorIcon::NoDrop => winit::window::CursorIcon::NoDrop,
CursorIcon::Grab => winit::window::CursorIcon::Grab,
CursorIcon::Grabbing => winit::window::CursorIcon::Grabbing,
CursorIcon::AllScroll => winit::window::CursorIcon::AllScroll,
CursorIcon::ZoomIn => winit::window::CursorIcon::ZoomIn,
CursorIcon::ZoomOut => winit::window::CursorIcon::ZoomOut,
CursorIcon::EResize => winit::window::CursorIcon::EResize,
CursorIcon::NResize => winit::window::CursorIcon::NResize,
CursorIcon::NeResize => winit::window::CursorIcon::NeResize,
CursorIcon::NwResize => winit::window::CursorIcon::NwResize,
CursorIcon::SResize => winit::window::CursorIcon::SResize,
CursorIcon::SeResize => winit::window::CursorIcon::SeResize,
CursorIcon::SwResize => winit::window::CursorIcon::SwResize,
CursorIcon::WResize => winit::window::CursorIcon::WResize,
CursorIcon::EwResize => winit::window::CursorIcon::EwResize,
CursorIcon::NsResize => winit::window::CursorIcon::NsResize,
CursorIcon::NeswResize => winit::window::CursorIcon::NeswResize,
CursorIcon::NwseResize => winit::window::CursorIcon::NwseResize,
CursorIcon::ColResize => winit::window::CursorIcon::ColResize,
CursorIcon::RowResize => winit::window::CursorIcon::RowResize,
_ => winit::window::CursorIcon::Default,
}
pub fn convert_cursor_icon(
cursor_icon: CursorIcon,
event_loop: &winit::event_loop::ActiveEventLoop,
) -> impl Into<winit::window::Cursor> {
let cursor: winit::window::Cursor = match cursor_icon {
CursorIcon::System(system) => match system {
SystemCursor::Crosshair => winit::window::CursorIcon::Crosshair.into(),
SystemCursor::Pointer => winit::window::CursorIcon::Pointer.into(),
SystemCursor::Move => winit::window::CursorIcon::Move.into(),
SystemCursor::Text => winit::window::CursorIcon::Text.into(),
SystemCursor::Wait => winit::window::CursorIcon::Wait.into(),
SystemCursor::Help => winit::window::CursorIcon::Help.into(),
SystemCursor::Progress => winit::window::CursorIcon::Progress.into(),
SystemCursor::NotAllowed => winit::window::CursorIcon::NotAllowed.into(),
SystemCursor::ContextMenu => winit::window::CursorIcon::ContextMenu.into(),
SystemCursor::Cell => winit::window::CursorIcon::Cell.into(),
SystemCursor::VerticalText => winit::window::CursorIcon::VerticalText.into(),
SystemCursor::Alias => winit::window::CursorIcon::Alias.into(),
SystemCursor::Copy => winit::window::CursorIcon::Copy.into(),
SystemCursor::NoDrop => winit::window::CursorIcon::NoDrop.into(),
SystemCursor::Grab => winit::window::CursorIcon::Grab.into(),
SystemCursor::Grabbing => winit::window::CursorIcon::Grabbing.into(),
SystemCursor::AllScroll => winit::window::CursorIcon::AllScroll.into(),
SystemCursor::ZoomIn => winit::window::CursorIcon::ZoomIn.into(),
SystemCursor::ZoomOut => winit::window::CursorIcon::ZoomOut.into(),
SystemCursor::EResize => winit::window::CursorIcon::EResize.into(),
SystemCursor::NResize => winit::window::CursorIcon::NResize.into(),
SystemCursor::NeResize => winit::window::CursorIcon::NeResize.into(),
SystemCursor::NwResize => winit::window::CursorIcon::NwResize.into(),
SystemCursor::SResize => winit::window::CursorIcon::SResize.into(),
SystemCursor::SeResize => winit::window::CursorIcon::SeResize.into(),
SystemCursor::SwResize => winit::window::CursorIcon::SwResize.into(),
SystemCursor::WResize => winit::window::CursorIcon::WResize.into(),
SystemCursor::EwResize => winit::window::CursorIcon::EwResize.into(),
SystemCursor::NsResize => winit::window::CursorIcon::NsResize.into(),
SystemCursor::NeswResize => winit::window::CursorIcon::NeswResize.into(),
SystemCursor::NwseResize => winit::window::CursorIcon::NwseResize.into(),
SystemCursor::ColResize => winit::window::CursorIcon::ColResize.into(),
SystemCursor::RowResize => winit::window::CursorIcon::RowResize.into(),
_ => winit::window::CursorIcon::Default.into(),
},
CursorIcon::Custom(custom) => {
let source = winit::window::CustomCursor::from_rgba(
custom.rgba,
custom.width,
custom.height,
custom.hotspot.0,
custom.hotspot.1,
);
let custom_cursor = event_loop.create_custom_cursor(source.unwrap());
custom_cursor.into()
}
};
cursor
}

pub fn convert_window_level(window_level: WindowLevel) -> winit::window::WindowLevel {
Expand Down
5 changes: 4 additions & 1 deletion crates/bevy_winit/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,10 @@ pub(crate) fn changed_windows(
}

if window.cursor.icon != cache.window.cursor.icon {
winit_window.set_cursor(converters::convert_cursor_icon(window.cursor.icon));
winit_window.set_cursor(converters::convert_cursor_icon(
window.cursor.icon.clone(),
event_loop,
));
}

if window.cursor.grab_mode != cache.window.cursor.grab_mode {
Expand Down

0 comments on commit 1f3a21a

Please sign in to comment.