You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
7.5 KiB
Rust
230 lines
7.5 KiB
Rust
use crate::editor::prelude::*;
|
|
use bevy::{
|
|
asset::{AssetLoader, LoadContext, LoadedAsset},
|
|
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(
|
|
¤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<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(),
|
|
});
|
|
});
|
|
}
|
|
}
|