From 748b8ea1c9dd9e746e7128cefe0831f6be45ec0a Mon Sep 17 00:00:00 2001 From: sam edelsten <samedelsten1@gmail.com> Date: Tue, 24 Oct 2023 20:47:41 +0100 Subject: [PATCH] use bevy builtins; single canvas image adds a `CosmicCanvas` component to hold the image cosmic draws to. allows easier interop between UI and Sprite widgets Each type of widget now uses a single `CosmicEditBundle`, adding widget specific components with `.insert()` or as tuples. --- examples/basic_sprite.rs | 33 ++++--- examples/basic_ui.rs | 39 +++++--- examples/bevy_api_testing.rs | 60 +++++++----- examples/every_option.rs | 53 ++++++----- examples/font_per_widget.rs | 72 +++++++++------ examples/image_background.rs | 27 ++++-- examples/multiple_sprites.rs | 74 ++++++++------- examples/readonly.rs | 36 +++++--- examples/text_input.rs | 84 ++++++++++------- src/lib.rs | 172 ++++++++--------------------------- src/render.rs | 116 ++++++++++++----------- 11 files changed, 382 insertions(+), 384 deletions(-) diff --git a/examples/basic_sprite.rs b/examples/basic_sprite.rs index e01b445..29b8b93 100644 --- a/examples/basic_sprite.rs +++ b/examples/basic_sprite.rs @@ -1,7 +1,7 @@ use bevy::{core_pipeline::clear_color::ClearColorConfig, prelude::*, window::PrimaryWindow}; use bevy_cosmic_edit::{ - AttrsOwned, CosmicAttrs, CosmicEditPlugin, CosmicEditSpriteBundle, CosmicFontConfig, - CosmicMetrics, CosmicText, CosmicTextPosition, Focus, + AttrsOwned, CosmicAttrs, CosmicEditBundle, CosmicEditPlugin, CosmicFontConfig, CosmicMetrics, + CosmicText, CosmicTextPosition, Focus, }; fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { @@ -20,21 +20,26 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { let scale_factor = primary_window.scale_factor() as f32; - let cosmic_edit = CosmicEditSpriteBundle { - sprite: Sprite { - custom_size: Some(Vec2::new(primary_window.width(), primary_window.height())), + let cosmic_edit = ( + CosmicEditBundle { + metrics: CosmicMetrics { + font_size: 14., + line_height: 18., + scale_factor, + }, + text_position: CosmicTextPosition::Center, + attrs: CosmicAttrs(AttrsOwned::new(attrs)), + text_setter: CosmicText::OneStyle("😀😀😀 x => y".to_string()), ..default() }, - cosmic_metrics: CosmicMetrics { - font_size: 14., - line_height: 18., - scale_factor, + SpriteBundle { + sprite: Sprite { + custom_size: Some(Vec2::new(primary_window.width(), primary_window.height())), + ..default() + }, + ..default() }, - text_position: CosmicTextPosition::Center, - cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)), - text_setter: CosmicText::OneStyle("😀😀😀 x => y".to_string()), - ..default() - }; + ); let cosmic_edit = commands.spawn(cosmic_edit).id(); diff --git a/examples/basic_ui.rs b/examples/basic_ui.rs index f02ab72..6630283 100644 --- a/examples/basic_ui.rs +++ b/examples/basic_ui.rs @@ -1,7 +1,7 @@ use bevy::{core_pipeline::clear_color::ClearColorConfig, prelude::*, window::PrimaryWindow}; use bevy_cosmic_edit::{ - AttrsOwned, CosmicAttrs, CosmicEditPlugin, CosmicEditUiBundle, CosmicEditor, CosmicFontConfig, - CosmicMetrics, CosmicText, CosmicTextPosition, Focus, + AttrsOwned, CosmicAttrs, CosmicEditBundle, CosmicEditPlugin, CosmicEditUiBundle, CosmicEditor, + CosmicFontConfig, CosmicMetrics, CosmicText, CosmicTextPosition, Focus, }; fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { @@ -20,22 +20,31 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { let scale_factor = primary_window.scale_factor() as f32; - let cosmic_edit = CosmicEditUiBundle { - style: Style { - width: Val::Percent(100.), - height: Val::Percent(100.), + let cosmic_edit = ( + CosmicEditBundle { + metrics: CosmicMetrics { + font_size: 14., + line_height: 18., + scale_factor, + }, + text_position: CosmicTextPosition::Center, + attrs: CosmicAttrs(AttrsOwned::new(attrs)), + text_setter: CosmicText::OneStyle("😀😀😀 x => y".to_string()), ..default() }, - cosmic_metrics: CosmicMetrics { - font_size: 14., - line_height: 18., - scale_factor, + CosmicEditUiBundle { + node_bundle: NodeBundle { + style: Style { + width: Val::Percent(100.), + height: Val::Percent(100.), + ..default() + }, + background_color: Color::WHITE.into(), + ..default() + }, + ..default() }, - text_position: CosmicTextPosition::Center, - cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)), - text_setter: CosmicText::OneStyle("😀😀😀 x => y".to_string()), - ..default() - }; + ); let cosmic_edit = commands.spawn(cosmic_edit).id(); diff --git a/examples/bevy_api_testing.rs b/examples/bevy_api_testing.rs index f51ff48..4d1b1a8 100644 --- a/examples/bevy_api_testing.rs +++ b/examples/bevy_api_testing.rs @@ -5,37 +5,53 @@ fn setup(mut commands: Commands) { commands.spawn(Camera2dBundle::default()); // spawn a new CosmicEditBundle - commands.spawn(CosmicEditUiBundle { - style: Style { - // Size and position of text box - width: Val::Px(300.), - height: Val::Px(50.), - left: Val::Px(100.), - top: Val::Px(100.), + let ui_editor = commands + .spawn(CosmicEditBundle { + attrs: CosmicAttrs(AttrsOwned::new( + Attrs::new().color(bevy_color_to_cosmic(Color::GREEN)), + )), + max_lines: CosmicMaxLines(1), ..default() - }, - cosmic_attrs: CosmicAttrs(AttrsOwned::new( - Attrs::new().color(bevy_color_to_cosmic(Color::GREEN)), - )), - max_lines: CosmicMaxLines(1), - placeholder_setter: PlaceholderText(CosmicText::OneStyle("Place held :)".into())), - ..default() - }); + }) + .insert(CosmicEditUiBundle { + node_bundle: NodeBundle { + style: Style { + // Size and position of text box + width: Val::Px(300.), + height: Val::Px(50.), + left: Val::Px(100.), + top: Val::Px(100.), + ..default() + }, + // needs to be set to prevent a bug where nothing is displayed + background_color: BackgroundColor(Color::WHITE), + ..default() + }, + ..default() + }) + .insert(CosmicEditPlaceholderBundle { + text_setter: PlaceholderText(CosmicText::OneStyle("Placeholder".into())), + attrs: PlaceholderAttrs(AttrsOwned::new( + Attrs::new().color(bevy_color_to_cosmic(Color::rgb_u8(128, 128, 128))), + )), + }) + .id(); - let sprite_editor = commands - .spawn(CosmicEditSpriteBundle { + commands.spawn(( + CosmicEditBundle { ..default() }, + SpriteBundle { + // Sets size of text box sprite: Sprite { - // Sets size of text box custom_size: Some(Vec2::new(300., 100.)), ..default() }, // Position of text box - transform: Transform::from_xyz(100., 200., 0.), + transform: Transform::from_xyz(0., 100., 0.), ..default() - }) - .id(); + }, + )); - commands.insert_resource(Focus(Some(sprite_editor))); + commands.insert_resource(Focus(Some(ui_editor))); } fn bevy_color_to_cosmic(color: bevy::prelude::Color) -> CosmicColor { diff --git a/examples/every_option.rs b/examples/every_option.rs index c2330f3..edc58f2 100644 --- a/examples/every_option.rs +++ b/examples/every_option.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, ui::FocusPolicy, window::PrimaryWindow}; +use bevy::{prelude::*, window::PrimaryWindow}; use bevy_cosmic_edit::*; #[derive(Resource)] @@ -12,33 +12,12 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { let primary_window = windows.single(); let editor = commands - .spawn(CosmicEditUiBundle { - node: Node::default(), - button: Button, - visibility: Visibility::Visible, - computed_visibility: ComputedVisibility::default(), - z_index: ZIndex::default(), - image: UiImage::default(), - transform: Transform::default(), - interaction: Interaction::default(), - focus_policy: FocusPolicy::default(), + .spawn(CosmicEditBundle { text_position: CosmicTextPosition::default(), fill_color: FillColor::default(), - background_color: BackgroundColor::default(), - global_transform: GlobalTransform::default(), background_image: CosmicBackground::default(), - border_color: Color::LIME_GREEN.into(), - style: Style { - // Size and position of text box - border: UiRect::all(Val::Px(4.)), - width: Val::Percent(20.), - height: Val::Px(50.), - left: Val::Percent(40.), - top: Val::Px(100.), - ..default() - }, - cosmic_attrs: CosmicAttrs(attrs.clone()), - cosmic_metrics: CosmicMetrics { + attrs: CosmicAttrs(attrs.clone()), + metrics: CosmicMetrics { font_size: 16., line_height: 16., scale_factor: primary_window.scale_factor() as f32, @@ -47,8 +26,28 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { max_lines: CosmicMaxLines(1), text_setter: CosmicText::OneStyle("BANANA IS THE CODEWORD!".into()), mode: CosmicMode::Wrap, - placeholder_setter: PlaceholderText(CosmicText::OneStyle("Placeholder".into())), - placeholder_attrs: PlaceholderAttrs(AttrsOwned::new( + canvas: Default::default(), + }) + .insert(CosmicEditUiBundle { + node_bundle: NodeBundle { + border_color: Color::LIME_GREEN.into(), + style: Style { + // Size and position of text box + border: UiRect::all(Val::Px(4.)), + width: Val::Percent(20.), + height: Val::Px(50.), + left: Val::Percent(40.), + top: Val::Px(100.), + ..default() + }, + background_color: Color::WHITE.into(), + ..default() + }, + ..default() + }) + .insert(CosmicEditPlaceholderBundle { + text_setter: PlaceholderText(CosmicText::OneStyle("Placeholder".into())), + attrs: PlaceholderAttrs(AttrsOwned::new( Attrs::new().color(CosmicColor::rgb(88, 88, 88)), )), }) diff --git a/examples/font_per_widget.rs b/examples/font_per_widget.rs index 6a62805..fa74f1e 100644 --- a/examples/font_per_widget.rs +++ b/examples/font_per_widget.rs @@ -207,45 +207,61 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { )], ]; - let cosmic_edit_1 = CosmicEditUiBundle { - text_position: bevy_cosmic_edit::CosmicTextPosition::Center, - cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)), - cosmic_metrics: CosmicMetrics { - font_size: 18., - line_height: 22., - scale_factor: primary_window.scale_factor() as f32, + let cosmic_edit_1 = ( + CosmicEditBundle { + text_position: bevy_cosmic_edit::CosmicTextPosition::Center, + attrs: CosmicAttrs(AttrsOwned::new(attrs)), + metrics: CosmicMetrics { + font_size: 18., + line_height: 22., + scale_factor: primary_window.scale_factor() as f32, + }, + text_setter: CosmicText::MultiStyle(lines), + ..default() }, - style: Style { - width: Val::Percent(50.), - height: Val::Percent(100.), + CosmicEditUiBundle { + node_bundle: NodeBundle { + style: Style { + width: Val::Percent(50.), + height: Val::Percent(100.), + ..default() + }, + background_color: BackgroundColor(Color::WHITE), + ..default() + }, ..default() }, - background_color: BackgroundColor(Color::WHITE), - text_setter: CosmicText::MultiStyle(lines), - ..default() - }; + ); let mut attrs_2 = Attrs::new(); attrs_2 = attrs_2.family(Family::Name("Times New Roman")); attrs_2.color_opt = Some(bevy_color_to_cosmic(Color::PURPLE)); - let cosmic_edit_2 = CosmicEditUiBundle { - cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs_2)), - cosmic_metrics: CosmicMetrics { - font_size: 28., - line_height: 36., - scale_factor: primary_window.scale_factor() as f32, + let cosmic_edit_2 = ( + CosmicEditBundle { + attrs: CosmicAttrs(AttrsOwned::new(attrs_2)), + metrics: CosmicMetrics { + font_size: 28., + line_height: 36., + scale_factor: primary_window.scale_factor() as f32, + }, + text_position: CosmicTextPosition::Center, + text_setter: CosmicText::OneStyle("Widget 2.\nClick on me =>".to_string()), + ..default() }, - text_position: CosmicTextPosition::Center, - background_color: BackgroundColor(Color::WHITE.with_a(0.8)), - style: Style { - width: Val::Percent(50.), - height: Val::Percent(100.), + CosmicEditUiBundle { + node_bundle: NodeBundle { + background_color: BackgroundColor(Color::WHITE.with_a(0.8)), + style: Style { + width: Val::Percent(50.), + height: Val::Percent(100.), + ..default() + }, + ..default() + }, ..default() }, - text_setter: CosmicText::OneStyle("Widget 2.\nClick on me =>".to_string()), - ..default() - }; + ); let mut id = None; // Spawn the CosmicEditUiBundles as children of root diff --git a/examples/image_background.rs b/examples/image_background.rs index cdc9d7d..8f2d994 100644 --- a/examples/image_background.rs +++ b/examples/image_background.rs @@ -7,21 +7,28 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { let bg_image_handle = asset_server.load("img/bevy_logo_light.png"); let editor = commands - .spawn(CosmicEditUiBundle { - style: Style { - // Size and position of text box - width: Val::Px(300.), - height: Val::Px(50.), - left: Val::Px(100.), - top: Val::Px(100.), - ..default() - }, - cosmic_attrs: CosmicAttrs(AttrsOwned::new( + .spawn(CosmicEditBundle { + attrs: CosmicAttrs(AttrsOwned::new( Attrs::new().color(bevy_color_to_cosmic(Color::GREEN)), )), background_image: CosmicBackground(Some(bg_image_handle)), ..default() }) + .insert(CosmicEditUiBundle { + node_bundle: NodeBundle { + style: Style { + // Size and position of text box + width: Val::Px(300.), + height: Val::Px(50.), + left: Val::Px(100.), + top: Val::Px(100.), + ..default() + }, + background_color: Color::WHITE.into(), + ..default() + }, + ..default() + }) .id(); commands.insert_resource(Focus(Some(editor))); } diff --git a/examples/multiple_sprites.rs b/examples/multiple_sprites.rs index 1f1942b..dc2f06f 100644 --- a/examples/multiple_sprites.rs +++ b/examples/multiple_sprites.rs @@ -20,43 +20,53 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { scale_factor: primary_window.scale_factor() as f32, }; - let cosmic_edit_1 = CosmicEditSpriteBundle { - cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)), - cosmic_metrics: metrics.clone(), - sprite: Sprite { - custom_size: Some(Vec2 { - x: primary_window.width() / 2., - y: primary_window.height(), - }), + let cosmic_edit_1 = ( + CosmicEditBundle { + attrs: CosmicAttrs(AttrsOwned::new(attrs)), + metrics: metrics.clone(), + text_position: CosmicTextPosition::Center, + fill_color: FillColor(Color::ALICE_BLUE), + text_setter: CosmicText::OneStyle("😀😀😀 x => y".to_string()), ..default() }, - transform: Transform::from_translation(Vec3::new(-primary_window.width() / 4., 0., 1.)), - text_position: CosmicTextPosition::Center, - fill_color: FillColor(Color::ALICE_BLUE), - text_setter: CosmicText::OneStyle("😀😀😀 x => y".to_string()), - ..default() - }; + SpriteBundle { + sprite: Sprite { + custom_size: Some(Vec2 { + x: primary_window.width() / 2., + y: primary_window.height(), + }), + ..default() + }, + transform: Transform::from_translation(Vec3::new(-primary_window.width() / 4., 0., 1.)), + ..default() + }, + ); - let cosmic_edit_2 = CosmicEditSpriteBundle { - cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)), - cosmic_metrics: metrics, - sprite: Sprite { - custom_size: Some(Vec2 { - x: primary_window.width() / 2., - y: primary_window.height() / 2., - }), + let cosmic_edit_2 = ( + CosmicEditBundle { + attrs: CosmicAttrs(AttrsOwned::new(attrs)), + metrics, + text_position: CosmicTextPosition::Center, + fill_color: FillColor(Color::GRAY.with_a(0.5)), + text_setter: CosmicText::OneStyle("Widget_2. Click on me".to_string()), ..default() }, - transform: Transform::from_translation(Vec3::new( - primary_window.width() / 4., - -primary_window.height() / 4., - 1., - )), - text_position: CosmicTextPosition::Center, - fill_color: FillColor(Color::GRAY.with_a(0.5)), - text_setter: CosmicText::OneStyle("Widget_2. Click on me".to_string()), - ..default() - }; + SpriteBundle { + sprite: Sprite { + custom_size: Some(Vec2 { + x: primary_window.width() / 2., + y: primary_window.height() / 2., + }), + ..default() + }, + transform: Transform::from_translation(Vec3::new( + primary_window.width() / 4., + -primary_window.height() / 4., + 1., + )), + ..default() + }, + ); let id = commands.spawn(cosmic_edit_1).id(); diff --git a/examples/readonly.rs b/examples/readonly.rs index 58035b7..118cdfe 100644 --- a/examples/readonly.rs +++ b/examples/readonly.rs @@ -20,23 +20,31 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { attrs = attrs.family(Family::Name("Victor Mono")); attrs = attrs.color(bevy_color_to_cosmic(Color::PURPLE)); - let cosmic_edit = CosmicEditUiBundle { - style: Style { - width: Val::Percent(100.), - height: Val::Percent(100.), + let cosmic_edit = ( + CosmicEditBundle { + attrs: CosmicAttrs(AttrsOwned::new(attrs)), + text_position: CosmicTextPosition::Center, + metrics: CosmicMetrics { + font_size: 14., + line_height: 18., + scale_factor: primary_window.scale_factor() as f32, + }, + text_setter: CosmicText::OneStyle("😀😀😀 x => y\nRead only widget".to_string()), ..default() }, - cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)), - text_position: CosmicTextPosition::Center, - background_color: BackgroundColor(Color::WHITE), - cosmic_metrics: CosmicMetrics { - font_size: 14., - line_height: 18., - scale_factor: primary_window.scale_factor() as f32, + CosmicEditUiBundle { + node_bundle: NodeBundle { + style: Style { + width: Val::Percent(100.), + height: Val::Percent(100.), + ..default() + }, + background_color: BackgroundColor(Color::WHITE), + ..default() + }, + ..default() }, - text_setter: CosmicText::OneStyle("😀😀😀 x => y\nRead only widget".to_string()), - ..default() - }; + ); let mut id = None; // Spawn the CosmicEditUiBundle as a child of root diff --git a/examples/text_input.rs b/examples/text_input.rs index f031b98..0b0f45e 100644 --- a/examples/text_input.rs +++ b/examples/text_input.rs @@ -10,30 +10,41 @@ fn create_editable_widget(commands: &mut Commands, scale_factor: f32, text: Stri let placeholder_attrs = AttrsOwned::new(Attrs::new().color(bevy_color_to_cosmic(Color::hex("#e6e6e6").unwrap()))); commands - .spawn(CosmicEditUiBundle { - border_color: Color::hex("#ededed").unwrap().into(), - style: Style { - border: UiRect::all(Val::Px(3.)), - width: Val::Percent(20.), - height: Val::Px(50.), - left: Val::Percent(40.), - top: Val::Px(100.), + .spawn(( + CosmicEditBundle { + attrs: CosmicAttrs(attrs.clone()), + metrics: CosmicMetrics { + font_size: 18., + line_height: 18. * 1.2, + scale_factor, + }, + max_lines: CosmicMaxLines(1), + text_setter: CosmicText::OneStyle(text), + text_position: CosmicTextPosition::Left { padding: 20 }, + mode: CosmicMode::InfiniteLine, ..default() }, - cosmic_attrs: CosmicAttrs(attrs.clone()), - cosmic_metrics: CosmicMetrics { - font_size: 18., - line_height: 18. * 1.2, - scale_factor, + CosmicEditUiBundle { + node_bundle: NodeBundle { + border_color: Color::hex("#ededed").unwrap().into(), + style: Style { + border: UiRect::all(Val::Px(3.)), + width: Val::Percent(20.), + height: Val::Px(50.), + left: Val::Percent(40.), + top: Val::Px(100.), + ..default() + }, + background_color: Color::WHITE.into(), + ..default() + }, + ..default() }, - max_lines: CosmicMaxLines(1), - text_setter: CosmicText::OneStyle(text), - text_position: CosmicTextPosition::Left { padding: 20 }, - mode: CosmicMode::InfiniteLine, - placeholder_setter: PlaceholderText(CosmicText::OneStyle("Type something...".into())), - placeholder_attrs: PlaceholderAttrs(placeholder_attrs.clone()), - ..default() - }) + CosmicEditPlaceholderBundle { + text_setter: PlaceholderText(CosmicText::OneStyle("Type something...".into())), + attrs: PlaceholderAttrs(placeholder_attrs.clone()), + }, + )) .id() } @@ -42,18 +53,9 @@ fn create_readonly_widget(commands: &mut Commands, scale_factor: f32, text: Stri AttrsOwned::new(Attrs::new().color(bevy_color_to_cosmic(Color::hex("4d4d4d").unwrap()))); commands .spawn(( - CosmicEditUiBundle { - border_color: Color::hex("#ededed").unwrap().into(), - style: Style { - border: UiRect::all(Val::Px(3.)), - width: Val::Percent(20.), - height: Val::Px(50.), - left: Val::Percent(40.), - top: Val::Px(100.), - ..default() - }, - cosmic_attrs: CosmicAttrs(attrs.clone()), - cosmic_metrics: CosmicMetrics { + CosmicEditBundle { + attrs: CosmicAttrs(attrs.clone()), + metrics: CosmicMetrics { font_size: 18., line_height: 18. * 1.2, scale_factor, @@ -63,6 +65,22 @@ fn create_readonly_widget(commands: &mut Commands, scale_factor: f32, text: Stri mode: CosmicMode::AutoHeight, ..default() }, + CosmicEditUiBundle { + node_bundle: NodeBundle { + border_color: Color::hex("#ededed").unwrap().into(), + style: Style { + border: UiRect::all(Val::Px(3.)), + width: Val::Percent(20.), + height: Val::Px(50.), + left: Val::Percent(40.), + top: Val::Px(100.), + ..default() + }, + background_color: Color::WHITE.into(), + ..default() + }, + ..default() + }, ReadOnly, )) .id() diff --git a/src/lib.rs b/src/lib.rs index 20c7fe4..2df1bc8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,9 +6,7 @@ mod render; use std::{collections::VecDeque, path::PathBuf}; -use bevy::{ - prelude::*, render::texture::DEFAULT_IMAGE_HANDLE, transform::TransformSystem, ui::FocusPolicy, -}; +use bevy::{prelude::*, render::texture::DEFAULT_IMAGE_HANDLE, transform::TransformSystem}; pub use cosmic_text::{ Action, Attrs, AttrsOwned, Color as CosmicColor, Cursor, Edit, Family, Style as FontStyle, Weight as FontWeight, @@ -209,156 +207,58 @@ impl Default for PlaceholderAttrs { Self(AttrsOwned::new(Attrs::new())) } } -#[derive(Bundle)] -pub struct CosmicEditUiBundle { - // Bevy UI bits - /// Describes the logical size of the node - pub node: Node, - /// Marker component that signals this node is a button - pub button: Button, - /// Styles which control the layout (size and position) of the node and it's children - /// In some cases these styles also affect how the node drawn/painted. - pub style: Style, - /// Describes whether and how the button has been interacted with by the input - pub interaction: Interaction, - /// Whether this node should block interaction with lower nodes - pub focus_policy: FocusPolicy, - /// UiNode Background Color, works as a tint. - pub background_color: BackgroundColor, - /// The background color, which serves as a "fill" for this node - pub fill_color: FillColor, - /// The color of the Node's border - pub border_color: BorderColor, - /// This is used as the cosmic text canvas - pub image: UiImage, - /// The transform of the node - /// - /// This field is automatically managed by the UI layout system. - /// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component. - pub transform: Transform, - /// The global transform of the node - /// - /// This field is automatically managed by the UI layout system. - /// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component. - pub global_transform: GlobalTransform, - /// Describes the visibility properties of the node - pub visibility: Visibility, - /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering - pub computed_visibility: ComputedVisibility, - /// Indicates the depth at which the node should appear in the UI - pub z_index: ZIndex, - // cosmic bits - /// text positioning enum - pub text_position: CosmicTextPosition, - /// text metrics - pub cosmic_metrics: CosmicMetrics, - /// text attributes - pub cosmic_attrs: CosmicAttrs, - /// bg img - pub background_image: CosmicBackground, - /// How many lines are allowed in buffer, 0 for no limit - pub max_lines: CosmicMaxLines, - /// How many characters are allowed in buffer, 0 for no limit - pub max_chars: CosmicMaxChars, - /// Setting this will update the buffer's text - pub text_setter: CosmicText, - /// Text input mode - pub mode: CosmicMode, - /// Setting this will update the placeholder text - pub placeholder_setter: PlaceholderText, - pub placeholder_attrs: PlaceholderAttrs, -} -impl Default for CosmicEditUiBundle { +#[derive(Component)] +pub struct CosmicCanvas(pub Handle<Image>); + +impl Default for CosmicCanvas { fn default() -> Self { - Self { - focus_policy: FocusPolicy::Block, - node: Default::default(), - button: Default::default(), - style: Default::default(), - border_color: BorderColor(Color::NONE), - interaction: Default::default(), - fill_color: Default::default(), - image: Default::default(), - transform: Default::default(), - global_transform: Default::default(), - visibility: Default::default(), - computed_visibility: Default::default(), - z_index: Default::default(), - text_position: Default::default(), - cosmic_metrics: Default::default(), - cosmic_attrs: Default::default(), - background_image: Default::default(), - max_lines: Default::default(), - max_chars: Default::default(), - text_setter: Default::default(), - mode: Default::default(), - background_color: BackgroundColor(Color::WHITE), - placeholder_setter: Default::default(), - placeholder_attrs: Default::default(), - } + CosmicCanvas(DEFAULT_IMAGE_HANDLE.typed()) } } -#[derive(Bundle)] -pub struct CosmicEditSpriteBundle { - // Bevy Sprite Bits - pub sprite: Sprite, - pub transform: Transform, - pub global_transform: GlobalTransform, - pub texture: Handle<Image>, - /// User indication of whether an entity is visible - pub visibility: Visibility, - /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering - pub computed_visibility: ComputedVisibility, - /// Widget background color - pub fill_color: FillColor, +#[derive(Bundle, Default)] +pub struct CosmicEditBundle { // cosmic bits - /// text positioning enum + pub fill_color: FillColor, pub text_position: CosmicTextPosition, - /// text metrics - pub cosmic_metrics: CosmicMetrics, - /// text attributes - pub cosmic_attrs: CosmicAttrs, - /// bg img + pub metrics: CosmicMetrics, + pub attrs: CosmicAttrs, pub background_image: CosmicBackground, - /// How many lines are allowed in buffer, 0 for no limit pub max_lines: CosmicMaxLines, - /// How many characters are allowed in buffer, 0 for no limit pub max_chars: CosmicMaxChars, - /// Setting this will update the buffer's text pub text_setter: CosmicText, - /// Text input mode pub mode: CosmicMode, - /// Setting this will update the placeholder text - pub placeholder_setter: PlaceholderText, - pub placeholder_attrs: PlaceholderAttrs, + pub canvas: CosmicCanvas, } -impl Default for CosmicEditSpriteBundle { +#[derive(Bundle)] +pub struct CosmicEditUiBundle { + pub node_bundle: NodeBundle, + pub image: UiImage, + pub interaction: Interaction, +} + +impl Default for CosmicEditUiBundle { fn default() -> Self { Self { - sprite: Default::default(), - transform: Default::default(), - global_transform: Default::default(), - texture: DEFAULT_IMAGE_HANDLE.typed(), - visibility: Visibility::Visible, - computed_visibility: Default::default(), - fill_color: Default::default(), - text_position: Default::default(), - cosmic_metrics: Default::default(), - cosmic_attrs: Default::default(), - background_image: Default::default(), - max_lines: Default::default(), - max_chars: Default::default(), - text_setter: Default::default(), - mode: Default::default(), - placeholder_setter: Default::default(), - placeholder_attrs: Default::default(), + node_bundle: NodeBundle { + background_color: BackgroundColor(Color::WHITE), + ..default() + }, + image: Default::default(), + interaction: Default::default(), } } } +#[derive(Bundle)] +pub struct CosmicEditPlaceholderBundle { + /// set this to update placeholder text + pub text_setter: PlaceholderText, + pub attrs: PlaceholderAttrs, +} + #[derive(Clone)] pub struct EditHistoryItem { pub cursor: Cursor, @@ -411,6 +311,8 @@ impl Plugin for CosmicEditPlugin { cosmic_editor_builder, placeholder_builder, on_scale_factor_change, + render::cosmic_ui_to_canvas, + render::cosmic_sprite_to_canvas, ), ) .add_systems(PreUpdate, (update_buffer_text, update_placeholder_text)) @@ -425,6 +327,8 @@ impl Plugin for CosmicEditPlugin { freeze_cursor_blink, hide_inactive_or_readonly_cursor, clear_inactive_selection, + render::update_handle_ui, + render::update_handle_sprite, ), ) .add_systems( @@ -802,7 +706,7 @@ mod tests { use crate::*; fn test_spawn_cosmic_edit_system(mut commands: Commands) { - commands.spawn(CosmicEditUiBundle { + commands.spawn(CosmicEditBundle { text_setter: CosmicText::OneStyle("Blah".into()), ..Default::default() }); diff --git a/src/render.rs b/src/render.rs index e1ad1cd..ee84891 100644 --- a/src/render.rs +++ b/src/render.rs @@ -11,8 +11,8 @@ use image::{imageops::FilterType, GenericImageView}; use crate::{ get_text_size, get_x_offset_center, get_y_offset_center, CosmicAttrs, CosmicBackground, - CosmicEditor, CosmicFontSystem, CosmicMetrics, CosmicMode, CosmicTextPosition, FillColor, - Focus, Placeholder, ReadOnly, XOffset, + CosmicCanvas, CosmicEditor, CosmicFontSystem, CosmicMetrics, CosmicMode, CosmicTextPosition, + FillColor, Focus, Placeholder, ReadOnly, XOffset, }; #[derive(Resource)] @@ -35,12 +35,11 @@ pub(crate) fn cosmic_edit_redraw_buffer( &CosmicAttrs, &CosmicBackground, &FillColor, + &mut CosmicCanvas, &CosmicTextPosition, - Option<&mut UiImage>, Option<&Node>, Option<&mut Style>, Option<&mut Sprite>, - Option<&mut Handle<Image>>, &mut XOffset, &CosmicMode, Option<&mut Placeholder>, @@ -55,12 +54,11 @@ pub(crate) fn cosmic_edit_redraw_buffer( attrs, background_image, fill_color, + mut canvas, text_position, - ui_image_opt, node_opt, style_opt, sprite_opt, - handle_opt, mut x_offset, mode, mut placeholder_opt, @@ -236,61 +234,37 @@ pub(crate) fn cosmic_edit_redraw_buffer( }, ); - // replace target image with modified pixel buffer - match handle_opt { - Some(mut handle) => replace_target_image( - &mut handle, - &mut images, - widget_width, - widget_height, - pixels, - ), - None => replace_target_image( - &mut ui_image_opt.unwrap().texture, - &mut images, - widget_width, - widget_height, - pixels, - ), + let canvas = &mut canvas.0; + + if let Some(prev_image) = images.get_mut(canvas) { + if *canvas == bevy::render::texture::DEFAULT_IMAGE_HANDLE.typed() { + let mut prev_image = prev_image.clone(); + prev_image.data.clear(); + prev_image.data.extend_from_slice(pixels.as_slice()); + prev_image.resize(Extent3d { + width: widget_width as u32, + height: widget_height as u32, + depth_or_array_layers: 1, + }); + let handle_id: HandleId = HandleId::random::<Image>(); + let new_handle: Handle<Image> = Handle::weak(handle_id); + let new_handle = images.set(new_handle, prev_image); + *canvas = new_handle; + } else { + prev_image.data.clear(); + prev_image.data.extend_from_slice(pixels.as_slice()); + prev_image.resize(Extent3d { + width: widget_width as u32, + height: widget_height as u32, + depth_or_array_layers: 1, + }); + } } editor.buffer_mut().set_redraw(false); } } -fn replace_target_image( - cosmic_canvas_img_handle: &mut Handle<Image>, - images: &mut ResMut<Assets<Image>>, - width: f32, - height: f32, - pixels: Vec<u8>, -) { - if let Some(prev_image) = images.get_mut(cosmic_canvas_img_handle) { - if *cosmic_canvas_img_handle == bevy::render::texture::DEFAULT_IMAGE_HANDLE.typed() { - let mut prev_image = prev_image.clone(); - prev_image.data.clear(); - prev_image.data.extend_from_slice(pixels.as_slice()); - prev_image.resize(Extent3d { - width: width as u32, - height: height as u32, - depth_or_array_layers: 1, - }); - let handle_id: HandleId = HandleId::random::<Image>(); - let new_handle: Handle<Image> = Handle::weak(handle_id); - let new_handle = images.set(new_handle, prev_image); - *cosmic_canvas_img_handle = new_handle; - } else { - prev_image.data.clear(); - prev_image.data.extend_from_slice(pixels.as_slice()); - prev_image.resize(Extent3d { - width: width as u32, - height: height as u32, - depth_or_array_layers: 1, - }); - } - } -} - fn draw_pixel( buffer: &mut [u8], width: i32, @@ -472,3 +446,35 @@ pub(crate) fn on_scale_factor_change( } } } + +pub(crate) fn cosmic_ui_to_canvas( + mut added_ui_images: Query<(&mut UiImage, &CosmicCanvas), Added<UiImage>>, +) { + for (mut ui_image, canvas) in added_ui_images.iter_mut() { + ui_image.texture = canvas.0.clone_weak(); + } +} + +pub(crate) fn update_handle_ui( + mut changed_handles: Query<(&mut UiImage, &CosmicCanvas), Changed<CosmicCanvas>>, +) { + for (mut ui_image, canvas) in changed_handles.iter_mut() { + ui_image.texture = canvas.0.clone_weak(); + } +} + +pub(crate) fn cosmic_sprite_to_canvas( + mut added_sprite_textures: Query<(&mut Handle<Image>, &CosmicCanvas), Added<Handle<Image>>>, +) { + for (mut handle, canvas) in added_sprite_textures.iter_mut() { + *handle = canvas.0.clone_weak(); + } +} + +pub(crate) fn update_handle_sprite( + mut changed_handles: Query<(&mut Handle<Image>, &CosmicCanvas), Changed<CosmicCanvas>>, +) { + for (mut handle, canvas) in changed_handles.iter_mut() { + *handle = canvas.0.clone_weak(); + } +} -- GitLab