Skip to content
Snippets Groups Projects
example_list.rs 2.90 KiB
use crate::component::image::Image;
use crate::egui::{Context, Frame, Ui};
use crate::fade_in::{fade_in, fade_in_manual};
use eframe::egui::style::Margin;
use eframe::egui::{Pos2, TextureHandle};

#[derive(Default)]
pub struct ExampleList {
    /// Heading text.
    title: &'static str,
    /// Examples to show.
    examples: Vec<Example>,
}

/// One bullet point and texture combination.
pub struct Example {
    /// Bullet point text.
    label: &'static str,
    /// Texture handle to render on the right side.
    texture: TextureHandle,
    /// When we started fading it ([`None`] if we haven't started yet).
    fade_start: Option<f64>,
}

impl Example {
    pub fn new(label: &'static str, texture: TextureHandle) -> Self {
        Self {
            label,
            texture,
            fade_start: None,
        }
    }
}

impl ExampleList {
    pub fn new(title: &'static str) -> Self {
        Self {
            title,
            examples: Vec::new(),
        }
    }

    pub fn transition(&mut self, ctx: &Context) -> bool {
        for example in &mut self.examples {
            if example.fade_start.is_none() {
                // If any image has not yet started fading in, fade it in and don't go to next slide.
                example.fade_start = Some(ctx.input().time);
                return false;
            }
        }
        true
    }

    /// Will call setter function once to populate examples.
    pub fn show(&mut self, ui: &mut Ui, setter: impl FnOnce() -> Vec<Example>) {
        if self.examples.is_empty() {
            self.examples = setter();
        }

        const IMAGE_SCALE: f32 = 256.0;
        let window_width = ui.available_width();
        let window_height = ui.available_height();
        let window_width_per_image = window_width / self.examples.len() as f32;
        let aspect_ratio_gap = (window_width_per_image - IMAGE_SCALE) * 0.5;

        Frame::none().margin(Margin::same(20.0)).show(ui, |ui| {
            ui.heading(self.title);
            ui.add_space(8.0);
            for (i, example) in self.examples.iter().enumerate() {
                if let Some(fade_start) = example.fade_start {
                    fade_in(ui, fade_start, |ui| {
                        ui.label(format!(" ⏵ {}", example.label));
                    });
                    fade_in_manual(ui, fade_start, |ui, alpha| {
                        let position = Pos2::new(
                            aspect_ratio_gap
                                + window_width * (i as f32) / self.examples.len() as f32,
                            window_height - IMAGE_SCALE - aspect_ratio_gap,
                        );
                        Image::default()
                            .height(IMAGE_SCALE)
                            .position(position)
                            .alpha(alpha)
                            .show(ui, &example.texture);
                    });
                }
            }
        });
    }
}