use crate::{
fyrox::{
core::pool::Handle,
engine::Engine,
graph::SceneGraph,
gui::{
button::{Button, ButtonBuilder, ButtonMessage},
check_box::{CheckBox, CheckBoxBuilder, CheckBoxMessage},
grid::{Column, Grid, GridBuilder, Row},
message::UiMessage,
scroll_bar::{ScrollBar, ScrollBarBuilder, ScrollBarMessage},
stack_panel::StackPanel,
text::TextBuilder,
widget::{WidgetBuilder, WidgetMessage},
BuildContext, Thickness, VerticalAlignment,
},
scene::{
node::Node,
sound::{Sound, Status},
},
},
scene::{GameScene, Selection},
Message,
};
pub struct AudioPreviewPanel {
pub root_widget: Handle<Grid>,
preview: Handle<CheckBox>,
play: Handle<Button>,
pause: Handle<Button>,
stop: Handle<Button>,
rewind: Handle<Button>,
time: Handle<ScrollBar>,
sounds_state: Vec<(Handle<Node>, Node)>,
}
fn make_button(text: &str, column: usize, ctx: &mut BuildContext) -> Handle<Button> {
ButtonBuilder::new(
WidgetBuilder::new()
.on_column(column)
.with_margin(Thickness::uniform(1.0)),
)
.with_text(text)
.build(ctx)
}
impl AudioPreviewPanel {
pub fn new(inspector_head: Handle<StackPanel>, ctx: &mut BuildContext) -> Self {
let preview;
let play;
let pause;
let stop;
let rewind;
let time;
let root_widget = GridBuilder::new(
WidgetBuilder::new()
.with_visibility(false)
.with_child(
GridBuilder::new(
WidgetBuilder::new()
.on_row(0)
.with_child({
preview = CheckBoxBuilder::new(
WidgetBuilder::new()
.with_vertical_alignment(VerticalAlignment::Center)
.with_margin(Thickness::uniform(1.0)),
)
.with_content(
TextBuilder::new(
WidgetBuilder::new()
.on_column(0)
.with_vertical_alignment(VerticalAlignment::Center),
)
.with_text("Preview")
.build(ctx),
)
.build(ctx);
preview
})
.with_child({
play = make_button("Play", 1, ctx);
play
})
.with_child({
pause = make_button("Pause", 2, ctx);
pause
})
.with_child({
stop = make_button("Stop", 3, ctx);
stop
})
.with_child({
rewind = make_button("Rewind", 4, ctx);
rewind
}),
)
.add_row(Row::stretch())
.add_column(Column::strict(80.0))
.add_column(Column::stretch())
.add_column(Column::stretch())
.add_column(Column::stretch())
.add_column(Column::stretch())
.build(ctx),
)
.with_child(
GridBuilder::new(
WidgetBuilder::new()
.on_row(1)
.with_child(
TextBuilder::new(
WidgetBuilder::new().with_margin(Thickness::uniform(1.0)),
)
.with_vertical_text_alignment(VerticalAlignment::Center)
.with_text("Time, s")
.build(ctx),
)
.with_child({
time = ScrollBarBuilder::new(
WidgetBuilder::new()
.on_column(1)
.with_margin(Thickness::uniform(1.0)),
)
.show_value(true)
.with_value_precision(2)
.with_min(0.0)
.build(ctx);
time
}),
)
.add_column(Column::auto())
.add_column(Column::stretch())
.add_row(Row::strict(26.0))
.build(ctx),
),
)
.add_column(Column::stretch())
.add_row(Row::stretch())
.add_row(Row::strict(26.0))
.build(ctx);
ctx.inner()
.send(root_widget, WidgetMessage::link_with(inspector_head));
Self {
root_widget,
preview,
play,
pause,
stop,
rewind,
time,
sounds_state: vec![],
}
}
pub fn handle_message(
&mut self,
message: &Message,
editor_selection: &Selection,
mut game_scene: Option<&mut GameScene>,
engine: &mut Engine,
) {
if let Some(game_scene) = game_scene.as_mut() {
if let Message::DoCommand(_)
| Message::UndoCurrentSceneCommand
| Message::RedoCurrentSceneCommand = message
{
self.leave_preview_mode(game_scene, engine);
}
}
if let Message::SelectionChanged { .. } = message {
let any_sound_selected = if let Some(game_scene) = game_scene {
let scene = &engine.scenes[game_scene.scene];
editor_selection.as_graph().is_some_and(|s| {
s.nodes()
.iter()
.any(|n| scene.graph.try_get_of_type::<Sound>(*n).is_ok())
})
} else {
false
};
engine.user_interfaces.first_mut().send(
self.root_widget,
WidgetMessage::Visibility(any_sound_selected),
);
}
}
fn enter_preview_mode(
&mut self,
editor_selection: &Selection,
game_scene: &mut GameScene,
engine: &mut Engine,
) {
assert!(self.sounds_state.is_empty());
let scene = &engine.scenes[game_scene.scene];
let node_overrides = game_scene.graph_switches.node_overrides.as_mut().unwrap();
let mut set = false;
if let Some(new_graph_selection) = editor_selection.as_graph() {
for &node_handle in &new_graph_selection.nodes {
if let Ok(sound) = scene.graph.try_get_of_type::<Sound>(node_handle) {
if !set {
if let Some(buffer) = sound.buffer() {
let mut state = buffer.state();
if let Some(buffer) = state.data() {
let duration_secs = buffer.duration().as_secs_f32();
engine.user_interfaces.first().send_sync_many(
self.time,
[
ScrollBarMessage::MaxValue(duration_secs),
ScrollBarMessage::Value(
sound.playback_time().clamp(0.0, duration_secs),
),
],
);
}
}
set = true;
}
self.sounds_state
.push((node_handle, scene.graph[node_handle].clone_box()));
assert!(node_overrides.insert(node_handle));
}
}
}
}
pub fn leave_preview_mode(&mut self, game_scene: &mut GameScene, engine: &mut Engine) {
let scene = &mut engine.scenes[game_scene.scene];
let node_overrides = game_scene.graph_switches.node_overrides.as_mut().unwrap();
for (sound_handle, original) in self.sounds_state.drain(..) {
scene.graph[sound_handle] = original;
assert!(node_overrides.remove(&sound_handle));
}
engine
.user_interfaces
.first()
.send_sync(self.preview, CheckBoxMessage::Check(Some(false)));
scene.graph.sound_context.state().destroy_sound_sources();
}
pub fn is_in_preview_mode(&self) -> bool {
!self.sounds_state.is_empty()
}
pub fn update(&self, editor_selection: &Selection, game_scene: &GameScene, engine: &Engine) {
let scene = &engine.scenes[game_scene.scene];
if let Some(new_graph_selection) = editor_selection.as_graph() {
for &node_handle in &new_graph_selection.nodes {
if let Ok(sound) = scene.graph.try_get_of_type::<Sound>(node_handle) {
engine
.user_interfaces
.first()
.send_sync(self.time, ScrollBarMessage::Value(sound.playback_time()));
break;
}
}
}
}
pub fn handle_ui_message(
&mut self,
message: &UiMessage,
editor_selection: &Selection,
game_scene: &mut GameScene,
engine: &mut Engine,
) {
if let Some(selection) = editor_selection.as_graph() {
if let Some(ButtonMessage::Click) = message.data() {
let scene = &mut engine.scenes[game_scene.scene];
for &node in &selection.nodes {
if let Ok(sound) = scene.graph.try_get_mut_of_type::<Sound>(node) {
if message.destination() == self.play {
sound.set_status(Status::Playing);
} else if message.destination() == self.pause {
sound.set_status(Status::Paused);
} else if message.destination() == self.stop {
sound.set_status(Status::Stopped);
} else if message.destination() == self.rewind {
sound.set_playback_time(0.0);
}
}
}
} else if let Some(CheckBoxMessage::Check(Some(value))) =
message.data_from(self.preview)
{
if *value {
self.enter_preview_mode(editor_selection, game_scene, engine);
} else {
self.leave_preview_mode(game_scene, engine);
}
} else if let Some(ScrollBarMessage::Value(playback_position)) =
message.data_from(self.time)
{
let scene = &mut engine.scenes[game_scene.scene];
for &node in &selection.nodes {
if let Ok(sound) = scene.graph.try_get_mut_of_type::<Sound>(node) {
sound.set_playback_time(*playback_position);
}
}
}
}
}
}