From f101d39e8d98f8385f99dbcc71c2c2bfda863f5c Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 28 Jan 2025 14:55:17 +0100 Subject: [PATCH] Auto-size Scene on what is available --- crates/egui/src/containers/scene.rs | 22 ++++++------------- crates/egui_demo_lib/src/demo/scene.rs | 29 +++++++++++++++----------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/crates/egui/src/containers/scene.rs b/crates/egui/src/containers/scene.rs index 20b7c03e934..7085d9d91b4 100644 --- a/crates/egui/src/containers/scene.rs +++ b/crates/egui/src/containers/scene.rs @@ -7,11 +7,9 @@ use core::f32; -use emath::{GuiRounding, Pos2}; +use emath::{GuiRounding, NumExt as _, Pos2}; -use crate::{ - emath::TSTransform, load, LayerId, Rangef, Rect, Response, Sense, Ui, UiBuilder, Vec2, -}; +use crate::{emath::TSTransform, LayerId, Rangef, Rect, Response, Sense, Ui, UiBuilder, Vec2}; /// Creates a transformation that fits a given scene rectangle into the available screen size. /// @@ -24,7 +22,8 @@ pub fn fit_to_rect_in_scene(rect_in_ui: Rect, rect_in_scene: Rect) -> TSTransfor let scale_y = available_size_in_ui.y / rect_in_scene.height(); // Use the smaller of the two scales to ensure the whole rectangle fits on the screen. - let scale = scale_x.min(scale_y).min(1.0); + const MAX_SCALE: f32 = 1.0; + let scale = f32::min(scale_x, scale_y).at_most(MAX_SCALE); // Compute the translation to center the bounding rect in the screen. let center_screen = rect_in_ui.center(); @@ -40,7 +39,6 @@ pub fn fit_to_rect_in_scene(rect_in_ui: Rect, rect_in_scene: Rect) -> TSTransfor pub struct Scene { zoom_range: Rangef, max_inner_size: Vec2, - fit_rect: Option, } impl Default for Scene { @@ -48,7 +46,6 @@ impl Default for Scene { Self { zoom_range: Rangef::new(f32::EPSILON, 1.0), max_inner_size: Vec2::splat(1000.0), - fit_rect: None, } } } @@ -84,20 +81,13 @@ impl Scene { .ctx() .set_sublayer(parent_ui.layer_id(), scene_layer_id); - // let size = parent_ui.available_size_before_wrap(); // TODO: let user control via builder - let size = Vec2::splat(440.0); + let desired_outer_size = parent_ui.available_size_before_wrap(); let (global_view_bounds, _outer_response) = - parent_ui.allocate_exact_size(size, Sense::hover()); + parent_ui.allocate_exact_size(desired_outer_size, Sense::hover()); let global_from_parent = TSTransform::from_translation(global_view_bounds.min.to_vec2()); let mut to_global = global_from_parent * *to_parent; - // Optionally change the transformation so that a scene rect is - // contained in the view, potentially with letter boxing. - if let Some(rect_in_scene) = self.fit_rect { - // *to_parent = fit_to_rect_in_scene(global_view_bounds, rect_in_scene); - } - let mut local_ui = parent_ui.new_child( UiBuilder::new() .layer_id(scene_layer_id) diff --git a/crates/egui_demo_lib/src/demo/scene.rs b/crates/egui_demo_lib/src/demo/scene.rs index 2f11d6e6dad..e4b458648ae 100644 --- a/crates/egui_demo_lib/src/demo/scene.rs +++ b/crates/egui_demo_lib/src/demo/scene.rs @@ -1,6 +1,6 @@ use egui::emath::TSTransform; use egui::scene::{fit_to_rect_in_scene, Scene}; -use egui::{Pos2, Rect, Sense, UiBuilder, Vec2}; +use egui::{Pos2, Rect, Vec2}; use super::widget_gallery; @@ -53,26 +53,31 @@ impl crate::View for SceneDemo { egui::Frame::group(ui.style()) .inner_margin(0.0) .show(ui, |ui| { - let scene = Scene::new().max_inner_size([500.0, 1000.0]); + let scene = Scene::new().max_inner_size([350.0, 1000.0]); let mut reset_view = false; + let mut inner_rect = Rect::NAN; let response = scene.show(ui, &mut self.parent_from_child, |ui| { + reset_view = ui.button("Reset view").clicked(); + + ui.add_space(16.0); + self.widget_gallery.ui(ui); - // ui.put( - // Rect::from_min_size(Pos2::ZERO, Vec2::splat(64.0)), - // egui::Button::new("Button"), - // ); - // ui.put( - // Rect::from_min_size(Pos2::ZERO + 72.0 * Vec2::DOWN, Vec2::new(500.0, 64.0)), - // egui::Label::new(format!("Inner ui min_rect: {:?}", ui.min_rect())), - // ); + ui.put( + Rect::from_min_size(Pos2::new(0.0, -64.0), Vec2::new(200.0, 16.0)), + egui::Label::new("You can put a widget anywhere").selectable(false), + ); - reset_view = ui.button("Reset view").clicked(); + inner_rect = ui.min_rect(); }); if reset_view || response.double_clicked() { - self.parent_from_child = TSTransform::from_scaling(0.5); + // TODO: auto-call this on first frame? + self.parent_from_child = fit_to_rect_in_scene( + Rect::from_min_size(Pos2::ZERO, ui.min_size()), + inner_rect, + ); } }); }