gled-ui 2.30.1

gled's egui interface, shared by the desktop app and the browser
Documentation
//! How assets look in asset trees and pickers.

use gled_protocol::assets::KnownAsset;
use std::sync::Arc;

use egui::{
    Color32, Mesh, Rect, Shape, Vec2,
    epaint::{Vertex, WHITE_UV},
};

use crate::ui::{color::ToColor32, curve_editor::CurveEditor, pills::show_pills};
use gled_model::asset::{
    animation::Animation, curve::Curve, midi_controller::MidiController,
    output_device::OutputDevice, palette::Palette, project::Project, scene::Scene,
};

/// An asset kind the UI can list. `show` draws a small preview at the right
/// end of `rect`; most kinds have none.
pub(crate) trait AssetUi: KnownAsset {
    fn show(&self, ui: &mut egui::Ui, rect: Rect) {
        let _ = (ui, rect);
    }
}

impl AssetUi for Animation {}
impl AssetUi for MidiController {}
impl AssetUi for OutputDevice {}
impl AssetUi for Project {}

impl AssetUi for Curve {
    fn show(&self, ui: &mut egui::Ui, rect: Rect) {
        let mut min = rect.min;
        min.x = rect.max.x - 64.0;
        let rect = Rect::from_min_max(min, rect.max);

        let mut curve = self.clone();
        curve.draw_curve(ui, false, None, rect);
    }
}

impl AssetUi for Palette {
    fn show(&self, ui: &mut egui::Ui, rect: Rect) {
        let mesh = {
            const COLOR_GRADIENT_RATIO: f32 = 0.35;
            const GAP: f32 = 2.0;
            const BORDER: f32 = 1.0;
            const HEIGHT: f32 = 18.0;
            let available_width = rect.width() - GAP - 4.0 * BORDER;
            let color_width = available_width * COLOR_GRADIENT_RATIO;
            let gradient_with: f32 = available_width - color_width;
            let width_per_gradient_color = gradient_with / 16.0;
            let start_pos = rect.right_center();

            let mut mesh = Mesh::default();
            mesh.add_colored_rect(
                Rect::from_min_max(
                    start_pos
                        - Vec2::new(
                            BORDER + color_width + BORDER + GAP + BORDER + gradient_with + BORDER,
                            HEIGHT / 2.0,
                        ),
                    start_pos - Vec2::new(GAP + BORDER + gradient_with + BORDER, -HEIGHT / 2.0),
                ),
                Color32::BLACK,
            );
            let index = mesh.vertices.len() as u32;
            mesh.add_triangle(index, index + 1, index + 2);
            mesh.add_triangle(index + 3, index + 4, index + 5);
            let primary_color = self.primary.color32();
            // Top left
            mesh.vertices.push(Vertex {
                pos: start_pos
                    - Vec2::new(
                        color_width + BORDER + GAP + BORDER + gradient_with + BORDER,
                        HEIGHT / 2.0 - BORDER,
                    ),
                uv: WHITE_UV,
                color: primary_color,
            });
            // Top right
            mesh.vertices.push(Vertex {
                pos: start_pos
                    - Vec2::new(
                        BORDER + GAP + BORDER + gradient_with + BORDER,
                        HEIGHT / 2.0 - BORDER,
                    ),
                uv: WHITE_UV,
                color: primary_color,
            });
            // Bottom left
            mesh.vertices.push(Vertex {
                pos: start_pos
                    - Vec2::new(
                        color_width + BORDER + GAP + BORDER + gradient_with + BORDER,
                        -HEIGHT / 2.0 + BORDER,
                    ),
                uv: WHITE_UV,
                color: primary_color,
            });
            let secondary_color = self.secondary.color32();
            // Top right
            mesh.vertices.push(Vertex {
                pos: start_pos
                    - Vec2::new(
                        BORDER + GAP + BORDER + gradient_with + BORDER,
                        HEIGHT / 2.0 - BORDER,
                    ),
                uv: WHITE_UV,
                color: secondary_color,
            });
            // Bottom left
            mesh.vertices.push(Vertex {
                pos: start_pos
                    - Vec2::new(
                        color_width + BORDER + GAP + BORDER + gradient_with + BORDER,
                        -HEIGHT / 2.0 + BORDER,
                    ),
                uv: WHITE_UV,
                color: secondary_color,
            });
            // Bottom right
            mesh.vertices.push(Vertex {
                pos: start_pos
                    - Vec2::new(
                        BORDER + GAP + BORDER + gradient_with + BORDER,
                        -HEIGHT / 2.0 + BORDER,
                    ),
                uv: WHITE_UV,
                color: secondary_color,
            });
            // Gradient background
            mesh.add_colored_rect(
                Rect::from_min_max(
                    start_pos - Vec2::new(BORDER + gradient_with + BORDER, HEIGHT / 2.0),
                    start_pos - Vec2::new(BORDER, -HEIGHT / 2.0),
                ),
                Color32::BLACK,
            );
            // Gradient colors
            for (i, color) in self.gradient.into_iter().rev().enumerate() {
                mesh.add_colored_rect(
                    Rect::from_min_max(
                        start_pos
                            - Vec2::new(
                                width_per_gradient_color * (i + 1) as f32 + BORDER,
                                HEIGHT / 2.0 - BORDER,
                            ),
                        start_pos
                            - Vec2::new(
                                width_per_gradient_color * i as f32 + BORDER,
                                -HEIGHT / 2.0 + BORDER,
                            ),
                    ),
                    color.color32(),
                );
            }

            mesh
        };
        ui.painter().add(Shape::Mesh(Arc::new(mesh)));
    }
}

impl AssetUi for Scene {
    fn show(&self, ui: &mut egui::Ui, rect: egui::Rect) {
        show_pills(
            ui,
            rect.right_top() + Vec2::new(0.0, 1.0),
            self.group_indices()
                .into_iter()
                .map(|index| (index.to_string(), Color32::GOLD))
                .collect(),
        );
    }
}