diff --git a/Cargo.lock b/Cargo.lock index e70356486b16ce06a2f46cda493253c2637b18fb..c282a360f85a35be7fb6aafb94a2d2c0b669e779 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -417,7 +417,6 @@ dependencies = [ "js-sys", "sys-locale", "unicode-segmentation", - "util", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -3182,14 +3181,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "util" -version = "0.1.0" -dependencies = [ - "bevy", - "bevy_cosmic_edit", -] - [[package]] name = "uuid" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 2c425e21aa9fe12f9ddf1d57732b6403f91dc97c..a3d03582168743a3f35581eba5d1d64a7e84bcb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,3 @@ -workspace = { members = ["util"] } [package] name = "bevy_cosmic_edit" version = "0.19.0" @@ -52,4 +51,3 @@ web-sys = { version = "0.3.67", features = [ [dev-dependencies] insta = "1.29.0" -util = { path = "./util/" } diff --git a/examples/basic_sprite.rs b/examples/basic_sprite.rs index 09073d0dd2ed969a571185079afa9414ad7c1b80..8f498f28ee11895d6a4940271bac95916b1652d2 100644 --- a/examples/basic_sprite.rs +++ b/examples/basic_sprite.rs @@ -1,6 +1,5 @@ use bevy::{prelude::*, window::PrimaryWindow}; use bevy_cosmic_edit::*; -use util::{change_active_editor_sprite, deselect_editor_on_esc, print_editor_text}; fn setup( mut commands: Commands, diff --git a/examples/basic_ui.rs b/examples/basic_ui.rs index 94eb841d7697f97b9589aa2f45bd7359f863794f..1c44bf012477487eac65e8d3cc0ed98fd1807244 100644 --- a/examples/basic_ui.rs +++ b/examples/basic_ui.rs @@ -1,6 +1,5 @@ use bevy::prelude::*; use bevy_cosmic_edit::*; -use util::{change_active_editor_ui, deselect_editor_on_esc, print_editor_text}; fn setup(mut commands: Commands, mut font_system: ResMut<CosmicFontSystem>) { let camera_bundle = Camera2dBundle { diff --git a/examples/every_option.rs b/examples/every_option.rs index b6e3ba90beb6c7e9ed13ca60c355aff9dde211ae..1e1d6aa4e1428ba2673cf560e7322cb6b12b0a23 100644 --- a/examples/every_option.rs +++ b/examples/every_option.rs @@ -1,6 +1,5 @@ use bevy::prelude::*; use bevy_cosmic_edit::*; -use util::{bevy_color_to_cosmic, change_active_editor_ui, deselect_editor_on_esc}; #[derive(Resource)] struct TextChangeTimer(pub Timer); diff --git a/examples/font_per_widget.rs b/examples/font_per_widget.rs index 17282745303a8cd5cc5de4f2249dae72f73ab705..a599c689134616c4a823ae38f127465e54af8639 100644 --- a/examples/font_per_widget.rs +++ b/examples/font_per_widget.rs @@ -2,7 +2,6 @@ use bevy::prelude::*; use bevy_cosmic_edit::*; -use util::{bevy_color_to_cosmic, change_active_editor_ui, deselect_editor_on_esc}; fn setup(mut commands: Commands, mut font_system: ResMut<CosmicFontSystem>) { commands.spawn(Camera2dBundle::default()); diff --git a/examples/image_background.rs b/examples/image_background.rs index 3d9b404260569b5f6c9194f76e8fc3d786a2b30f..48152788956371873d2c1501b42c343e26ce9259 100644 --- a/examples/image_background.rs +++ b/examples/image_background.rs @@ -1,6 +1,5 @@ use bevy::prelude::*; use bevy_cosmic_edit::*; -use util::{bevy_color_to_cosmic, change_active_editor_ui, deselect_editor_on_esc}; fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { commands.spawn(Camera2dBundle::default()); diff --git a/examples/multiple_sprites.rs b/examples/multiple_sprites.rs index e8623fcaf16552907c23699ac2a987aa010fd2c3..e5cdb5098ff9937382ec04625e808f01f10c0eb3 100644 --- a/examples/multiple_sprites.rs +++ b/examples/multiple_sprites.rs @@ -1,6 +1,5 @@ use bevy::{prelude::*, window::PrimaryWindow}; use bevy_cosmic_edit::*; -use util::{bevy_color_to_cosmic, change_active_editor_sprite}; fn setup( mut commands: Commands, diff --git a/examples/password.rs b/examples/password.rs index 0539f39557b5f438a56a570ade71930164928b4f..4314c464ae098b9d823f36738c6f139f95b5a2a8 100644 --- a/examples/password.rs +++ b/examples/password.rs @@ -1,6 +1,5 @@ use bevy::prelude::*; -use bevy_cosmic_edit::{password::Password, placeholder::Placeholder, *}; -use util::{change_active_editor_sprite, deselect_editor_on_esc, print_editor_text}; +use bevy_cosmic_edit::*; fn setup(mut commands: Commands) { commands.spawn(Camera2dBundle::default()); @@ -40,7 +39,7 @@ fn main() { ( change_active_editor_sprite, deselect_editor_on_esc, - print_editor_text.after(KbInput), + print_editor_text.after(InputSet), ), ) .run(); diff --git a/examples/placeholder.rs b/examples/placeholder.rs index 82d459515548428c7a89a781ad60f275a872f56b..64192ad6f92d693aaf3747d8856b9d1924a68816 100644 --- a/examples/placeholder.rs +++ b/examples/placeholder.rs @@ -1,8 +1,5 @@ use bevy::prelude::*; -use bevy_cosmic_edit::{placeholder::Placeholder, *}; -use util::{ - bevy_color_to_cosmic, change_active_editor_ui, deselect_editor_on_esc, print_editor_text, -}; +use bevy_cosmic_edit::*; fn setup(mut commands: Commands, mut font_system: ResMut<CosmicFontSystem>) { let camera_bundle = Camera2dBundle { diff --git a/examples/readonly.rs b/examples/readonly.rs index 0a76bd89f69ca32326a3256605b251a42ac6d92f..b339fa9c6b8bd76561a00d5803eca2587ce1472d 100644 --- a/examples/readonly.rs +++ b/examples/readonly.rs @@ -1,6 +1,5 @@ use bevy::prelude::*; use bevy_cosmic_edit::*; -use util::{bevy_color_to_cosmic, change_active_editor_ui}; fn setup(mut commands: Commands, mut font_system: ResMut<CosmicFontSystem>) { commands.spawn(Camera2dBundle::default()); diff --git a/examples/sprite_and_ui_clickable.rs b/examples/sprite_and_ui_clickable.rs index 0afb584c4e46d19013cf82c0fe977aeea85d1ed4..68d87e407c25fc7b6ec89f4d8ddd7ee5871da6be 100644 --- a/examples/sprite_and_ui_clickable.rs +++ b/examples/sprite_and_ui_clickable.rs @@ -1,9 +1,5 @@ use bevy::prelude::*; use bevy_cosmic_edit::*; -use util::{ - bevy_color_to_cosmic, change_active_editor_sprite, change_active_editor_ui, - deselect_editor_on_esc, -}; fn setup(mut commands: Commands) { commands.spawn(Camera2dBundle::default()); diff --git a/src/buffer.rs b/src/buffer.rs index 1244e35b633c7ac39d5acee4ab042c7f576e2d05..422c6050d047575da35068474728f86916350c7a 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -1,6 +1,27 @@ use crate::*; use bevy::{prelude::*, window::PrimaryWindow}; +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub struct BufferSet; + +pub struct BufferPlugin; + +impl Plugin for BufferPlugin { + fn build(&self, app: &mut App) { + app.add_systems( + First, + ( + add_font_system, + set_initial_scale, + set_redraw, + set_editor_redraw, + swap_target_handle, + ) + .chain(), + ); + } +} + pub trait BufferExtras { fn get_text(&self) -> String; } diff --git a/src/cosmic_edit.rs b/src/cosmic_edit.rs new file mode 100644 index 0000000000000000000000000000000000000000..ab13543341355ba1e778e7277f7509e68be6a6d1 --- /dev/null +++ b/src/cosmic_edit.rs @@ -0,0 +1,133 @@ +use crate::*; +use bevy::prelude::*; + +#[derive(Clone, Component, PartialEq, Default)] +pub enum CosmicMode { + InfiniteLine, + #[default] + Wrap, +} + +/// Enum representing the position of the cosmic text. +#[derive(Clone, Component)] +pub enum CosmicTextPosition { + Center { padding: i32 }, + TopLeft { padding: i32 }, + Left { padding: i32 }, +} + +impl Default for CosmicTextPosition { + fn default() -> Self { + CosmicTextPosition::Center { padding: 5 } + } +} + +#[derive(Component)] +pub struct ReadOnly; // tag component + +#[derive(Component, Debug, Default)] +pub struct XOffset { + pub left: f32, + pub width: f32, +} + +#[derive(Component, Deref, DerefMut)] +pub struct DefaultAttrs(pub AttrsOwned); + +impl Default for DefaultAttrs { + fn default() -> Self { + DefaultAttrs(AttrsOwned::new(Attrs::new())) + } +} + +#[derive(Component, Default)] +pub struct CosmicBackground(pub Option<Handle<Image>>); + +#[derive(Component, Default, Deref)] +pub struct FillColor(pub Color); + +#[derive(Component, Default, Deref)] +pub struct CursorColor(pub Color); + +#[derive(Component, Default, Deref)] +pub struct SelectionColor(pub Color); + +#[derive(Component, Default)] +pub struct CosmicMaxLines(pub usize); + +#[derive(Component, Default)] +pub struct CosmicMaxChars(pub usize); + +#[derive(Component)] +pub struct CosmicSource(pub Entity); + +#[derive(Bundle)] +pub struct CosmicEditBundle { + // cosmic bits + pub buffer: CosmicBuffer, + // render bits + pub fill_color: FillColor, + pub cursor_color: CursorColor, + pub selection_color: SelectionColor, + pub default_attrs: DefaultAttrs, + pub background_image: CosmicBackground, + pub sprite_bundle: SpriteBundle, + // restriction bits + pub max_lines: CosmicMaxLines, + pub max_chars: CosmicMaxChars, + // layout bits + pub x_offset: XOffset, + pub mode: CosmicMode, + pub text_position: CosmicTextPosition, + pub padding: CosmicPadding, + pub widget_size: CosmicWidgetSize, +} + +impl Default for CosmicEditBundle { + fn default() -> Self { + CosmicEditBundle { + buffer: Default::default(), + fill_color: Default::default(), + cursor_color: CursorColor(Color::BLACK), + selection_color: SelectionColor(Color::GRAY), + text_position: Default::default(), + default_attrs: Default::default(), + background_image: Default::default(), + max_lines: Default::default(), + max_chars: Default::default(), + mode: Default::default(), + sprite_bundle: SpriteBundle { + sprite: Sprite { + custom_size: Some(Vec2::ONE * 128.0), + ..default() + }, + visibility: Visibility::Hidden, + ..default() + }, + x_offset: Default::default(), + padding: Default::default(), + widget_size: Default::default(), + } + } +} + +#[derive(Resource, Deref, DerefMut)] +pub struct CosmicFontSystem(pub FontSystem); + +#[derive(Component, Deref, DerefMut)] +pub struct CosmicEditor { + #[deref] + pub editor: Editor<'static>, + pub cursor_visible: bool, + pub cursor_timer: Timer, +} + +impl CosmicEditor { + pub fn new(editor: Editor<'static>) -> Self { + Self { + editor, + cursor_visible: true, + cursor_timer: Timer::new(Duration::from_millis(530), TimerMode::Repeating), + } + } +} diff --git a/src/cursor.rs b/src/cursor.rs index a044bcfb7d63a78b2c415dbc684e19f0ab9f42ff..e14720948a932036f3b4c9a720b50386070e89e0 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -1,9 +1,30 @@ +use crate::*; use bevy::{input::mouse::MouseMotion, prelude::*, window::PrimaryWindow}; -use crate::{CosmicBuffer, CosmicSource, CosmicTextChanged}; +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub struct CursorSet; -#[cfg(feature = "multicam")] -use crate::CosmicPrimaryCamera; +pub struct CursorPlugin { + pub change_cursor: CursorConfig, +} + +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 => {} + } + } +} /// For use with custom cursor control; Event is emitted when cursor enters a text widget #[derive(Event)] diff --git a/src/events.rs b/src/events.rs new file mode 100644 index 0000000000000000000000000000000000000000..57aa2008ee256b13ccd5312dd1f337b206dfe296 --- /dev/null +++ b/src/events.rs @@ -0,0 +1,14 @@ +// File for all events, meant for easy documentation + +use bevy::prelude::*; + +pub struct EventsPlugin; + +impl Plugin for EventsPlugin { + fn build(&self, app: &mut App) { + app.add_event::<CosmicTextChanged>(); + } +} + +#[derive(Event, Debug)] +pub struct CosmicTextChanged(pub (Entity, String)); diff --git a/src/focus.rs b/src/focus.rs index 6520f0dd77491b2d01848d6c85b3869149067f99..4f8d5f85347070a6a49b352f7cb984d33c84eb1e 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -1,7 +1,23 @@ +use crate::*; use bevy::prelude::*; use cosmic_text::{Edit, Editor}; -use crate::{CosmicBuffer, CosmicEditor}; +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub struct FocusSet; + +pub struct FocusPlugin; + +impl Plugin for FocusPlugin { + fn build(&self, app: &mut App) { + app.add_systems( + PostUpdate, + (drop_editor_unfocused, add_editor_to_focused) + .chain() + .in_set(FocusSet), + ) + .init_resource::<FocusedWidget>(); + } +} /// Resource struct that keeps track of the currently active editor entity. #[derive(Resource, Default, Deref, DerefMut)] diff --git a/src/input.rs b/src/input.rs index be89f1fe277b9f8583e8b88bb60838d7a75c2d51..6e7ad8f7307c24b65190af510f2b97e74722be9a 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,8 +1,6 @@ #![allow(clippy::too_many_arguments, clippy::type_complexity)] -#[cfg(target_arch = "wasm32")] -use bevy::tasks::AsyncComputeTaskPool; - +use crate::*; use bevy::{ input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel}, prelude::*, @@ -13,18 +11,31 @@ use cosmic_text::{Action, Cursor, Edit, Motion, Selection}; #[cfg(target_arch = "wasm32")] use crate::DefaultAttrs; #[cfg(target_arch = "wasm32")] +use bevy::tasks::AsyncComputeTaskPool; +#[cfg(target_arch = "wasm32")] use js_sys::Promise; #[cfg(target_arch = "wasm32")] use wasm_bindgen::prelude::*; #[cfg(target_arch = "wasm32")] use wasm_bindgen_futures::JsFuture; -use crate::{ - buffer::{get_x_offset_center, get_y_offset_center, BufferExtras}, - get_node_cursor_pos, CosmicBuffer, CosmicEditor, CosmicFontSystem, CosmicMaxChars, - CosmicMaxLines, CosmicSource, CosmicTextChanged, CosmicTextPosition, FocusedWidget, ReadOnly, - XOffset, -}; +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub struct InputSet; + +pub struct InputPlugin; + +impl Plugin for InputPlugin { + fn build(&self, app: &mut App) { + app.add_systems(PreUpdate, input_mouse.in_set(InputSet)) + .add_systems( + Update, + (kb_move_cursor, kb_input_text, kb_clipboard) + .chain() + .in_set(InputSet), + ) + .insert_resource(ClickTimer(Timer::from_seconds(0.5, TimerMode::Once))); + } +} #[derive(Resource)] pub struct ClickTimer(pub Timer); diff --git a/src/lib.rs b/src/lib.rs index 1cc13e040cc458929113ac5fb4116b6ef813a7af..49348cea4d473c48be945fee1d42e6e88045c4cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,184 +1,82 @@ #![allow(clippy::type_complexity)] mod buffer; +mod cosmic_edit; mod cursor; -pub mod focus; +mod events; +mod focus; mod input; -mod layout; +mod password; +mod placeholder; mod render; - -mod plugins; -pub use plugins::*; +mod util; +mod widget; use std::{path::PathBuf, time::Duration}; use bevy::{prelude::*, transform::TransformSystem}; -use buffer::{ - add_font_system, set_editor_redraw, set_initial_scale, set_redraw, swap_target_handle, -}; -pub use buffer::{get_x_offset_center, get_y_offset_center, CosmicBuffer}; +pub use buffer::*; +pub use cosmic_edit::*; pub use cosmic_text::{ - Action, Attrs, AttrsOwned, Color as CosmicColor, Cursor, Edit, Family, Metrics, Shaping, - Style as FontStyle, Weight as FontWeight, + Action, Attrs, AttrsOwned, Buffer, Color as CosmicColor, Cursor, Edit, Editor, Family, + FontSystem, Metrics, Shaping, Style as FontStyle, Weight as FontWeight, }; -use cosmic_text::{Buffer, Editor, FontSystem, SwashCache}; -use cursor::{change_cursor, hover_sprites, hover_ui}; -pub use cursor::{TextHoverIn, TextHoverOut}; +pub use cursor::*; +pub use events::*; pub use focus::*; -use input::{input_mouse, kb_clipboard, kb_input_text, kb_move_cursor, ClickTimer}; -#[cfg(target_arch = "wasm32")] -use input::{poll_wasm_paste, WasmPaste, WasmPasteAsyncChannel}; -use layout::{ - new_image_from_default, reshape, set_buffer_size, set_padding, set_sprite_size_from_ui, - set_widget_size, set_x_offset, CosmicPadding, CosmicWidgetSize, -}; -use render::{blink_cursor, render_texture, SwashCacheState}; - -#[cfg(feature = "multicam")] -#[derive(Component)] -pub struct CosmicPrimaryCamera; - -#[derive(Clone, Component, PartialEq, Default)] -pub enum CosmicMode { - InfiniteLine, - #[default] - Wrap, -} +pub use input::*; +pub use password::*; +pub use placeholder::*; +pub use render::*; +pub use util::*; +pub use widget::*; +/// Plugin struct that adds systems and initializes resources related to cosmic edit functionality. #[derive(Default)] -pub enum CursorConfig { - #[default] - Default, - Events, - None, -} - -/// Enum representing the position of the cosmic text. -#[derive(Clone, Component)] -pub enum CosmicTextPosition { - Center { padding: i32 }, - TopLeft { padding: i32 }, - Left { padding: i32 }, -} - -impl Default for CosmicTextPosition { - fn default() -> Self { - CosmicTextPosition::Center { padding: 5 } - } +pub struct CosmicEditPlugin { + pub font_config: CosmicFontConfig, + pub change_cursor: CursorConfig, } -#[derive(Event, Debug)] -pub struct CosmicTextChanged(pub (Entity, String)); - -#[derive(Resource, Deref, DerefMut)] -pub struct CosmicFontSystem(pub FontSystem); - -#[derive(Component)] -pub struct ReadOnly; // tag component - -#[derive(Component, Debug, Default)] -pub struct XOffset { - pub left: f32, - pub width: f32, -} +impl Plugin for CosmicEditPlugin { + fn build(&self, app: &mut App) { + let font_system = create_cosmic_font_system(self.font_config.clone()); -#[derive(Component, Deref, DerefMut)] -pub struct CosmicEditor { - #[deref] - pub editor: Editor<'static>, - pub cursor_visible: bool, - pub cursor_timer: Timer, -} + app.add_plugins(( + BufferPlugin, + RenderPlugin, + WidgetPlugin, + InputPlugin, + FocusPlugin, + CursorPlugin { + change_cursor: self.change_cursor.clone(), + }, + PlaceholderPlugin, + PasswordPlugin, + EventsPlugin, + )) + .insert_resource(CosmicFontSystem(font_system)); -impl CosmicEditor { - fn new(editor: Editor<'static>) -> Self { - Self { - editor, - cursor_visible: true, - cursor_timer: Timer::new(Duration::from_millis(530), TimerMode::Repeating), + #[cfg(target_arch = "wasm32")] + { + let (tx, rx) = crossbeam_channel::bounded::<WasmPaste>(1); + app.insert_resource(WasmPasteAsyncChannel { tx, rx }) + .add_systems(Update, poll_wasm_paste); } } } -#[derive(Component, Deref, DerefMut)] -pub struct DefaultAttrs(pub AttrsOwned); - -impl Default for DefaultAttrs { - fn default() -> Self { - DefaultAttrs(AttrsOwned::new(Attrs::new())) - } -} - -#[derive(Component, Default)] -pub struct CosmicBackground(pub Option<Handle<Image>>); - -#[derive(Component, Default, Deref)] -pub struct FillColor(pub Color); - -#[derive(Component, Default, Deref)] -pub struct CursorColor(pub Color); - -#[derive(Component, Default, Deref)] -pub struct SelectionColor(pub Color); - -#[derive(Component, Default)] -pub struct CosmicMaxLines(pub usize); - -#[derive(Component, Default)] -pub struct CosmicMaxChars(pub usize); - +#[cfg(feature = "multicam")] #[derive(Component)] -pub struct CosmicSource(pub Entity); - -#[derive(Bundle)] -pub struct CosmicEditBundle { - // cosmic bits - pub buffer: CosmicBuffer, - // render bits - pub fill_color: FillColor, - pub cursor_color: CursorColor, - pub selection_color: SelectionColor, - pub default_attrs: DefaultAttrs, - pub background_image: CosmicBackground, - pub sprite_bundle: SpriteBundle, - // restriction bits - pub max_lines: CosmicMaxLines, - pub max_chars: CosmicMaxChars, - // layout bits - pub x_offset: XOffset, - pub mode: CosmicMode, - pub text_position: CosmicTextPosition, - pub padding: CosmicPadding, - pub widget_size: CosmicWidgetSize, -} +pub struct CosmicPrimaryCamera; -impl Default for CosmicEditBundle { - fn default() -> Self { - CosmicEditBundle { - buffer: Default::default(), - fill_color: Default::default(), - cursor_color: CursorColor(Color::BLACK), - selection_color: SelectionColor(Color::GRAY), - text_position: Default::default(), - default_attrs: Default::default(), - background_image: Default::default(), - max_lines: Default::default(), - max_chars: Default::default(), - mode: Default::default(), - sprite_bundle: SpriteBundle { - sprite: Sprite { - custom_size: Some(Vec2::ONE * 128.0), - ..default() - }, - visibility: Visibility::Hidden, - ..default() - }, - x_offset: Default::default(), - padding: Default::default(), - widget_size: Default::default(), - } - } +#[derive(Default, Clone)] +pub enum CursorConfig { + #[default] + Default, + Events, + None, } /// Resource struct that holds configuration options for cosmic fonts. @@ -200,105 +98,6 @@ impl Default for CosmicFontConfig { } } -#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] -pub struct KbInput; - -#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] -pub struct Render; - -/// Plugin struct that adds systems and initializes resources related to cosmic edit functionality. -#[derive(Default)] -pub struct CosmicEditPlugin { - pub font_config: CosmicFontConfig, - pub change_cursor: CursorConfig, -} - -impl Plugin for CosmicEditPlugin { - fn build(&self, app: &mut App) { - let font_system = create_cosmic_font_system(self.font_config.clone()); - - let layout_systems = ( - (new_image_from_default, set_sprite_size_from_ui), - set_widget_size, - set_buffer_size, - set_padding, - set_x_offset, - ) - .chain(); - - app.add_systems( - First, - ( - add_font_system, - set_initial_scale, - set_redraw, - set_editor_redraw, - swap_target_handle, - ) - .chain(), - ) - .add_systems(PreUpdate, (input_mouse,).chain()) - .add_systems( - Update, - ( - (kb_move_cursor, kb_input_text, kb_clipboard, reshape) - .chain() - .in_set(KbInput), - blink_cursor, - ), - ) - .add_systems( - PostUpdate, - ( - layout_systems, - drop_editor_unfocused, - add_editor_to_focused, - render_texture, - ) - .chain() - .in_set(Render) - .after(TransformSystem::TransformPropagate), - ) - .init_resource::<FocusedWidget>() - .insert_resource(SwashCacheState { - swash_cache: SwashCache::new(), - }) - .insert_resource(CosmicFontSystem(font_system)) - .insert_resource(ClickTimer(Timer::from_seconds(0.5, TimerMode::Once))) - .add_event::<CosmicTextChanged>(); - - 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 => {} - } - - #[cfg(target_arch = "wasm32")] - { - let (tx, rx) = crossbeam_channel::bounded::<WasmPaste>(1); - app.insert_resource(WasmPasteAsyncChannel { tx, rx }) - .add_systems(Update, poll_wasm_paste); - } - - add_feature_plugins(app); - } -} - -fn add_feature_plugins(app: &mut App) -> &mut App { - app.add_plugins(plugins::placeholder::PlaceholderPlugin); - app.add_plugins(plugins::password::PasswordPlugin); - - app -} - fn create_cosmic_font_system(cosmic_font_config: CosmicFontConfig) -> FontSystem { let locale = sys_locale::get_locale().unwrap_or_else(|| String::from("en-US")); let mut db = cosmic_text::fontdb::Database::new(); @@ -316,55 +115,6 @@ fn create_cosmic_font_system(cosmic_font_config: CosmicFontConfig) -> FontSystem cosmic_text::FontSystem::new_with_locale_and_db(locale, db) } -pub fn get_node_cursor_pos( - window: &Window, - node_transform: &GlobalTransform, - size: (f32, f32), - 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., - ); - - 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)) - } else { - None - } - } else { - 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)) - } else { - None - } - }) - } - }) -} - -#[cfg(target_arch = "wasm32")] -pub fn get_timestamp() -> f64 { - js_sys::Date::now() -} - -#[cfg(not(target_arch = "wasm32"))] -pub fn get_timestamp() -> f64 { - use std::time::SystemTime; - use std::time::UNIX_EPOCH; - let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); - duration.as_millis() as f64 -} - #[cfg(test)] mod tests { use crate::*; diff --git a/src/plugins/password/mod.rs b/src/password.rs similarity index 94% rename from src/plugins/password/mod.rs rename to src/password.rs index a36109c8e5bfc303172a59f6a326a95ce4863983..f84819e1504de9eba27eb24a7655cc978a59c124 100644 --- a/src/plugins/password/mod.rs +++ b/src/password.rs @@ -1,13 +1,8 @@ -use crate::{buffer::BufferExtras, placeholder::Placeholder}; +use crate::*; use bevy::prelude::*; use cosmic_text::{Cursor, Edit, Selection, Shaping}; use unicode_segmentation::UnicodeSegmentation; -use crate::{ - input::{input_mouse, kb_input_text, kb_move_cursor}, - CosmicBuffer, CosmicEditor, CosmicFontSystem, DefaultAttrs, Render, -}; - pub struct PasswordPlugin; #[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] @@ -25,8 +20,8 @@ impl Plugin for PasswordPlugin { .add_systems( PostUpdate, ( - hide_password_text.before(Render).in_set(PasswordSet), - restore_password_text.after(Render), + hide_password_text.before(RenderSet).in_set(PasswordSet), + restore_password_text.after(RenderSet), ), ); } diff --git a/src/plugins/placeholder/mod.rs b/src/placeholder.rs similarity index 96% rename from src/plugins/placeholder/mod.rs rename to src/placeholder.rs index a1807795af188ba9753dd358b753d691880e791c..d956760bb5ac783dd360b0fe899d804901dc7ad8 100644 --- a/src/plugins/placeholder/mod.rs +++ b/src/placeholder.rs @@ -1,11 +1,7 @@ -use crate::{buffer::BufferExtras, Render}; +use crate::*; use bevy::prelude::*; use cosmic_text::{Attrs, Edit}; -use crate::{ - CosmicBuffer, CosmicEditor, CosmicFontSystem, CosmicTextChanged, DefaultAttrs, KbInput, -}; - #[derive(Component)] pub struct Placeholder { pub text: &'static str, @@ -40,8 +36,8 @@ impl Plugin for PlaceholderPlugin { remove_placeholder_on_input, ) .chain() - .after(KbInput) - .before(Render), + .after(InputSet) + .before(RenderSet), ); } } diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs deleted file mode 100644 index 08a7f609753d4e9fc21c3d47d18b1c76649df80d..0000000000000000000000000000000000000000 --- a/src/plugins/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod password; -pub mod placeholder; diff --git a/src/render.rs b/src/render.rs index 78e376ed4d9c069ce0bbc773944d780dd49b0bfc..ef9d04d729f65caa90e34c754ae3a8637358200f 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,12 +1,25 @@ +use crate::*; use bevy::{prelude::*, render::render_resource::Extent3d}; use cosmic_text::{Color, Edit, SwashCache}; use image::{imageops::FilterType, GenericImageView}; -use crate::{ - layout::{CosmicPadding, CosmicWidgetSize}, - CosmicBackground, CosmicBuffer, CosmicEditor, CosmicFontSystem, CosmicTextPosition, - CursorColor, DefaultAttrs, FillColor, ReadOnly, SelectionColor, XOffset, -}; +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub struct RenderSet; + +pub struct RenderPlugin; + +impl Plugin for RenderPlugin { + fn build(&self, app: &mut App) { + app.insert_resource(SwashCacheState { + swash_cache: SwashCache::new(), + }) + .add_systems(Update, blink_cursor) + .add_systems( + PostUpdate, + (render_texture,).in_set(RenderSet).after(WidgetSet), + ); + } +} #[derive(Resource)] pub(crate) struct SwashCacheState { @@ -63,7 +76,7 @@ fn draw_pixel(buffer: &mut [u8], width: i32, height: i32, x: i32, y: i32, color: buffer[offset + 3] = (out.a() * 255.0) as u8; } -pub(crate) fn render_texture( +fn render_texture( mut query: Query<( Option<&mut CosmicEditor>, &mut CosmicBuffer, diff --git a/util/src/lib.rs b/src/util.rs similarity index 65% rename from util/src/lib.rs rename to src/util.rs index 405152cd2ac7aaa293d14eb85d459cc88788238a..6175e52a7b5cdf74b3bce6e5af9454af830bbde6 100644 --- a/util/src/lib.rs +++ b/src/util.rs @@ -1,6 +1,6 @@ // Common functions for examples +use crate::*; use bevy::{prelude::*, window::PrimaryWindow}; -use bevy_cosmic_edit::*; pub fn deselect_editor_on_esc(i: Res<ButtonInput<KeyCode>>, mut focus: ResMut<FocusedWidget>) { if i.just_pressed(KeyCode::Escape) { @@ -8,6 +8,42 @@ 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), + 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., + ); + + 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)) + } else { + None + } + } else { + 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)) + } else { + None + } + }) + } + }) +} + pub fn change_active_editor_sprite( mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>, @@ -82,3 +118,16 @@ pub fn bevy_color_to_cosmic(color: bevy::prelude::Color) -> CosmicColor { (color.a() * 255.) as u8, ) } + +#[cfg(target_arch = "wasm32")] +pub fn get_timestamp() -> f64 { + js_sys::Date::now() +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn get_timestamp() -> f64 { + use std::time::SystemTime; + use std::time::UNIX_EPOCH; + let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + duration.as_millis() as f64 +} diff --git a/src/layout.rs b/src/widget.rs similarity index 88% rename from src/layout.rs rename to src/widget.rs index f5d0bce834a9809cf2fbd15f35922136e5655fd3..e79ac22f3ff7a01b9bc923592dfcf25899b1b400 100644 --- a/src/layout.rs +++ b/src/widget.rs @@ -2,7 +2,29 @@ use crate::*; use bevy::{prelude::*, window::PrimaryWindow}; use cosmic_text::Affinity; -use self::buffer::{get_x_offset_center, get_y_offset_center}; +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub struct WidgetSet; + +pub struct WidgetPlugin; + +impl Plugin for WidgetPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Update, reshape.in_set(WidgetSet).after(InputSet)) + .add_systems( + PostUpdate, + ( + (new_image_from_default, set_sprite_size_from_ui), + set_widget_size, + set_buffer_size, + set_padding, + set_x_offset, + ) + .chain() + .in_set(WidgetSet) + .after(TransformSystem::TransformPropagate), + ); + } +} #[derive(Component, Default, Deref, DerefMut, Debug)] pub struct CosmicPadding(pub Vec2); diff --git a/util/Cargo.toml b/util/Cargo.toml deleted file mode 100644 index 51de83365dfe6af657fa3258f3c808e5a1af1b7c..0000000000000000000000000000000000000000 --- a/util/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "util" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -bevy = { version = "0.13", default-features = false, features = [ - "bevy_asset", - "bevy_core_pipeline", - "bevy_render", - "bevy_scene", - "bevy_sprite", - "bevy_text", - "bevy_ui", - "bevy_winit", - "png", - "x11", - "webgpu", -] } -bevy_cosmic_edit = { version = "*", path = "../" }