#![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); }); } }