From 4495be1cd9ca122b65a3b34230d1294c70a6b4f7 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Tue, 19 Sep 2023 21:45:59 -0700 Subject: [PATCH] moving code around, refactor monologue spawning events --- bin/editor.rs | 284 ++-------------------------------------- src/editor/font.rs | 71 ++++++++++ src/editor/mod.rs | 4 + src/editor/monologue.rs | 233 ++++++++++++++++++++++++++++++++ src/ui.rs | 1 - 5 files changed, 316 insertions(+), 277 deletions(-) create mode 100644 src/editor/font.rs create mode 100644 src/editor/monologue.rs diff --git a/bin/editor.rs b/bin/editor.rs index bc6879f..d8bfaab 100644 --- a/bin/editor.rs +++ b/bin/editor.rs @@ -24,14 +24,14 @@ // * (???) Better handle hide/close monologue use bevy::{ - asset::{Asset, AssetLoader, Assets, ChangeWatcher, LoadContext, LoadedAsset}, + asset::{Asset, Assets, ChangeWatcher}, gltf::Gltf, prelude::*, - utils::{BoxedFuture, Duration}, + utils::Duration, }; use monologue_trees::{ debug::*, - editor::{assets::*, audio::*, *}, + editor::{assets::*, audio::*, font::*, monologue::*, *}, ui, }; @@ -75,6 +75,7 @@ fn main() { .add_asset::() .init_asset_loader::() .add_event::() + .add_event::() .add_systems(Startup, (initialize_ui, init_texts_ui, welcome_message)) .add_systems(Update, quit.run_if(ui::activated::)) .add_systems( @@ -108,7 +109,10 @@ fn main() { gltf_ui, texts_ui, control_active_gltf, - show_preview_text, + control_monologue, + ui_control_monologue, + ui_active::, + ui_inactive::, sync_monologue_font, ), ) @@ -894,278 +898,6 @@ mod animations { } } -use fonts::*; -mod fonts { - use super::*; - - #[derive(Debug, Component, Default)] - pub struct FontWidget; - - #[derive(Debug, Resource, Default)] - pub struct FontInfo { - pub default: Option>, - } - - pub fn fonts_ui( - mut events: EventReader>, - mut commands: Commands, - widget: Query>, - current: Query<(Entity, &ui::TargetAsset)>, - server: Res, - ) { - events.iter().for_each(|event| match event { - AssetEvent::Created { handle } => { - info!("Asset created! {:?}", event); - create_asset_button( - &widget, - &mut commands, - ui::TargetAsset { - handle: handle.clone(), - }, - get_asset_name(&server, handle.clone()), - Some(handle.clone()), - ); - } - AssetEvent::Removed { handle } => { - info!("Asset removed! {:?}", event); - destroy_asset_button( - ¤t, - &mut commands, - &ui::TargetAsset { - handle: handle.clone(), - }, - ); - } - AssetEvent::Modified { handle } => { - info!("Asset modified! {:?}", event); - destroy_asset_button( - ¤t, - &mut commands, - &ui::TargetAsset { - handle: handle.clone(), - }, - ); - create_asset_button( - &widget, - &mut commands, - ui::TargetAsset { - handle: handle.clone(), - }, - get_asset_name(&server, handle.clone()), - Some(handle.clone()), - ); - } - }); - } - - pub fn set_active_font( - events: Query<&ui::TargetAsset, Added>, - mut font: ResMut, - ) { - events - .iter() - .for_each(|ui::TargetAsset { handle }| font.default = Some(handle.clone())); - } -} - -use monologues::*; -mod monologues { - use super::*; - use bevy::{ - reflect::{TypePath, TypeUuid}, - ui::FocusPolicy, - }; - use serde::Deserialize; - - #[derive(Debug, Component, Default)] - pub struct MonologueWidget; - - #[derive(Debug, Deserialize, TypeUuid, TypePath, PartialEq)] - #[uuid = "216a570b-d142-4026-baed-d7feb0250458"] - pub struct Monologue { - text: String, - } - - #[derive(Debug, Component)] - pub struct MonologueModal; - - #[derive(Debug, Component)] - pub struct MonologueContainer; - - #[derive(Default)] - pub struct MonologueLoader; - - impl AssetLoader for MonologueLoader { - fn load<'a>( - &'a self, - bytes: &'a [u8], - load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result<(), bevy::asset::Error>> { - Box::pin(async move { - let asset = Monologue { - text: String::from_utf8(bytes.to_vec())?, - }; - load_context.set_default_asset(LoadedAsset::new(asset)); - Ok(()) - }) - } - - fn extensions(&self) -> &[&str] { - &["monologue.txt"] - } - } - - pub fn init_texts_ui(mut commands: Commands) { - commands.spawn(( - NodeBundle { - style: Style { - width: Val::Percent(100.0), - align_items: AlignItems::Center, - justify_content: JustifyContent::Center, - ..default() - }, - focus_policy: FocusPolicy::Pass, - ..default() - }, - MonologueContainer, - )); - } - - pub fn texts_ui( - mut events: EventReader>, - mut commands: Commands, - widget: Query>, - current: Query<(Entity, &ui::TargetAsset)>, - server: Res, - ) { - events.iter().for_each(|event| match event { - AssetEvent::Created { handle } => { - info!("Monologue created! {:?}", event); - create_asset_button( - &widget, - &mut commands, - ui::TargetAsset { - handle: handle.clone(), - }, - get_asset_name(&server, handle.clone()), - None, - ); - } - AssetEvent::Removed { handle } => { - info!("Monologue removed! {:?}", event); - destroy_asset_button( - ¤t, - &mut commands, - &ui::TargetAsset { - handle: handle.clone(), - }, - ); - } - AssetEvent::Modified { handle } => { - info!("Monologue modified! {:?}", event); - destroy_asset_button( - ¤t, - &mut commands, - &ui::TargetAsset { - handle: handle.clone(), - }, - ); - create_asset_button( - &widget, - &mut commands, - ui::TargetAsset { - handle: handle.clone(), - }, - get_asset_name(&server, handle.clone()), - None, - ); - } - }); - } - - pub fn show_preview_text( - added: Query, Added)>, - monologue_handles: Query<&ui::TargetAsset>, - monologues: Res>, - container: Query>, - mut commands: Commands, - font: Res, - ) { - added - .iter() - .filter_map(|entity| monologue_handles.get(entity).ok()) - .for_each(|ui::TargetAsset { handle }| { - let monologue = monologues.get(handle).expect("Preview loaded monologue"); - commands - .entity(container.single()) - .despawn_descendants() - .with_children(|parent| { - parent - .spawn(NodeBundle { - style: Style { - max_width: Val::Percent(50.0), - padding: UiRect::all(Val::Px(1.0)), - margin: UiRect::all(Val::Px(1.0)), - border: UiRect::all(Val::Px(1.0)), - flex_direction: FlexDirection::Column, - ..default() - }, - background_color: Color::WHITE.into(), - border_color: Color::BLACK.into(), - ..default() - }) - .with_children(|parent| { - parent.spawn(( - ui::TitleBarBase::new(Color::VIOLET).bundle(), - ui::Title { - text: "Monologue".into(), - ..default() - }, - ui::Close { - target: parent.parent_entity(), - }, - ui::Sorting(0), - )); - let style = match &font.default { - Some(handle) => TextStyle { - color: Color::BLACK.into(), - font_size: 16.0, - font: handle.clone(), - ..default() - }, - None => TextStyle { - color: Color::BLACK.into(), - font_size: 16.0, - ..default() - }, - }; - parent.spawn(( - TextBundle::from_section(monologue.text.clone(), style), - handle.clone(), - )); - }); - }); - }); - } - - // TODO: Sync Handle and TextStyle components to automagically generate and sync text - pub fn sync_monologue_font( - mut texts: Query<&mut Text, With>>, - font: Res, - ) { - if font.is_changed() || font.is_added() { - texts.iter_mut().for_each(|mut text| { - text.sections - .iter_mut() - .for_each(|section| match &font.default { - Some(handle) => section.style.font = handle.clone(), - None => section.style.font = Handle::default(), - }); - }); - } - } -} - use cameras::*; mod cameras { use super::*; diff --git a/src/editor/font.rs b/src/editor/font.rs new file mode 100644 index 0000000..af882b1 --- /dev/null +++ b/src/editor/font.rs @@ -0,0 +1,71 @@ +use crate::{editor::assets::*, ui}; +use bevy::prelude::*; + +#[derive(Debug, Component, Default)] +pub struct FontWidget; + +#[derive(Debug, Resource, Default)] +pub struct FontInfo { + pub default: Option>, +} + +pub fn fonts_ui( + mut events: EventReader>, + mut commands: Commands, + widget: Query>, + current: Query<(Entity, &ui::TargetAsset)>, + server: Res, +) { + events.iter().for_each(|event| match event { + AssetEvent::Created { handle } => { + info!("Asset created! {:?}", event); + create_asset_button( + &widget, + &mut commands, + ui::TargetAsset { + handle: handle.clone(), + }, + get_asset_name(&server, handle.clone()), + Some(handle.clone()), + ); + } + AssetEvent::Removed { handle } => { + info!("Asset removed! {:?}", event); + destroy_asset_button( + ¤t, + &mut commands, + &ui::TargetAsset { + handle: handle.clone(), + }, + ); + } + AssetEvent::Modified { handle } => { + info!("Asset modified! {:?}", event); + destroy_asset_button( + ¤t, + &mut commands, + &ui::TargetAsset { + handle: handle.clone(), + }, + ); + create_asset_button( + &widget, + &mut commands, + ui::TargetAsset { + handle: handle.clone(), + }, + get_asset_name(&server, handle.clone()), + Some(handle.clone()), + ); + } + }); +} + +pub fn set_active_font( + events: Query<&ui::TargetAsset, Added>, + mut font: ResMut, +) { + events + .iter() + .for_each(|ui::TargetAsset { handle }| font.default = Some(handle.clone())); +} diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 3fc8cbe..4ae372b 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -2,6 +2,10 @@ pub mod audio; pub mod assets; +pub mod monologue; + +pub mod font; + use crate::ui; use bevy::{asset::Asset, prelude::*}; diff --git a/src/editor/monologue.rs b/src/editor/monologue.rs new file mode 100644 index 0000000..f3ae7b4 --- /dev/null +++ b/src/editor/monologue.rs @@ -0,0 +1,233 @@ +use crate::{ + editor::{assets::*, font::*}, + ui, +}; +use bevy::{ + asset::{AssetLoader, LoadContext, LoadedAsset}, + prelude::*, + reflect::{TypePath, TypeUuid}, + ui::FocusPolicy, + utils::BoxedFuture, +}; +use serde::Deserialize; + +#[derive(Debug, Component, Default)] +pub struct MonologueWidget; + +#[derive(Debug, Deserialize, TypeUuid, TypePath, PartialEq)] +#[uuid = "216a570b-d142-4026-baed-d7feb0250458"] +pub struct Monologue { + text: String, +} + +#[derive(Debug, Event)] +pub enum ControlMonologue { + Show(Handle), + Hide, +} + +#[derive(Debug, Component)] +pub struct MonologueModal; + +#[derive(Debug, Component)] +pub struct MonologueContainer; + +#[derive(Default)] +pub struct MonologueLoader; + +impl AssetLoader for MonologueLoader { + fn load<'a>( + &'a self, + bytes: &'a [u8], + load_context: &'a mut LoadContext, + ) -> BoxedFuture<'a, Result<(), bevy::asset::Error>> { + Box::pin(async move { + let asset = Monologue { + text: String::from_utf8(bytes.to_vec())?, + }; + load_context.set_default_asset(LoadedAsset::new(asset)); + Ok(()) + }) + } + + fn extensions(&self) -> &[&str] { + &["monologue.txt"] + } +} + +pub fn init_texts_ui(mut commands: Commands) { + commands.spawn(( + NodeBundle { + style: Style { + width: Val::Percent(100.0), + align_items: AlignItems::Center, + justify_content: JustifyContent::Center, + ..default() + }, + focus_policy: FocusPolicy::Pass, + ..default() + }, + MonologueContainer, + )); +} + +pub fn texts_ui( + mut events: EventReader>, + mut commands: Commands, + widget: Query>, + current: Query<(Entity, &ui::TargetAsset)>, + server: Res, +) { + events.iter().for_each(|event| match event { + AssetEvent::Created { handle } => { + info!("Monologue created! {:?}", event); + create_asset_button( + &widget, + &mut commands, + ui::TargetAsset { + handle: handle.clone(), + }, + get_asset_name(&server, handle.clone()), + None, + ); + } + AssetEvent::Removed { handle } => { + info!("Monologue removed! {:?}", event); + destroy_asset_button( + ¤t, + &mut commands, + &ui::TargetAsset { + handle: handle.clone(), + }, + ); + } + AssetEvent::Modified { handle } => { + info!("Monologue modified! {:?}", event); + destroy_asset_button( + ¤t, + &mut commands, + &ui::TargetAsset { + handle: handle.clone(), + }, + ); + create_asset_button( + &widget, + &mut commands, + ui::TargetAsset { + handle: handle.clone(), + }, + get_asset_name(&server, handle.clone()), + None, + ); + } + }); +} + +pub fn control_monologue( + mut events: EventReader, + monologues: Res>, + container: Query>, + mut commands: Commands, + font: Res, // Not convinced we need this... +) { + events.iter().for_each(|event| match event { + ControlMonologue::Hide => { + commands.entity(container.single()).despawn_descendants(); + } + ControlMonologue::Show(handle) => { + monologues.get(handle).iter().for_each(|&monologue| { + commands + .entity(container.single()) + .despawn_descendants() + .with_children(|parent| { + parent + .spawn(NodeBundle { + style: Style { + max_width: Val::Percent(50.0), + padding: UiRect::all(Val::Px(1.0)), + margin: UiRect::all(Val::Px(1.0)), + border: UiRect::all(Val::Px(1.0)), + flex_direction: FlexDirection::Column, + ..default() + }, + background_color: Color::WHITE.into(), + border_color: Color::BLACK.into(), + ..default() + }) + .with_children(|parent| { + parent.spawn(( + ui::TitleBarBase::new(Color::VIOLET).bundle(), + ui::Title { + text: "Monologue".into(), + ..default() + }, + ui::Close { + target: parent.parent_entity(), + }, + ui::Sorting(0), + )); + let style = match &font.default { + Some(handle) => TextStyle { + color: Color::BLACK.into(), + font_size: 16.0, + font: handle.clone(), + ..default() + }, + None => TextStyle { + color: Color::BLACK.into(), + font_size: 16.0, + ..default() + }, + }; + parent.spawn(( + TextBundle::from_section(monologue.text.clone(), style), + handle.clone(), + )); + }); + }); + }); + } + }); +} + +pub fn ui_control_monologue( + events: Query< + ( + &Interaction, + &ui::TargetAsset, + Option<&ui::Active>, + ), + (With