gled-ui 2.30.1

gled's egui interface, shared by the desktop app and the browser
Documentation
use crate::ui::effect::EffectUi;
use crate::{pipeline::thumbnails::ThumbnailTextures, ui::effect::widget::EffectWidget};
use egui::{Button, Color32, Ui, Vec2};
use gled_model::{
    asset::{
        group::Groups,
        scene::{Scene, effect::Effect},
    },
    collection::Collections,
};
use gled_protocol::state::SoundSnapshot;
use uuid::Uuid;

#[derive(Default, Debug)]
pub(crate) struct SceneEffectEditorState {
    pub(crate) selected_effect: usize,
}

impl SceneEffectEditorState {
    pub(crate) fn reset(&mut self) {
        self.selected_effect = 0;
    }

    pub(crate) fn clamp(&mut self, effect_count: usize) {
        if effect_count == 0 {
            self.selected_effect = 0;
        } else {
            self.selected_effect = self.selected_effect.min(effect_count - 1);
        }
    }
}

/// `owner` and `textures` locate the thumbnails of the scene's effects.
pub(crate) fn selected_effect_editor_ui(
    ui: &mut Ui,
    scene: &mut Scene,
    owner: Uuid,
    textures: &ThumbnailTextures,
    state: &mut SceneEffectEditorState,
    allow_animation_change: bool,
    svg: Option<egui::TextureHandle>,
    beat_progression: f32,
    collections: &mut Collections,
    sound_data: &SoundSnapshot,
) -> bool {
    state.clamp(scene.effects().len());

    let mut changed = false;
    if let Some(effect) = scene.effect(state.selected_effect) {
        changed |= effect.config_ui(
            ui,
            textures.texture_id(&(owner, state.selected_effect)),
            None,
            allow_animation_change,
            svg,
            beat_progression,
            collections,
            sound_data,
        );
    }

    ui.separator();

    ui.vertical_centered_justified(|ui| {
        if ui
            .add(Button::new("+ Add Animation").fill(Color32::DARK_GREEN))
            .clicked()
        {
            state.selected_effect = scene.add_effect(Effect::default());
            changed = true;
        }
    });
    ui.vertical_centered_justified(|ui| {
        if ui
            .add(Button::new("🗐 Duplicate Animation").fill(Color32::DARK_BLUE))
            .clicked()
            && let Some(effect) = scene.effect(state.selected_effect).cloned()
        {
            state.selected_effect = scene.add_effect(effect);
            changed = true;
        }
    });
    ui.vertical_centered_justified(|ui| {
        if ui
            .add(Button::new("🗑 Remove Animation").fill(Color32::DARK_RED))
            .clicked()
        {
            scene.remove_effect(state.selected_effect);
            state.selected_effect = state.selected_effect.saturating_sub(1);
            state.clamp(scene.effects().len());
            changed = true;
        }
    });

    changed
}

pub(crate) fn scene_effect_list_ui(
    ui: &mut Ui,
    scene: &Scene,
    owner: Uuid,
    textures: &ThumbnailTextures,
    state: &mut SceneEffectEditorState,
    show_group: bool,
    svg: Option<egui::TextureHandle>,
    groups: Option<&Groups>,
    groups_show_index: bool,
    beat_progression: Option<f32>,
    collections: &mut Collections,
    sound_data: &SoundSnapshot,
) {
    state.clamp(scene.effects().len());

    ui.horizontal_wrapped(|ui| {
        for (index, effect) in scene.effects().iter().enumerate() {
            ui.add_sized(
                Vec2::splat(100.0),
                EffectWidget {
                    show_group,
                    selectable: Some((&mut state.selected_effect, index)),
                    effect,
                    thumbnail: textures.texture_id(&(owner, index)),
                    svg: svg.clone(),
                    groups,
                    groups_show_index,
                    beat_progression,
                    collections,
                    sound_data,
                },
            );
        }
    });
}