Added set_cursor_icon(...) to Window (#3395)

# Objective

The window's cursor should be settable without having to implement a custom cursor icon solution. This will especially be helpful when creating user-interfaces that might like to use the cursor to denote some meaning (e.g., _clickable_, _resizable_, etc.).

## Solution

Added a `CursorIcon` enum that maps one-to-one to winit's `CursorIcon` enum, as well as a method to set/get it for the given `Window`.
This commit is contained in:
MrGVSV 2021-12-20 22:04:45 +00:00
parent 3443cc77cb
commit 5479047aa2
6 changed files with 132 additions and 2 deletions

View file

@ -0,0 +1,39 @@
/// The icon to display for a window's cursor
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum CursorIcon {
Default,
Crosshair,
Hand,
Arrow,
Move,
Text,
Wait,
Help,
Progress,
NotAllowed,
ContextMenu,
Cell,
VerticalText,
Alias,
Copy,
NoDrop,
Grab,
Grabbing,
AllScroll,
ZoomIn,
ZoomOut,
EResize,
NResize,
NeResize,
NwResize,
SResize,
SeResize,
SwResize,
WResize,
EwResize,
NsResize,
NeswResize,
NwseResize,
ColResize,
RowResize,
}

View file

@ -1,3 +1,4 @@
mod cursor;
mod event;
mod raw_window_handle;
mod system;
@ -5,6 +6,7 @@ mod window;
mod windows;
pub use crate::raw_window_handle::*;
pub use cursor::*;
pub use event::*;
pub use system::*;
pub use window::*;
@ -13,8 +15,8 @@ pub use windows::*;
pub mod prelude {
#[doc(hidden)]
pub use crate::{
CursorEntered, CursorLeft, CursorMoved, FileDragAndDrop, ReceivedCharacter, Window,
WindowDescriptor, WindowMoved, Windows,
CursorEntered, CursorIcon, CursorLeft, CursorMoved, FileDragAndDrop, ReceivedCharacter,
Window, WindowDescriptor, WindowMoved, Windows,
};
}

View file

@ -19,6 +19,7 @@ impl WindowId {
}
}
use crate::CursorIcon;
use std::fmt;
use crate::raw_window_handle::RawWindowHandleWrapper;
@ -123,6 +124,7 @@ pub struct Window {
vsync: bool,
resizable: bool,
decorations: bool,
cursor_icon: CursorIcon,
cursor_visible: bool,
cursor_locked: bool,
physical_cursor_position: Option<DVec2>,
@ -162,6 +164,9 @@ pub enum WindowCommand {
SetCursorLockMode {
locked: bool,
},
SetCursorIcon {
icon: CursorIcon,
},
SetCursorVisibility {
visible: bool,
},
@ -222,6 +227,7 @@ impl Window {
decorations: window_descriptor.decorations,
cursor_visible: window_descriptor.cursor_visible,
cursor_locked: window_descriptor.cursor_locked,
cursor_icon: CursorIcon::Default,
physical_cursor_position: None,
raw_window_handle: RawWindowHandleWrapper::new(raw_window_handle),
focused: true,
@ -474,6 +480,16 @@ impl Window {
});
}
#[inline]
pub fn cursor_icon(&self) -> CursorIcon {
self.cursor_icon
}
pub fn set_cursor_icon(&mut self, icon: CursorIcon) {
self.command_queue
.push(WindowCommand::SetCursorIcon { icon });
}
/// The current mouse position, in physical pixels.
#[inline]
pub fn physical_cursor_position(&self) -> Option<DVec2> {

View file

@ -5,6 +5,7 @@ use bevy_input::{
ElementState,
};
use bevy_math::Vec2;
use bevy_window::CursorIcon;
pub fn convert_keyboard_input(keyboard_input: &winit::event::KeyboardInput) -> KeyboardInput {
KeyboardInput {
@ -225,3 +226,43 @@ pub fn convert_virtual_key_code(virtual_key_code: winit::event::VirtualKeyCode)
winit::event::VirtualKeyCode::Cut => KeyCode::Cut,
}
}
pub fn convert_cursor_icon(cursor_icon: CursorIcon) -> winit::window::CursorIcon {
match cursor_icon {
CursorIcon::Default => winit::window::CursorIcon::Default,
CursorIcon::Crosshair => winit::window::CursorIcon::Crosshair,
CursorIcon::Hand => winit::window::CursorIcon::Hand,
CursorIcon::Arrow => winit::window::CursorIcon::Arrow,
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,
}
}

View file

@ -103,6 +103,10 @@ fn change_window(world: &mut World) {
let window = winit_windows.get_window(id).unwrap();
window.set_decorations(decorations);
}
bevy_window::WindowCommand::SetCursorIcon { icon } => {
let window = winit_windows.get_window(id).unwrap();
window.set_cursor_icon(converters::convert_cursor_icon(icon));
}
bevy_window::WindowCommand::SetCursorLockMode { locked } => {
let window = winit_windows.get_window(id).unwrap();
window

View file

@ -13,6 +13,7 @@ fn main() {
.add_plugins(DefaultPlugins)
.add_system(change_title)
.add_system(toggle_cursor)
.add_system(cycle_cursor_icon)
.run();
}
@ -33,3 +34,30 @@ fn toggle_cursor(input: Res<Input<KeyCode>>, mut windows: ResMut<Windows>) {
window.set_cursor_visibility(!window.cursor_visible());
}
}
/// This system cycles the cursor's icon through a small set of icons when clicking
fn cycle_cursor_icon(
input: Res<Input<MouseButton>>,
mut windows: ResMut<Windows>,
mut index: Local<usize>,
) {
const ICONS: &[CursorIcon] = &[
CursorIcon::Default,
CursorIcon::Hand,
CursorIcon::Wait,
CursorIcon::Text,
CursorIcon::Copy,
];
let window = windows.get_primary_mut().unwrap();
if input.just_pressed(MouseButton::Left) {
*index = (*index + 1) % ICONS.len();
window.set_cursor_icon(ICONS[*index]);
} else if input.just_pressed(MouseButton::Right) {
*index = if *index == 0 {
ICONS.len() - 1
} else {
*index - 1
};
window.set_cursor_icon(ICONS[*index]);
}
}