Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//! # bevy_cosmic_edit
//!
//! Multiline text editor using [`cosmic_text`] for the [`bevy`] game engine!
//!
//! This bevy plugin provides multiline text editing for bevy apps, thanks to [cosmic_text](https://github.com/pop-os/cosmic-text) crate!
//! Emoji, ligatures, and other fancy stuff is supported!
//!
//! 
//!
//! ## Usage
//!
//! *Warning: This plugin is currently in early development, and its API is subject to change.*
//!
//! ```
//! use bevy::prelude::*;
//! use bevy_cosmic_edit::*;
//!
//! fn setup(mut commands: Commands, mut font_system: ResMut<CosmicFontSystem>) {
//! commands.spawn(Camera2dBundle::default());
//!
//! // Text attributes
//! let font_size = 16.0;
//! let line_height = 18.0;
//! let attrs = Attrs::new()
//! .family(Family::Monospace)
//! .color(Color::DARK_GRAY.to_cosmic())
//! .weight(FontWeight::BOLD);
//!
//! // Spawning
//! commands.spawn(CosmicEditBundle {
//! buffer: CosmicBuffer::new(&mut font_system, Metrics::new(font_size, line_height))
//! .with_text(&mut font_system, "Hello, Cosmic!", attrs),
//! sprite_bundle: SpriteBundle {
//! sprite: Sprite {
//! custom_size: Some(Vec2::new(300.0, 40.0)),
//! ..default()
//! },
//! ..default()
//! },
//! ..default()
//! });
//! }
//!
//! fn main() {
//! App::new()
//! .add_plugins(DefaultPlugins)
//! .add_plugins(CosmicEditPlugin::default())
//! .add_systems(Startup, setup)
//! .add_systems(Update, change_active_editor_sprite)
//! .run();
//! }
//! ```
//!
//! Check the examples folder for much more!
//!
//! Native:
//!
//! ```shell
//! $ cargo r --example font_per_widget
//! ```
//!
//! Wasm:
//!
//! ```shell
//! $ cargo install wasm-server-runner
//! $ RUSTFLAGS=--cfg=web_sys_unstable_apis cargo r --target wasm32-unknown-unknown --example basic_ui
//! ```
//!
//! ## Compatibility
//!
//! | bevy | bevy_cosmic_edit |
//! | ------ | ---------------- |
//! | 0.13.0 | 0.16 - latest |
//! | 0.12.* | 0.15 |
//! | 0.11.* | 0.8 - 0.14 |
//!
//! ## Feature flags
#![doc = document_features::document_features!()]
//!
#![allow(clippy::type_complexity)]
pub use cosmic_text::{self, Color as CosmicColor, Style as FontStyle, Weight as FontWeight};
pub use input::*;
pub use password::*;
pub use placeholder::*;
pub use render::*;
/// Plugin struct that adds systems and initializes resources related to cosmic edit functionality.
#[derive(Default)]
pub struct CosmicEditPlugin {
pub font_config: CosmicFontConfig,
}
impl Plugin for CosmicEditPlugin {
fn build(&self, app: &mut App) {
let font_system = create_cosmic_font_system(self.font_config.clone());
app.add_plugins((
BufferPlugin,
RenderPlugin,
WidgetPlugin,
InputPlugin,
FocusPlugin,
PlaceholderPlugin,
PasswordPlugin,
.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);
app.insert_resource(WasmPasteAsyncChannel { tx, rx })
.add_systems(Update, poll_wasm_paste);
}
}
}
/// 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.
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
///
/// A very basic example which doesn't panic:
/// ```rust
/// use bevy::prelude::*;
/// use bevy_cosmic_edit::CosmicPrimaryCamera;
///
/// fn main() {
/// App::new()
/// .add_plugins((
/// DefaultPlugins,
/// bevy_cosmic_edit::CosmicEditPlugin::default(),
/// ))
/// .add_systems(Startup, setup)
/// .run();
/// }
///
/// fn setup(mut commands: Commands) {
/// commands.spawn((Camera3dBundle::default(), CosmicPrimaryCamera));
/// commands.spawn(Camera3dBundle {
/// camera: Camera {
/// order: 2,
/// ..default()
/// },
/// ..default()
/// });
/// }
/// ```
#[derive(Component, Debug, Default)]
/// Resource struct that holds configuration options for cosmic fonts.
#[derive(Resource, Clone)]
pub struct CosmicFontConfig {
pub fonts_dir_path: Option<PathBuf>,
pub font_bytes: Option<Vec<&'static [u8]>>,
/// If [false], some characters (esspecially Unicode emojies) might not load properly
/// Caution: this can be relatively slow
pub load_system_fonts: bool,
}
impl Default for CosmicFontConfig {
fn default() -> Self {
let fallback_font = include_bytes!("./font/FiraMono-Regular-subset.ttf");
Self {
font_bytes: Some(vec![fallback_font]),
fonts_dir_path: None,
}
}
}
fn create_cosmic_font_system(cosmic_font_config: CosmicFontConfig) -> cosmic_text::FontSystem {
let locale = sys_locale::get_locale().unwrap_or_else(|| String::from("en-US"));
let mut db = cosmic_text::fontdb::Database::new();
if let Some(dir_path) = cosmic_font_config.fonts_dir_path.clone() {
db.load_fonts_dir(dir_path);
}
if let Some(custom_font_data) = &cosmic_font_config.font_bytes {
for elem in custom_font_data {
db.load_font_data(elem.to_vec());
if cosmic_font_config.load_system_fonts {
db.load_system_fonts();
}
cosmic_text::FontSystem::new_with_locale_and_db(locale, db)
use bevy::input::keyboard::KeyboardInput;
use self::buffer::CosmicBuffer;
fn test_spawn_cosmic_edit_system(
mut commands: Commands,
mut font_system: ResMut<CosmicFontSystem>,
) {
buffer: CosmicBuffer::new(&mut font_system, cosmic_text::Metrics::new(20., 20.))
.with_rich_text(&mut font_system, vec![("Blah", attrs)], attrs),
}
#[test]
fn test_spawn_cosmic_edit() {
let mut app = App::new();
app.add_plugins(TaskPoolPlugin::default());
app.add_plugins(AssetPlugin::default());
app.insert_resource(CosmicFontSystem(create_cosmic_font_system(
CosmicFontConfig::default(),
)));
app.add_systems(Update, test_spawn_cosmic_edit_system);
let mouse_input: ButtonInput<MouseButton> = ButtonInput::<MouseButton>::default();
app.add_event::<KeyboardInput>();
let mut text_nodes_query = app.world_mut().query::<&CosmicBuffer>();
for cosmic_editor in text_nodes_query.iter(&app.world()) {
insta::assert_debug_snapshot!(cosmic_editor
.lines
.iter()
.map(|line| line.text())
.collect::<Vec<_>>());
}
}
}