Skip to content
Snippets Groups Projects
Commit ffa12275 authored by Finn Bear's avatar Finn Bear
Browse files

Axes arrows for fractal slide.

parent a1075bd1
No related branches found
No related tags found
No related merge requests found
use crate::egui::{Align2, Pos2, Stroke, Ui};
use eframe::egui::{Color32, FontFamily, FontId, Shape};
use eframe::egui::{Color32, FontFamily, FontId, Shape, Vec2};
use eframe::emath::Rot2;
use std::cmp::Ordering;
/// Pointy line used to emphasize something.
#[must_use = "must call show"]
pub struct Arrow {
/// Where arrow originates from.
pub origin: Pos2,
/// Where arrow points.
pub tip: Pos2,
/// Color of arrow and (optional) label.
pub stroke: Color32,
/// Width of arrow.
pub stroke_width: f32,
/// Optional text to display at origin of arrow.
pub label: String,
/// Put label at tip instead of at origin.
pub label_at_tip: bool,
/// Override alignment of label text.
pub label_align: Option<Align2>,
/// Offset position of label text.
pub label_offset: Vec2,
/// Font size of label.
pub font_size: f32,
}
......@@ -22,6 +34,9 @@ impl Default for Arrow {
stroke: Color32::BLACK,
stroke_width: 6.0,
label: String::new(),
label_at_tip: false,
label_align: None,
label_offset: Vec2::ZERO,
font_size: 40.0,
}
}
......@@ -47,19 +62,26 @@ impl Arrow {
stroke,
));
if !self.label.is_empty() {
let align = match (vector.x.total_cmp(&0.0), vector.y.total_cmp(&0.0)) {
(Ordering::Less, Ordering::Less) => Align2::LEFT_TOP,
(Ordering::Less, Ordering::Equal) => Align2::LEFT_CENTER,
(Ordering::Less, Ordering::Greater) => Align2::LEFT_BOTTOM,
(Ordering::Equal, Ordering::Less) => Align2::CENTER_TOP,
(Ordering::Equal, Ordering::Equal) => Align2::CENTER_CENTER,
(Ordering::Equal, Ordering::Greater) => Align2::CENTER_BOTTOM,
(Ordering::Greater, Ordering::Less) => Align2::RIGHT_TOP,
(Ordering::Greater, Ordering::Equal) => Align2::RIGHT_CENTER,
(Ordering::Greater, Ordering::Greater) => Align2::RIGHT_BOTTOM,
};
let position = if self.label_at_tip {
self.tip
} else {
self.origin
} + self.label_offset;
let align = self.label_align.unwrap_or_else(|| {
match (vector.x.total_cmp(&0.0), vector.y.total_cmp(&0.0)) {
(Ordering::Less, Ordering::Less) => Align2::LEFT_TOP,
(Ordering::Less, Ordering::Equal) => Align2::LEFT_CENTER,
(Ordering::Less, Ordering::Greater) => Align2::LEFT_BOTTOM,
(Ordering::Equal, Ordering::Less) => Align2::CENTER_TOP,
(Ordering::Equal, Ordering::Equal) => Align2::CENTER_CENTER,
(Ordering::Equal, Ordering::Greater) => Align2::CENTER_BOTTOM,
(Ordering::Greater, Ordering::Less) => Align2::RIGHT_TOP,
(Ordering::Greater, Ordering::Equal) => Align2::RIGHT_CENTER,
(Ordering::Greater, Ordering::Greater) => Align2::RIGHT_BOTTOM,
}
});
ui.painter().text(
self.origin,
position,
align,
self.label.as_str(),
FontId::new(self.font_size, FontFamily::Proportional),
......
......@@ -3,6 +3,7 @@ mod mandelbrot;
mod rectangle;
use crate::color::set_alpha;
use crate::component::arrow::Arrow;
use crate::component::code::{pseudocode, Code};
use crate::component::grid::Grid;
use crate::egui::{Color32, Context, Frame, Ui};
......@@ -14,6 +15,7 @@ use crate::slide::s5_fractals::mandelbrot::mandelbrot;
use crate::slide::s5_fractals::rectangle::rectangle;
use crate::slide::Slide;
use eframe::egui::style::Margin;
use eframe::egui::{Align2, Vec2};
/// Mandelbrot, etc.
pub struct Fractals {
......@@ -43,6 +45,11 @@ enum FractalsState {
/// When we started fading out the dots.
fade_start: f64,
},
/// Fade in axes.
Axes {
/// When we started fading in the axes.
fade_start: f64,
},
Rectangle {
/// How many pixels of the grid we've filled in.
pixels: usize,
......@@ -105,7 +112,12 @@ impl Slide for Fractals {
fade_start: ctx.input().time,
};
}
FractalsState::Erase { .. } => self.state = FractalsState::Rectangle { pixels: 0 },
FractalsState::Erase { .. } => {
self.state = FractalsState::Axes {
fade_start: ctx.input().time,
}
}
FractalsState::Axes { .. } => self.state = FractalsState::Rectangle { pixels: 0 },
FractalsState::Rectangle { .. } => self.state = FractalsState::Circle { pixels: 0 },
FractalsState::Circle { .. } => self.state = FractalsState::Mandelbrot { pixels: 0 },
FractalsState::Mandelbrot { .. } => return true,
......@@ -128,7 +140,7 @@ impl Slide for Fractals {
//
// Note that we use indirection via a reference but not a heap-allocated [`Box`]. We can get
// away with that since the function doesn't leave our stack frame.
let algo: Option<&dyn Fn(f32, f32) -> bool>;
let mut algo: Option<&dyn Fn(f32, f32) -> bool> = None;
// Limit to this many pixels. If [`None`], will render all pixels.
// We use a mutable reference so we can increment in one place.
......@@ -145,7 +157,6 @@ impl Slide for Fractals {
self.code.alpha = alpha;
self.grid.alpha = alpha;
});
algo = None;
}
&mut FractalsState::Erase { fade_start } => {
fade_out_manual(ui, fade_start, |_, alpha| {
......@@ -156,7 +167,9 @@ impl Slide for Fractals {
}
}
});
algo = None;
}
&mut FractalsState::Axes { .. } => {
// No-op (arrows are rendered below).
}
FractalsState::Rectangle { pixels } => {
self.code.code = pseudocode(include_str!("s5_fractals/rectangle.rs"));
......@@ -215,6 +228,39 @@ impl Slide for Fractals {
}
self.code.show(ui.ctx());
self.grid.show(ui.ctx());
self.grid.show_with_overlays(ui.ctx(), |ui, to_screen| {
if let &FractalsState::Axes { fade_start } = &self.state {
fade_in_manual(ui, fade_start, |ui, alpha| {
let color = set_alpha(Color32::BLACK, alpha);
let middle = self.grid.size_cells / 2;
Arrow {
origin: to_screen * self.grid.center(middle, middle),
tip: to_screen * self.grid.center(self.grid.size_cells - 1, middle),
stroke: color,
label: "x".into(),
label_at_tip: true,
label_align: Some(Align2::CENTER_CENTER),
label_offset: Vec2::new(-20.0, 10.0),
stroke_width: 4.0,
font_size: 25.0,
..Arrow::default()
}
.show(ui);
Arrow {
origin: to_screen * self.grid.center(middle, middle),
tip: to_screen * self.grid.center(middle, 0),
stroke: color,
label: "y".into(),
label_at_tip: true,
label_align: Some(Align2::CENTER_CENTER),
label_offset: Vec2::new(-10.0, 20.0),
stroke_width: 4.0,
font_size: 25.0,
..Arrow::default()
}
.show(ui);
});
}
});
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment