From 1e61685f6aed95b5de6db83658756056fde70cc9 Mon Sep 17 00:00:00 2001
From: Finn Bear <finnbearlabs@gmail.com>
Date: Sat, 30 Apr 2022 17:06:14 -0700
Subject: [PATCH] Improvements and reorganization.

---
 src/cartoon.rs                                |  10 ++--
 src/component.rs                              |   1 +
 .../example_list.rs}                          |  43 ++++++++++--------
 src/image/placeholder0.png                    | Bin 0 -> 5881 bytes
 src/image/placeholder1.png                    | Bin 0 -> 5881 bytes
 src/slide.rs                                  |   9 ++--
 src/slide/s5_emergence.rs                     |  33 ++++++++++++++
 src/slide/{s5_fractals.rs => s6_fractals.rs}  |  12 ++---
 .../{s5_fractals => s6_fractals}/README.md    |   0
 .../{s5_fractals => s6_fractals}/circle.rs    |   0
 .../mandelbrot.rs                             |   0
 .../{s5_fractals => s6_fractals}/rectangle.rs |   0
 src/slide/s7_computation.rs                   |  34 ++++++++++++++
 src/slide/{s7_mosaic.rs => s8_mosaic.rs}      |   0
 .../{s8_conclusion.rs => s9_conclusion.rs}    |   0
 15 files changed, 108 insertions(+), 34 deletions(-)
 rename src/{slide/s6_computation.rs => component/example_list.rs} (68%)
 create mode 100644 src/image/placeholder0.png
 create mode 100644 src/image/placeholder1.png
 create mode 100644 src/slide/s5_emergence.rs
 rename src/slide/{s5_fractals.rs => s6_fractals.rs} (96%)
 rename src/slide/{s5_fractals => s6_fractals}/README.md (100%)
 rename src/slide/{s5_fractals => s6_fractals}/circle.rs (100%)
 rename src/slide/{s5_fractals => s6_fractals}/mandelbrot.rs (100%)
 rename src/slide/{s5_fractals => s6_fractals}/rectangle.rs (100%)
 create mode 100644 src/slide/s7_computation.rs
 rename src/slide/{s7_mosaic.rs => s8_mosaic.rs} (100%)
 rename src/slide/{s8_conclusion.rs => s9_conclusion.rs} (100%)

diff --git a/src/cartoon.rs b/src/cartoon.rs
index f284212..9fada36 100644
--- a/src/cartoon.rs
+++ b/src/cartoon.rs
@@ -3,10 +3,11 @@ 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::s5_emergence::Emergence;
+use crate::slide::s6_fractals::Fractals;
+use crate::slide::s7_computation::Computation;
+use crate::slide::s8_mosaic::Mosaic;
+use crate::slide::s9_conclusion::Conclusion;
 use crate::slide::Slide;
 use eframe::egui::style::Margin;
 use eframe::egui::{Key, Style, TextStyle, Visuals};
@@ -58,6 +59,7 @@ fn create_slides() -> Vec<Box<dyn Slide>> {
         Box::new(Introduction::default()),
         Box::new(Complexity::default()),
         Box::new(Automata::default()),
+        Box::new(Emergence::default()),
         Box::new(Fractals::default()),
         Box::new(Computation::default()),
         Box::new(Mosaic::default()),
diff --git a/src/component.rs b/src/component.rs
index c72f31f..e0590fc 100644
--- a/src/component.rs
+++ b/src/component.rs
@@ -3,6 +3,7 @@
 
 pub mod arrow;
 pub mod code;
+pub mod example_list;
 pub mod grid;
 pub mod image;
 pub mod triangle;
diff --git a/src/slide/s6_computation.rs b/src/component/example_list.rs
similarity index 68%
rename from src/slide/s6_computation.rs
rename to src/component/example_list.rs
index 02c78bb..9e744fa 100644
--- a/src/slide/s6_computation.rs
+++ b/src/component/example_list.rs
@@ -1,19 +1,19 @@
 use crate::component::image::Image;
-use crate::ctx_img;
 use crate::egui::{Context, Frame, Ui};
 use crate::fade_in::{fade_in, fade_in_manual};
-use crate::slide::Slide;
 use eframe::egui::style::Margin;
 use eframe::egui::{Pos2, TextureHandle};
 
 #[derive(Default)]
-pub struct Computation {
-    /// Will fade in one by one.
-    examples: Vec<ComputationExample>,
+pub struct ExampleList {
+    /// Heading text.
+    title: &'static str,
+    /// Examples to show.
+    examples: Vec<Example>,
 }
 
 /// One bullet point and texture combination.
-struct ComputationExample {
+pub struct Example {
     /// Bullet point text.
     label: &'static str,
     /// Texture handle to render on the right side.
@@ -22,7 +22,7 @@ struct ComputationExample {
     fade_start: Option<f64>,
 }
 
-impl ComputationExample {
+impl Example {
     pub fn new(label: &'static str, texture: TextureHandle) -> Self {
         Self {
             label,
@@ -32,8 +32,15 @@ impl ComputationExample {
     }
 }
 
-impl Slide for Computation {
-    fn transition(&mut self, ctx: &Context) -> bool {
+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.
@@ -44,24 +51,20 @@ impl Slide for Computation {
         true
     }
 
-    fn show(&mut self, ui: &mut Ui) {
+    /// 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() {
-            // For now, these images are somewhat like placeholders.
-            self.examples = vec![
-                ComputationExample::new("Raytracing", ctx_img!(ui.ctx(), "raytracing0.png")),
-                ComputationExample::new("Raymarching", ctx_img!(ui.ctx(), "raymarching1.png")),
-                ComputationExample::new("Particle simulation", ctx_img!(ui.ctx(), "atom0.png")),
-                ComputationExample::new("Fluid simulation", ctx_img!(ui.ctx(), "fluid0.png")),
-            ]
+            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("More Computation-based Art");
+            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 {
@@ -70,9 +73,9 @@ impl Slide for Computation {
                     });
                     fade_in_manual(ui, fade_start, |ui, alpha| {
                         let position = Pos2::new(
-                            (window_width_per_image - IMAGE_SCALE) * 0.5
+                            aspect_ratio_gap
                                 + window_width * (i as f32) / self.examples.len() as f32,
-                            window_height - IMAGE_SCALE * 1.1,
+                            window_height - IMAGE_SCALE - aspect_ratio_gap,
                         );
                         Image::default()
                             .height(IMAGE_SCALE)
diff --git a/src/image/placeholder0.png b/src/image/placeholder0.png
new file mode 100644
index 0000000000000000000000000000000000000000..9e8c2b9db3de79d3c2d8b0b059be597579860205
GIT binary patch
literal 5881
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

literal 0
HcmV?d00001

diff --git a/src/image/placeholder1.png b/src/image/placeholder1.png
new file mode 100644
index 0000000000000000000000000000000000000000..9e8c2b9db3de79d3c2d8b0b059be597579860205
GIT binary patch
literal 5881
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

literal 0
HcmV?d00001

diff --git a/src/slide.rs b/src/slide.rs
index 2151fb9..1241c6a 100644
--- a/src/slide.rs
+++ b/src/slide.rs
@@ -6,10 +6,11 @@ pub mod s1_title;
 pub mod s2_introduction;
 pub mod s3_complexity;
 pub mod s4_automata;
-pub mod s5_fractals;
-pub mod s6_computation;
-pub mod s7_mosaic;
-pub mod s8_conclusion;
+pub mod s5_emergence;
+pub mod s6_fractals;
+pub mod s7_computation;
+pub mod s8_mosaic;
+pub mod s9_conclusion;
 
 /// An interface for all slides.
 pub trait Slide {
diff --git a/src/slide/s5_emergence.rs b/src/slide/s5_emergence.rs
new file mode 100644
index 0000000..1fe26e6
--- /dev/null
+++ b/src/slide/s5_emergence.rs
@@ -0,0 +1,33 @@
+use crate::component::example_list::{Example, ExampleList};
+use crate::ctx_img;
+use crate::egui::{Context, Ui};
+use crate::slide::Slide;
+
+pub struct Emergence {
+    inner: ExampleList,
+}
+
+impl Default for Emergence {
+    fn default() -> Self {
+        Self {
+            inner: ExampleList::new("More Emergence-based Art"),
+        }
+    }
+}
+
+impl Slide for Emergence {
+    fn transition(&mut self, ctx: &Context) -> bool {
+        self.inner.transition(ctx)
+    }
+
+    fn show(&mut self, ui: &mut Ui) {
+        let ctx = ui.ctx().clone();
+        self.inner.show(ui, || {
+            vec![
+                Example::new("Langton's ant", ctx_img!(ctx, "placeholder0.png")),
+                Example::new("Flocking simulation", ctx_img!(ctx, "placeholder1.png")),
+                Example::new("Slime mold simulation", ctx_img!(ctx, "slime0.png")),
+            ]
+        });
+    }
+}
diff --git a/src/slide/s5_fractals.rs b/src/slide/s6_fractals.rs
similarity index 96%
rename from src/slide/s5_fractals.rs
rename to src/slide/s6_fractals.rs
index 806221a..3fd9221 100644
--- a/src/slide/s5_fractals.rs
+++ b/src/slide/s6_fractals.rs
@@ -10,9 +10,9 @@ use crate::egui::{Color32, Context, Frame, Ui};
 use crate::fade_in::{fade_in_manual, fade_out_manual};
 use crate::governor::Governor;
 use crate::slide::s4_automata::randomize_grid;
-use crate::slide::s5_fractals::circle::circle;
-use crate::slide::s5_fractals::mandelbrot::mandelbrot;
-use crate::slide::s5_fractals::rectangle::rectangle;
+use crate::slide::s6_fractals::circle::circle;
+use crate::slide::s6_fractals::mandelbrot::mandelbrot;
+use crate::slide::s6_fractals::rectangle::rectangle;
 use crate::slide::Slide;
 use eframe::egui::style::Margin;
 use eframe::egui::{Align2, Vec2};
@@ -172,17 +172,17 @@ impl Slide for Fractals {
                 // No-op (arrows are rendered below).
             }
             FractalsState::Rectangle { pixels } => {
-                self.code.code = pseudocode(include_str!("s5_fractals/rectangle.rs"));
+                self.code.code = pseudocode(include_str!("s6_fractals/rectangle.rs"));
                 algo = Some(&rectangle);
                 limit_pixels = Some(pixels)
             }
             FractalsState::Circle { pixels } => {
-                self.code.code = pseudocode(include_str!("s5_fractals/circle.rs"));
+                self.code.code = pseudocode(include_str!("s6_fractals/circle.rs"));
                 algo = Some(&circle);
                 limit_pixels = Some(pixels);
             }
             FractalsState::Mandelbrot { pixels } => {
-                self.code.code = pseudocode(include_str!("s5_fractals/mandelbrot.rs"));
+                self.code.code = pseudocode(include_str!("s6_fractals/mandelbrot.rs"));
                 algo = Some(&mandelbrot);
                 limit_pixels = Some(pixels);
             }
diff --git a/src/slide/s5_fractals/README.md b/src/slide/s6_fractals/README.md
similarity index 100%
rename from src/slide/s5_fractals/README.md
rename to src/slide/s6_fractals/README.md
diff --git a/src/slide/s5_fractals/circle.rs b/src/slide/s6_fractals/circle.rs
similarity index 100%
rename from src/slide/s5_fractals/circle.rs
rename to src/slide/s6_fractals/circle.rs
diff --git a/src/slide/s5_fractals/mandelbrot.rs b/src/slide/s6_fractals/mandelbrot.rs
similarity index 100%
rename from src/slide/s5_fractals/mandelbrot.rs
rename to src/slide/s6_fractals/mandelbrot.rs
diff --git a/src/slide/s5_fractals/rectangle.rs b/src/slide/s6_fractals/rectangle.rs
similarity index 100%
rename from src/slide/s5_fractals/rectangle.rs
rename to src/slide/s6_fractals/rectangle.rs
diff --git a/src/slide/s7_computation.rs b/src/slide/s7_computation.rs
new file mode 100644
index 0000000..9802ef5
--- /dev/null
+++ b/src/slide/s7_computation.rs
@@ -0,0 +1,34 @@
+use crate::component::example_list::{Example, ExampleList};
+use crate::ctx_img;
+use crate::egui::{Context, Ui};
+use crate::slide::Slide;
+
+pub struct Computation {
+    inner: ExampleList,
+}
+
+impl Default for Computation {
+    fn default() -> Self {
+        Self {
+            inner: ExampleList::new("More Computation-based Art"),
+        }
+    }
+}
+
+impl Slide for Computation {
+    fn transition(&mut self, ctx: &Context) -> bool {
+        self.inner.transition(ctx)
+    }
+
+    fn show(&mut self, ui: &mut Ui) {
+        let ctx = ui.ctx().clone();
+        self.inner.show(ui, || {
+            vec![
+                Example::new("Raytracing", ctx_img!(ctx, "raytracing0.png")),
+                Example::new("Raymarching", ctx_img!(ctx, "raymarching1.png")),
+                Example::new("Particle simulation", ctx_img!(ctx, "atom0.png")),
+                Example::new("Fluid simulation", ctx_img!(ctx, "fluid0.png")),
+            ]
+        });
+    }
+}
diff --git a/src/slide/s7_mosaic.rs b/src/slide/s8_mosaic.rs
similarity index 100%
rename from src/slide/s7_mosaic.rs
rename to src/slide/s8_mosaic.rs
diff --git a/src/slide/s8_conclusion.rs b/src/slide/s9_conclusion.rs
similarity index 100%
rename from src/slide/s8_conclusion.rs
rename to src/slide/s9_conclusion.rs
-- 
GitLab