Skip to content
Snippets Groups Projects
main.rs 4.44 KiB
#![feature(derive_default_enum)]
#![feature(mixed_integer_ops)]

pub mod component;
pub mod governor;
pub mod image;
pub mod slide;

use crate::slide::s1_title::Title;
use crate::slide::s2_introduction::Introduction;
use crate::slide::s3_complexity::Complexity;
use crate::slide::s4_automata::Automata;
use crate::slide::s5_fractals::Fractals;
use crate::slide::s6_computation::Computation;
use crate::slide::s7_mosaic::Mosaic;
use crate::slide::s8_conclusion::Conclusion;
use crate::slide::Slide;
use eframe::egui::style::Margin;
use eframe::egui::{Key, Style, TextStyle, Visuals};
use eframe::epi::{Frame, Storage};
use eframe::{egui, epi};

fn main() {
    let app = Cartoon::default();

    let size = egui::Vec2::new(1280f32, 720f32);

    let native_options = eframe::NativeOptions {
        always_on_top: false,
        maximized: false,
        decorated: true,
        drag_and_drop_support: false,
        icon_data: None,
        initial_window_pos: None,
        initial_window_size: None,
        min_window_size: Some(size),
        max_window_size: Some(size),
        resizable: false,
        transparent: false,
    };

    eframe::run_native(Box::new(app), native_options);
}

pub struct Cartoon {
    slides: Vec<Box<dyn Slide>>,
    slide_index: usize,
}

impl Default for Cartoon {
    fn default() -> Self {
        Self {
            slides: create_slides(),
            slide_index: 0,
        }
    }
}

fn create_slides() -> Vec<Box<dyn Slide>> {
    vec![
        Box::new(Title::default()) as Box<dyn Slide>,
        Box::new(Introduction::default()),
        Box::new(Complexity::default()),
        Box::new(Automata::default()),
        Box::new(Fractals::default()),
        Box::new(Computation::default()),
        Box::new(Mosaic::default()),
        Box::new(Conclusion::default()),
    ]
}

impl epi::App for Cartoon {
    fn name(&self) -> &str {
        "Generative Art Cartoon"
    }

    fn setup(&mut self, ctx: &egui::Context, _frame: &Frame, _storage: Option<&dyn Storage>) {
        let mut style = Style::default();
        style.animation_time = 0.5;
        style.visuals = Visuals::light();
        style.spacing.window_margin = Margin::same(24.0);
        {
            let header_style = style.text_styles.get_mut(&TextStyle::Heading).unwrap();
            header_style.size = 48.0;
        }
        {
            let body_style = style.text_styles.get_mut(&TextStyle::Body).unwrap();
            body_style.size = 30.0;
        }
        {
            let small_style = style.text_styles.get_mut(&TextStyle::Small).unwrap();
            small_style.size = 22.0;
        }
        /*
        {
            let monospaced_style = style.text_styles.get_mut(&TextStyle::Monospace).unwrap();
            monospaced_style.size = 22.0;
        }
         */
        ctx.set_style(style);
    }

    /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`.
    fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
        // For inspiration and more examples, go to https://emilk.github.io/egui

        /*
        egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
            egui::menu::bar(ui, |ui| {
                ui.menu_button("File", |ui| {
                    if ui.button("Quit").clicked() {
                        frame.quit();
                    }
                });
            });
        });
         */

        let force_advance =
            ctx.input().key_pressed(Key::ArrowRight) || ctx.input().key_pressed(Key::D);
        let advance = force_advance || ctx.input().key_pressed(Key::Space);
        let retreat = ctx.input().key_pressed(Key::ArrowLeft) || ctx.input().key_pressed(Key::A);

        if advance || retreat {
            self.slide_index = if advance {
                if force_advance || self.slides[self.slide_index].transition(ctx) {
                    let new = (self.slide_index + 1) % self.slides.len();
                    if new == 0 {
                        self.slides = create_slides();
                    }
                    ctx.request_repaint();
                    new
                } else {
                    self.slide_index
                }
            } else {
                ctx.request_repaint();
                self.slide_index
                    .checked_sub(1)
                    .unwrap_or(self.slides.len() - 1)
            };
        }

        egui::CentralPanel::default().show(ctx, |ui| {
            self.slides[self.slide_index].show(ui, ctx);
        });
    }
}