From e8a853a64ba9bf6a424b59828419764edf97a63a Mon Sep 17 00:00:00 2001 From: Caleb Yates <105958073+ActuallyHappening@users.noreply.github.com> Date: Fri, 29 Nov 2024 21:32:58 +1000 Subject: [PATCH] Code quality improvements (#164) * fix: Implement reflect for FocusedWidget * refactor: using `bevy_math::Rect.contains` implementation to clean up code * fix: clippy is happy now * fix: fmt is happy now * add: Lots of Reflect impls and type registrations * refactor: moved certain type registrations into their own modules --- src/cosmic_edit.rs | 22 +++++++++++----------- src/cursor.rs | 30 ++++++++++++++++-------------- src/events.rs | 5 +++-- src/focus.rs | 6 ++++-- src/input.rs | 14 +++++++------- src/lib.rs | 15 +++++++++++++-- src/render.rs | 1 + src/util.rs | 29 ++++++++++++++++++----------- src/widget.rs | 8 +++++--- 9 files changed, 78 insertions(+), 52 deletions(-) diff --git a/src/cosmic_edit.rs b/src/cosmic_edit.rs index 953b28d..392bb8e 100644 --- a/src/cosmic_edit.rs +++ b/src/cosmic_edit.rs @@ -3,7 +3,7 @@ use bevy::prelude::*; use cosmic_text::{Attrs, AttrsOwned, Editor, FontSystem}; /// Enum representing text wrapping in a cosmic [`Buffer`] -#[derive(Clone, Component, PartialEq, Default)] +#[derive(Component, Reflect, Clone, PartialEq, Default)] pub enum CosmicWrap { InfiniteLine, #[default] @@ -11,7 +11,7 @@ pub enum CosmicWrap { } /// Enum representing the text alignment in a cosmic [`Buffer`] -#[derive(Clone, Component)] +#[derive(Component, Reflect, Clone)] pub enum CosmicTextAlign { Center { padding: i32 }, TopLeft { padding: i32 }, @@ -30,7 +30,7 @@ impl Default for CosmicTextAlign { pub struct ReadOnly; // tag component /// Internal value used to decide what section of a [`Buffer`] to render -#[derive(Component, Debug, Default)] +#[derive(Component, Reflect, Debug, Default)] pub struct XOffset { pub left: f32, pub width: f32, @@ -47,32 +47,32 @@ impl Default for DefaultAttrs { } /// Image to be used as a buffer's background -#[derive(Component, Default)] +#[derive(Component, Reflect, Default)] pub struct CosmicBackgroundImage(pub Option<Handle<Image>>); /// Color to be used as a buffer's background -#[derive(Component, Default, Deref)] +#[derive(Component, Reflect, Default, Deref)] pub struct CosmicBackgroundColor(pub Color); /// Color to be used for the text cursor -#[derive(Component, Default, Deref)] +#[derive(Component, Reflect, Default, Deref)] pub struct CursorColor(pub Color); /// Color to be used as the selected text background -#[derive(Component, Default, Deref)] +#[derive(Component, Reflect, Default, Deref)] pub struct SelectionColor(pub Color); /// Color to be used for the selected text -#[derive(Component, Default, Deref)] +#[derive(Component, Reflect, Default, Deref)] pub struct SelectedTextColor(pub Color); /// Maximum number of lines allowed in a buffer -#[derive(Component, Default)] +#[derive(Component, Reflect, Default)] pub struct MaxLines(pub usize); /// Maximum number of characters allowed in a buffer // TODO: Check this functionality with widechars; Use graphemes to test? -#[derive(Component, Default)] +#[derive(Component, Reflect, Default)] pub struct MaxChars(pub usize); /// Buffer does not respond to scroll events @@ -111,7 +111,7 @@ pub struct ScrollDisabled; /// # .add_plugins(CosmicEditPlugin::default()) /// # .add_systems(Startup, setup); /// # } -#[derive(Component)] +#[derive(Component, Reflect)] pub struct CosmicSource(pub Entity); /// A bundle containing all the required components for [`CosmicBuffer`] functionality. diff --git a/src/cursor.rs b/src/cursor.rs index 27354b7..ae3b250 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -23,11 +23,12 @@ impl Plugin for CursorPlugin { .run_if(not(resource_exists::<CursorPluginDisabled>)), ) .add_event::<TextHoverIn>() + .register_type::<TextHoverIn>() .add_event::<TextHoverOut>(); } } -#[derive(Component, Deref)] +#[derive(Component, Reflect, Deref)] pub struct HoverCursor(pub CursorIcon); impl Default for HoverCursor { @@ -39,12 +40,12 @@ impl Default for HoverCursor { /// 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)] +#[derive(Event, Reflect, Deref, Debug)] pub struct TextHoverIn(pub CursorIcon); /// For use with custom cursor control /// Event is emitted when cursor leaves a text widget -#[derive(Event)] +#[derive(Event, Debug)] pub struct TextHoverOut; pub(crate) fn change_cursor( @@ -109,17 +110,18 @@ pub(crate) fn hover_sprites( } let size = sprite.custom_size.unwrap_or(Vec2::ONE); - let x_min = node_transform.affine().translation.x - size.x / 2.; - let y_min = node_transform.affine().translation.y - size.y / 2.; - let x_max = node_transform.affine().translation.x + size.x / 2.; - let y_max = node_transform.affine().translation.y + size.y / 2.; - if let Some(pos) = window.cursor_position() { - 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; - } - } + if get_node_cursor_pos( + window, + node_transform, + size, + false, + camera, + camera_transform, + ) + .is_some() + { + *hovered = true; + icon = hover.0; } } diff --git a/src/events.rs b/src/events.rs index e9ecea5..1f542b3 100644 --- a/src/events.rs +++ b/src/events.rs @@ -7,12 +7,13 @@ pub(crate) struct EventsPlugin; impl Plugin for EventsPlugin { fn build(&self, app: &mut App) { - app.add_event::<CosmicTextChanged>(); + app.add_event::<CosmicTextChanged>() + .register_type::<CosmicTextChanged>(); } } /// Text change events /// Sent when text is changed in a cosmic buffer /// Contains the entity on which the text was changed, and the new text as a [`String`] -#[derive(Event, Debug)] +#[derive(Event, Reflect, Debug)] pub struct CosmicTextChanged(pub (Entity, String)); diff --git a/src/focus.rs b/src/focus.rs index 522b18e..88cf6e5 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -17,12 +17,14 @@ impl Plugin for FocusPlugin { .in_set(FocusSet) .after(WidgetSet), ) - .init_resource::<FocusedWidget>(); + .init_resource::<FocusedWidget>() + .register_type::<FocusedWidget>(); } } /// Resource struct that keeps track of the currently active editor entity. -#[derive(Resource, Default, Deref, DerefMut)] +#[derive(Resource, Reflect, Default, Deref, DerefMut)] +#[reflect(Resource)] pub struct FocusedWidget(pub Option<Entity>); pub(crate) fn add_editor_to_focused( diff --git a/src/input.rs b/src/input.rs index 0b1df13..931028b 100644 --- a/src/input.rs +++ b/src/input.rs @@ -125,8 +125,8 @@ pub(crate) fn input_mouse( let mut is_ui_node = false; let mut transform = sprite_transform; - let (mut width, mut height) = - (sprite.custom_size.unwrap().x, sprite.custom_size.unwrap().y); + let sprite_size = sprite.custom_size.expect("Must specify Sprite.custom_size"); + let (mut width, mut height) = (sprite_size.x, sprite_size.y); // TODO: this is bad loop nesting, rethink system with relationships in mind for (node, node_transform, source) in node_q.iter() { @@ -159,10 +159,10 @@ pub(crate) fn input_mouse( get_y_offset_center(height * scale_factor, &buffer), ), }; - let point = |node_cursor_pos: (f32, f32)| { + let point = |node_cursor_pos: Vec2| { ( - (node_cursor_pos.0 * scale_factor) as i32 - padding_x, - (node_cursor_pos.1 * scale_factor) as i32 - padding_y, + (node_cursor_pos.x * scale_factor) as i32 - padding_x, + (node_cursor_pos.y * scale_factor) as i32 - padding_y, ) }; @@ -173,7 +173,7 @@ pub(crate) fn input_mouse( if let Some(node_cursor_pos) = get_node_cursor_pos( primary_window, transform, - (width, height), + Vec2::new(width, height), is_ui_node, camera, camera_transform, @@ -213,7 +213,7 @@ pub(crate) fn input_mouse( if let Some(node_cursor_pos) = get_node_cursor_pos( primary_window, transform, - (width, height), + Vec2::new(width, height), is_ui_node, camera, camera_transform, diff --git a/src/lib.rs b/src/lib.rs index 18eeb5f..1568a32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,6 +138,18 @@ impl Plugin for CosmicEditPlugin { )) .insert_resource(CosmicFontSystem(font_system)); + app.register_type::<CosmicWrap>() + .register_type::<CosmicTextAlign>() + .register_type::<XOffset>() + .register_type::<CosmicBackgroundImage>() + .register_type::<CosmicBackgroundColor>() + .register_type::<CursorColor>() + .register_type::<SelectionColor>() + .register_type::<MaxLines>() + .register_type::<MaxChars>() + .register_type::<CosmicSource>() + .register_type::<HoverCursor>(); + #[cfg(target_arch = "wasm32")] { let (tx, rx) = crossbeam_channel::bounded::<WasmPaste>(1); @@ -148,7 +160,7 @@ impl Plugin for CosmicEditPlugin { } /// Attach to primary camera, and enable the `multicam` feature to use multiple cameras. -/// Will panic if no `Camera`s without this component exist and the `multicam` feature is enabled. +/// Will panic if no Camera's without this component exist and the `multicam` feature is enabled. /// /// A very basic example which doesn't panic: /// ```rust @@ -176,7 +188,6 @@ impl Plugin for CosmicEditPlugin { /// }); /// } /// ``` -#[cfg(feature = "multicam")] #[derive(Component, Debug, Default)] pub struct CosmicPrimaryCamera; diff --git a/src/render.rs b/src/render.rs index 4466a3c..0fa8a80 100644 --- a/src/render.rs +++ b/src/render.rs @@ -218,6 +218,7 @@ fn render_texture( if let Some(prev_image) = images.get_mut(canvas) { prev_image.data.clear(); + // Updates the stored asset image with the computed pixels prev_image.data.extend_from_slice(pixels.as_slice()); prev_image.resize(Extent3d { width: size.0.x as u32, diff --git a/src/util.rs b/src/util.rs index c4439f3..7c5233d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -36,22 +36,26 @@ pub fn deselect_editor_on_esc(i: Res<ButtonInput<KeyCode>>, mut focus: ResMut<Fo pub fn get_node_cursor_pos( window: &Window, node_transform: &GlobalTransform, - size: (f32, f32), + size: Vec2, is_ui_node: bool, camera: &Camera, camera_transform: &GlobalTransform, -) -> Option<(f32, f32)> { - let (x_min, y_min, x_max, y_max) = ( - node_transform.affine().translation.x - size.0 / 2., - node_transform.affine().translation.y - size.1 / 2., - node_transform.affine().translation.x + size.0 / 2., - node_transform.affine().translation.y + size.1 / 2., +) -> Option<Vec2> { + let node_translation = node_transform.affine().translation; + let node_bounds = Rect::new( + node_translation.x - size.x / 2., + node_translation.y - size.y / 2., + node_translation.x + size.x / 2., + node_translation.y + size.y / 2., ); window.cursor_position().and_then(|pos| { if is_ui_node { - if x_min < pos.x && pos.x < x_max && y_min < pos.y && pos.y < y_max { - Some((pos.x - x_min, pos.y - y_min)) + if node_bounds.contains(pos) { + Some(Vec2::new( + pos.x - node_bounds.min.x, + pos.y - node_bounds.min.y, + )) } else { None } @@ -59,8 +63,11 @@ pub fn get_node_cursor_pos( camera .viewport_to_world_2d(camera_transform, pos) .and_then(|pos| { - if x_min < pos.x && pos.x < x_max && y_min < pos.y && pos.y < y_max { - Some((pos.x - x_min, y_max - pos.y)) + if node_bounds.contains(pos) { + Some(Vec2::new( + pos.x - node_bounds.min.x, + node_bounds.max.y - pos.y, + )) } else { None } diff --git a/src/widget.rs b/src/widget.rs index 6e4b2f8..c6410af 100644 --- a/src/widget.rs +++ b/src/widget.rs @@ -24,21 +24,23 @@ impl Plugin for WidgetPlugin { .chain() .in_set(WidgetSet) .after(TransformSystem::TransformPropagate), - ); + ) + .register_type::<CosmicPadding>() + .register_type::<CosmicWidgetSize>(); } } /// Wrapper for a [`Vec2`] describing the horizontal and vertical padding of a widget. /// This is set programatically, not for user modification. /// To set a widget's padding, use [`CosmicTextAlign`] -#[derive(Component, Default, Deref, DerefMut, Debug)] +#[derive(Component, Reflect, Default, Deref, DerefMut, Debug)] pub struct CosmicPadding(pub Vec2); /// Wrapper for a [`Vec2`] describing the horizontal and vertical size of a widget. /// This is set programatically, not for user modification. /// To set a widget's size, use either it's [`Sprite`] dimensions or modify the target UI element's /// size. -#[derive(Component, Default, Deref, DerefMut)] +#[derive(Component, Reflect, Default, Deref, DerefMut)] pub struct CosmicWidgetSize(pub Vec2); /// Reshapes text in a [`CosmicEditor`] -- GitLab