use egui::emath::TSTransform;
use egui::{Pos2, Rect, Vec2};
use gled_model::patching::layout::scene_bounds;
#[derive(Debug, Clone, Copy)]
pub(crate) struct SceneView {
pub(crate) center: Pos2,
pub(crate) zoom: Option<f32>,
}
impl SceneView {
pub(crate) fn centred_on(center: Pos2) -> Self {
Self { center, zoom: None }
}
}
pub(crate) fn fit_scene_square(slot: Rect) -> TSTransform {
let bounds = scene_bounds();
let fitted = fit_into(bounds.size(), slot);
let scale = fitted.width() / bounds.width();
TSTransform::new(
fitted.center().to_vec2() - scale * bounds.center().to_vec2(),
scale,
)
}
pub(crate) fn fit_into(size: Vec2, slot: Rect) -> Rect {
let scale = (slot.width() / size.x).min(slot.height() / size.y);
Rect::from_center_size(slot.center(), size * scale)
}
#[cfg(test)]
mod tests {
use super::*;
use egui::{pos2, vec2};
use gled_model::patching::layout::SCENE_SIZE;
#[test]
fn a_thumbnail_shows_the_same_square_the_live_preview_does() {
let preview = Rect::from_min_size(pos2(10.0, 20.0), Vec2::splat(100.0));
let xform = fit_scene_square(preview);
let bounds = scene_bounds();
assert_eq!(xform * bounds.min, preview.min);
assert_eq!(xform * bounds.max, preview.max);
assert_eq!(xform * bounds.center(), preview.center());
let uv = |p: Pos2| vec2(p.x / SCENE_SIZE, p.y / SCENE_SIZE);
assert_eq!(uv(bounds.min), vec2(0.0, 0.0));
assert_eq!(uv(bounds.max), vec2(1.0, 1.0));
}
#[test]
fn the_scene_fits_the_space_it_is_given() {
for rect in [
Rect::from_min_size(pos2(10.0, 20.0), vec2(860.0, 300.0)),
Rect::from_min_size(Pos2::ZERO, vec2(300.0, 900.0)),
Rect::from_min_size(pos2(-40.0, 5.0), vec2(400.0, 400.0)),
] {
let shown = fit_scene_square(rect) * scene_bounds();
assert!(
rect.expand(0.5).contains_rect(shown),
"scene drawn at {shown:?} in {rect:?}"
);
assert!(
(shown.center() - rect.center()).length() < 0.5,
"the scene sits in the middle of the space"
);
assert!(
(shown.width() - shown.height()).abs() < 0.5,
"the scene stays square"
);
}
}
#[test]
fn a_fitted_picture_keeps_its_shape() {
let slot = Rect::from_min_size(Pos2::ZERO, vec2(100.0, 50.0));
let fitted = fit_into(vec2(40.0, 40.0), slot);
assert_eq!(
fitted,
Rect::from_center_size(pos2(50.0, 25.0), vec2(50.0, 50.0))
);
}
}