moving code around, refactor monologue spawning events

main
Elijah Voigt 2 years ago
parent 2b9f96d4b4
commit 4495be1cd9

@ -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::<Monologue>()
.init_asset_loader::<MonologueLoader>()
.add_event::<ControlAudio>()
.add_event::<ControlMonologue>()
.add_systems(Startup, (initialize_ui, init_texts_ui, welcome_message))
.add_systems(Update, quit.run_if(ui::activated::<QuitAction>))
.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::<Monologue>,
ui_inactive::<Monologue>,
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<Handle<Font>>,
}
pub fn fonts_ui(
mut events: EventReader<AssetEvent<Font>>,
mut commands: Commands,
widget: Query<Entity, With<FontWidget>>,
current: Query<(Entity, &ui::TargetAsset<Font>)>,
server: Res<AssetServer>,
) {
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(
&current,
&mut commands,
&ui::TargetAsset {
handle: handle.clone(),
},
);
}
AssetEvent::Modified { handle } => {
info!("Asset modified! {:?}", event);
destroy_asset_button(
&current,
&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<Font>, Added<ui::Active>>,
mut font: ResMut<FontInfo>,
) {
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<AssetEvent<Monologue>>,
mut commands: Commands,
widget: Query<Entity, With<MonologueWidget>>,
current: Query<(Entity, &ui::TargetAsset<Monologue>)>,
server: Res<AssetServer>,
) {
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(
&current,
&mut commands,
&ui::TargetAsset {
handle: handle.clone(),
},
);
}
AssetEvent::Modified { handle } => {
info!("Monologue modified! {:?}", event);
destroy_asset_button(
&current,
&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<Entity, (With<Button>, Added<ui::Active>)>,
monologue_handles: Query<&ui::TargetAsset<Monologue>>,
monologues: Res<Assets<Monologue>>,
container: Query<Entity, With<MonologueContainer>>,
mut commands: Commands,
font: Res<FontInfo>,
) {
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<Monologue> and TextStyle components to automagically generate and sync text
pub fn sync_monologue_font(
mut texts: Query<&mut Text, With<Handle<Monologue>>>,
font: Res<FontInfo>,
) {
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::*;

@ -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<Handle<Font>>,
}
pub fn fonts_ui(
mut events: EventReader<AssetEvent<Font>>,
mut commands: Commands,
widget: Query<Entity, With<FontWidget>>,
current: Query<(Entity, &ui::TargetAsset<Font>)>,
server: Res<AssetServer>,
) {
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(
&current,
&mut commands,
&ui::TargetAsset {
handle: handle.clone(),
},
);
}
AssetEvent::Modified { handle } => {
info!("Asset modified! {:?}", event);
destroy_asset_button(
&current,
&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<Font>, Added<ui::Active>>,
mut font: ResMut<FontInfo>,
) {
events
.iter()
.for_each(|ui::TargetAsset { handle }| font.default = Some(handle.clone()));
}

@ -2,6 +2,10 @@ pub mod audio;
pub mod assets;
pub mod monologue;
pub mod font;
use crate::ui;
use bevy::{asset::Asset, prelude::*};

@ -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<Monologue>),
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<AssetEvent<Monologue>>,
mut commands: Commands,
widget: Query<Entity, With<MonologueWidget>>,
current: Query<(Entity, &ui::TargetAsset<Monologue>)>,
server: Res<AssetServer>,
) {
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(
&current,
&mut commands,
&ui::TargetAsset {
handle: handle.clone(),
},
);
}
AssetEvent::Modified { handle } => {
info!("Monologue modified! {:?}", event);
destroy_asset_button(
&current,
&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<ControlMonologue>,
monologues: Res<Assets<Monologue>>,
container: Query<Entity, With<MonologueContainer>>,
mut commands: Commands,
font: Res<FontInfo>, // 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<Monologue>,
Option<&ui::Active>,
),
(With<Button>, Changed<Interaction>),
>,
mut writer: EventWriter<ControlMonologue>,
) {
events
.iter()
.filter_map(
|(interaction, ui::TargetAsset { handle }, active)| match interaction {
Interaction::Pressed => Some((handle, active)),
_ => None,
},
)
.for_each(|(handle, active)| match active {
Some(_) => writer.send(ControlMonologue::Hide),
None => writer.send(ControlMonologue::Show(handle.clone())),
});
}
// TODO: Sync Handle<Monologue> and TextStyle components to automagically generate and sync text
pub fn sync_monologue_font(
mut texts: Query<&mut Text, With<Handle<Monologue>>>,
font: Res<FontInfo>,
) {
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(),
});
});
}
}

@ -453,7 +453,6 @@ mod buttons {
.iter()
.for_each(|(select, children)| match interaction {
Interaction::Pressed => match select {
Select::None => (),
Select::Multi | Select::Action => {
if active.is_some() {
commands.entity(entity).remove::<Active>();

Loading…
Cancel
Save