pub(crate) mod widget;
use crate::app::controller_feedback;
use crate::ui::animation_editor::AnimationUi;
use crate::ui::asset::CollectionsChangeButton;
use crate::ui::layout_selection::inherited_selection_button;
use crate::ui::multiplied_curve::MultipliedCurveUi;
use egui::{Slider, TextureId};
use gled_model::patching::Patch;
use gled_model::{
asset::{
Asset, animation::Animation, midi_controller::MidiEffectParameter, scene::effect::Effect,
},
collection::Collections,
};
use gled_protocol::state::SoundSnapshot;
use std::sync::Arc;
pub(crate) trait EffectUi {
fn config_ui(
&mut self,
ui: &mut egui::Ui,
thumbnail: Option<TextureId>,
animation_overwrite: Option<&Arc<Asset<Animation>>>,
allow_animation_change: bool,
patch: &Patch,
beat_progression: f32,
collections: &mut Collections,
sound_data: &SoundSnapshot,
) -> bool;
}
impl EffectUi for Effect {
fn config_ui(
&mut self,
ui: &mut egui::Ui,
thumbnail: Option<TextureId>,
animation_overwrite: Option<&Arc<Asset<Animation>>>,
allow_animation_change: bool,
patch: &Patch,
beat_progression: f32,
collections: &mut Collections,
sound_data: &SoundSnapshot,
) -> bool {
let mut changed = false;
if allow_animation_change {
ui.label("Animation");
ui.vertical_centered_justified(|ui| {
changed |= self.animation.collections_change_button(ui, collections);
});
}
ui.label("Progression");
let response = ui.vertical_centered_justified(|ui| {
changed |=
self.beat_progression
.change_button(ui, beat_progression, collections, sound_data);
});
outline_if_touched(
ui,
MidiEffectParameter::BeatProgression,
response.response.rect,
);
let mut beat_progression = beat_progression;
beat_progression +=
self.beat_progression_offset
.value(beat_progression, collections, sound_data);
ui.label("Colorshift");
let response = ui.vertical_centered_justified(|ui| {
changed |=
self.color_shift
.change_button(ui, beat_progression, collections, sound_data);
});
outline_if_touched(ui, MidiEffectParameter::ColorShift, response.response.rect);
ui.label("Opacity");
let response = ui.vertical_centered_justified(|ui| {
changed |= self
.opacity
.change_button(ui, beat_progression, collections, sound_data);
});
outline_if_touched(ui, MidiEffectParameter::Opacity, response.response.rect);
ui.label("Beat offset");
let response = ui.vertical_centered_justified(|ui| {
changed |= self.beat_progression_offset.change_button(
ui,
beat_progression,
collections,
sound_data,
);
});
outline_if_touched(ui, MidiEffectParameter::BeatOffset, response.response.rect);
ui.label("Speed");
ui.horizontal(|ui| {
ui.spacing_mut().slider_width = ui.available_width() - 60.0;
changed |= ui
.add(
Slider::new(&mut self.speed_exponent, -8..=8)
.step_by(1.0)
.custom_formatter(|n, _| {
format!(
"{} x",
if n > 0.0 {
2i32.pow(n as u32).to_string()
} else if n > -0.1 {
"1".to_string()
} else {
format!("1/{}", 2i32.pow((-n) as u32))
}
)
})
.custom_parser(|s| {
let s = s.split(' ').next().unwrap_or(s);
let s = s.strip_suffix('x').unwrap_or(s);
let n = if let Some(n) =
s.strip_prefix("1/").and_then(|s| s.parse::<f32>().ok())
{
1f32 / n
} else {
s.parse::<f32>().ok()?
};
Some(n.log2() as f64)
}),
)
.changed();
});
if let Some(animation) = animation_overwrite
.cloned()
.or_else(|| self.animation.and_then(|id| Asset::get(id, collections)))
&& let Some(rendered) = thumbnail
{
changed |= animation.data.config_ui(
&mut self.animation_config,
ui,
rendered,
None,
beat_progression,
collections,
sound_data,
);
}
ui.separator();
ui.label("Layout");
ui.vertical_centered_justified(|ui| {
changed |= inherited_selection_button(ui, patch, &mut self.selection);
});
changed
}
}
pub(crate) fn outline_if_touched(ui: &egui::Ui, parameter: MidiEffectParameter, rect: egui::Rect) {
if controller_feedback::shown_effect_touched(ui.ctx(), parameter) {
controller_feedback::outline_touched(ui, rect);
}
}