From ef84f0edec47b6325d0bfbcf97fbb571ef99e805 Mon Sep 17 00:00:00 2001 From: sam edelsten <samedelsten1@gmail.com> Date: Tue, 30 Apr 2024 19:34:41 +0100 Subject: [PATCH] per-widget mouse cursor control --- examples/every_option.rs | 1 + src/cosmic_edit.rs | 2 + src/cursor.rs | 81 +++++++++++++++++++++++----------------- src/lib.rs | 4 +- 4 files changed, 51 insertions(+), 37 deletions(-) diff --git a/examples/every_option.rs b/examples/every_option.rs index 1e1d6aa..5b546f7 100644 --- a/examples/every_option.rs +++ b/examples/every_option.rs @@ -42,6 +42,7 @@ fn setup(mut commands: Commands, mut font_system: ResMut<CosmicFontSystem>) { // Computed fields padding: Default::default(), widget_size: Default::default(), + hover_cursor: Default::default(), }) .id(); diff --git a/src/cosmic_edit.rs b/src/cosmic_edit.rs index ab13543..48a209a 100644 --- a/src/cosmic_edit.rs +++ b/src/cosmic_edit.rs @@ -81,6 +81,7 @@ pub struct CosmicEditBundle { pub text_position: CosmicTextPosition, pub padding: CosmicPadding, pub widget_size: CosmicWidgetSize, + pub hover_cursor: HoverCursor, } impl Default for CosmicEditBundle { @@ -107,6 +108,7 @@ impl Default for CosmicEditBundle { x_offset: Default::default(), padding: Default::default(), widget_size: Default::default(), + hover_cursor: Default::default(), } } } diff --git a/src/cursor.rs b/src/cursor.rs index e147209..a27d637 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -1,41 +1,42 @@ use crate::*; use bevy::{input::mouse::MouseMotion, prelude::*, window::PrimaryWindow}; +/// System set for mouse cursor systems. Runs in [`Update`] #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] pub struct CursorSet; -pub struct CursorPlugin { - pub change_cursor: CursorConfig, -} +pub struct CursorPlugin; impl Plugin for CursorPlugin { fn build(&self, app: &mut App) { - match self.change_cursor { - CursorConfig::Default => { - app.add_systems(Update, (hover_sprites, hover_ui, change_cursor)) - .add_event::<TextHoverIn>() - .add_event::<TextHoverOut>(); - } - CursorConfig::Events => { - app.add_systems(Update, (hover_sprites, hover_ui)) - .add_event::<TextHoverIn>() - .add_event::<TextHoverOut>(); - } - CursorConfig::None => {} - } + app.add_systems(Update, ((hover_sprites, hover_ui), change_cursor).chain()) + .add_event::<TextHoverIn>() + .add_event::<TextHoverOut>(); } } -/// For use with custom cursor control; Event is emitted when cursor enters a text widget -#[derive(Event)] -pub struct TextHoverIn; +#[derive(Component, Deref)] +pub struct HoverCursor(pub CursorIcon); + +impl Default for HoverCursor { + fn default() -> Self { + Self(CursorIcon::Text) + } +} -/// For use with custom cursor control; Event is emitted when cursor leaves a text widget +/// For use with custom cursor control +/// Event is emitted when cursor enters a text widget +/// Event contains the cursor from the buffer's [`HoverCursor`] +#[derive(Event, Deref)] +pub struct TextHoverIn(pub CursorIcon); + +/// For use with custom cursor control +/// Event is emitted when cursor leaves a text widget #[derive(Event)] pub struct TextHoverOut; -pub fn change_cursor( - evr_hover_in: EventReader<TextHoverIn>, +pub(crate) fn change_cursor( + mut evr_hover_in: EventReader<TextHoverIn>, evr_hover_out: EventReader<TextHoverOut>, evr_text_changed: EventReader<CosmicTextChanged>, evr_mouse_motion: EventReader<MouseMotion>, @@ -46,15 +47,17 @@ pub fn change_cursor( return; } let mut window = windows.single_mut(); - if !evr_hover_in.is_empty() { - window.cursor.icon = CursorIcon::Text; - } - if !evr_hover_out.is_empty() { + + if let Some(ev) = evr_hover_in.read().last() { + window.cursor.icon = ev.0; + } else if !evr_hover_out.is_empty() { window.cursor.icon = CursorIcon::Default; } + if !evr_text_changed.is_empty() { window.cursor.visible = false; } + if mouse_buttons.get_just_pressed().len() != 0 || !evr_mouse_motion.is_empty() { window.cursor.visible = true; } @@ -67,9 +70,12 @@ type CameraQuery<'a, 'b, 'c, 'd> = #[cfg(not(feature = "multicam"))] type CameraQuery<'a, 'b, 'c, 'd> = Query<'a, 'b, (&'c Camera, &'d GlobalTransform)>; -pub fn hover_sprites( +pub(crate) fn hover_sprites( windows: Query<&Window, With<PrimaryWindow>>, - mut cosmic_edit_query: Query<(&mut Sprite, &Visibility, &GlobalTransform), With<CosmicBuffer>>, + mut cosmic_edit_query: Query< + (&mut Sprite, &Visibility, &GlobalTransform, &HoverCursor), + With<CosmicBuffer>, + >, camera_q: CameraQuery, mut hovered: Local<bool>, mut last_hovered: Local<bool>, @@ -82,7 +88,10 @@ pub fn hover_sprites( } let window = windows.single(); let (camera, camera_transform) = camera_q.single(); - for (sprite, visibility, node_transform) in &mut cosmic_edit_query.iter_mut() { + + let mut icon = CursorIcon::Default; + + for (sprite, visibility, node_transform, hover) in &mut cosmic_edit_query.iter_mut() { if visibility == Visibility::Hidden { continue; } @@ -96,6 +105,7 @@ pub fn hover_sprites( if let Some(pos) = camera.viewport_to_world_2d(camera_transform, pos) { if x_min < pos.x && pos.x < x_max && y_min < pos.y && pos.y < y_max { *hovered = true; + icon = hover.0; } } } @@ -103,7 +113,7 @@ pub fn hover_sprites( if *last_hovered != *hovered { if *hovered { - evw_hover_in.send(TextHoverIn); + evw_hover_in.send(TextHoverIn(icon)); } else { evw_hover_out.send(TextHoverOut); } @@ -112,18 +122,21 @@ pub fn hover_sprites( *last_hovered = *hovered; } -pub fn hover_ui( - mut interaction_query: Query<&Interaction, (Changed<Interaction>, With<CosmicSource>)>, +pub(crate) fn hover_ui( + interaction_query: Query<(&Interaction, &CosmicSource), Changed<Interaction>>, + cosmic_query: Query<&HoverCursor, With<CosmicBuffer>>, mut evw_hover_in: EventWriter<TextHoverIn>, mut evw_hover_out: EventWriter<TextHoverOut>, ) { - for interaction in interaction_query.iter_mut() { + for (interaction, source) in interaction_query.iter() { match interaction { Interaction::None => { evw_hover_out.send(TextHoverOut); } Interaction::Hovered => { - evw_hover_in.send(TextHoverIn); + if let Ok(hover) = cosmic_query.get(source.0) { + evw_hover_in.send(TextHoverIn(hover.0)); + } } _ => {} } diff --git a/src/lib.rs b/src/lib.rs index 49348ce..337d4dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,9 +49,7 @@ impl Plugin for CosmicEditPlugin { WidgetPlugin, InputPlugin, FocusPlugin, - CursorPlugin { - change_cursor: self.change_cursor.clone(), - }, + CursorPlugin, PlaceholderPlugin, PasswordPlugin, EventsPlugin, -- GitLab