diff --git a/crates/egui/src/containers/area.rs b/crates/egui/src/containers/area.rs index f0cc8cab7..e7f787f40 100644 --- a/crates/egui/src/containers/area.rs +++ b/crates/egui/src/containers/area.rs @@ -613,7 +613,7 @@ impl Prepared { .. } = self; - state.size = Some(content_ui.placer().min_item_size()); + state.size = Some(content_ui.intrinsic_size()); dbg!(state.size); diff --git a/crates/egui/src/containers/collapsing_header.rs b/crates/egui/src/containers/collapsing_header.rs index c34e56294..5be77f3d0 100644 --- a/crates/egui/src/containers/collapsing_header.rs +++ b/crates/egui/src/containers/collapsing_header.rs @@ -18,7 +18,7 @@ pub(crate) struct InnerState { open_height: Option, } -/// This is a a building block for building collapsing regions. +/// This is a building block for building collapsing regions. /// /// It is used by [`CollapsingHeader`] and [`crate::Window`], but can also be used on its own. /// @@ -87,7 +87,7 @@ impl CollapsingState { ui: &mut Ui, button_size: Vec2, ) -> Response { - let (_id, rect) = ui.allocate_space(button_size); + let (_id, rect) = ui.allocate_space(button_size, Vec2::ZERO); // TODO let response = ui.interact(rect, self.id, Sense::click()); response.widget_info(|| { WidgetInfo::labeled( @@ -117,7 +117,7 @@ impl CollapsingState { icon_fn: impl FnOnce(&mut Ui, f32, &Response) + 'static, ) -> Response { let size = vec2(ui.spacing().indent, ui.spacing().icon_width); - let (_id, rect) = ui.allocate_space(size); + let (_id, rect) = ui.allocate_space(size, Vec2::ZERO); // TODO let response = ui.interact(rect, self.id, Sense::click()); if response.clicked() { self.toggle(ui); @@ -554,7 +554,7 @@ impl CollapsingHeader { let mut desired_size = vec2(desired_width, galley.size().y + 2.0 * button_padding.y); desired_size = desired_size.at_least(ui.spacing().interact_size); - let (_, rect) = ui.allocate_space(desired_size); + let (_, rect) = ui.allocate_space(desired_size, desired_size); // TODO let mut header_response = ui.interact(rect, id, Sense::click()); let text_pos = pos2( diff --git a/crates/egui/src/containers/combo_box.rs b/crates/egui/src/containers/combo_box.rs index 7a5a160f9..86ec7d298 100644 --- a/crates/egui/src/containers/combo_box.rs +++ b/crates/egui/src/containers/combo_box.rs @@ -340,7 +340,7 @@ fn combo_box_dyn<'c, R>( let actual_width = (galley.size().x + icon_spacing + icon_size.x).at_least(minimum_width); let actual_height = galley.size().y.max(icon_size.y); - let (_, rect) = ui.allocate_space(Vec2::new(actual_width, actual_height)); + let (_, rect) = ui.allocate_space(Vec2::new(actual_width, actual_height), Vec2::ZERO); // TODO let button_rect = ui.min_rect().expand2(ui.spacing().button_padding); let response = ui.interact(button_rect, button_id, Sense::click()); // response.active |= is_popup_open; @@ -444,7 +444,7 @@ fn button_frame( ); } - ui.advance_cursor_after_rect(outer_rect); + ui.advance_cursor_after_rect(outer_rect, Vec2::ZERO); // TODO response } diff --git a/crates/egui/src/containers/frame.rs b/crates/egui/src/containers/frame.rs index 1fdbbca92..2f8e7cbe8 100644 --- a/crates/egui/src/containers/frame.rs +++ b/crates/egui/src/containers/frame.rs @@ -473,7 +473,11 @@ impl Prepared { /// /// This can be called before or after [`Self::paint`]. pub fn allocate_space(&self, ui: &mut Ui) -> Response { - ui.allocate_rect(self.outer_rect(), Sense::hover()) + ui.allocate_rect( + self.outer_rect(), + Sense::hover(), + self.content_ui.intrinsic_size() + self.frame.total_margin().sum(), + ) } /// Paint the frame. diff --git a/crates/egui/src/containers/popup.rs b/crates/egui/src/containers/popup.rs index 9011b9f36..4a457bf03 100644 --- a/crates/egui/src/containers/popup.rs +++ b/crates/egui/src/containers/popup.rs @@ -568,8 +568,7 @@ impl<'a> Popup<'a> { let mut response = area.show(&ctx, |ui| { style.apply(ui.style_mut()); - // frame.show(ui, content).inner - content(ui) + frame.show(ui, content).inner }); let closed_by_click = match close_behavior { diff --git a/crates/egui/src/containers/resize.rs b/crates/egui/src/containers/resize.rs index 0df9a1136..35c4d42c0 100644 --- a/crates/egui/src/containers/resize.rs +++ b/crates/egui/src/containers/resize.rs @@ -331,7 +331,10 @@ impl Resize { size[d] = state.last_content_size[d]; } } - ui.advance_cursor_after_rect(Rect::from_min_size(content_ui.min_rect().min, size)); + ui.advance_cursor_after_rect( + Rect::from_min_size(content_ui.min_rect().min, size), + Vec2::ZERO, + ); // TODO // ------------------------------ diff --git a/crates/egui/src/containers/scroll_area.rs b/crates/egui/src/containers/scroll_area.rs index c430b6ea9..d88c9c2f3 100644 --- a/crates/egui/src/containers/scroll_area.rs +++ b/crates/egui/src/containers/scroll_area.rs @@ -1245,7 +1245,7 @@ impl Prepared { } } - ui.advance_cursor_after_rect(outer_rect); + ui.advance_cursor_after_rect(outer_rect, Vec2::ZERO); // TODO if show_scroll_this_frame != state.show_scroll { ui.ctx().request_repaint(); diff --git a/crates/egui/src/containers/sides.rs b/crates/egui/src/containers/sides.rs index e34ae70eb..a7275ad54 100644 --- a/crates/egui/src/containers/sides.rs +++ b/crates/egui/src/containers/sides.rs @@ -1,4 +1,4 @@ -use emath::Align; +use emath::{Align, Vec2}; use crate::{Layout, Ui, UiBuilder}; @@ -84,7 +84,7 @@ impl Sides { let result_left; let result_right; - let left_rect = { + let (left_rect, left_preferred_size) = { let left_max_rect = top_rect; let mut left_ui = ui.new_child( UiBuilder::new() @@ -92,10 +92,10 @@ impl Sides { .layout(Layout::left_to_right(Align::Center)), ); result_left = add_left(&mut left_ui); - left_ui.min_rect() + (left_ui.min_rect(), left_ui.intrinsic_size()) }; - let right_rect = { + let (right_rect, right_preferred_size) = { let right_max_rect = top_rect.with_min_x(left_rect.max.x); let mut right_ui = ui.new_child( UiBuilder::new() @@ -103,7 +103,7 @@ impl Sides { .layout(Layout::right_to_left(Align::Center)), ); result_right = add_right(&mut right_ui); - right_ui.min_rect() + (right_ui.min_rect(), right_ui.intrinsic_size()) }; let mut final_rect = left_rect.union(right_rect); @@ -118,7 +118,12 @@ impl Sides { final_rect.max.x = final_rect.max.x.max(left_rect.min.x + min_width); } - ui.advance_cursor_after_rect(final_rect); + let preferred_size = Vec2::new( + left_preferred_size.x + spacing + right_preferred_size.x, + left_preferred_size.y.max(right_preferred_size.y), + ); + + ui.advance_cursor_after_rect(final_rect, preferred_size); (result_left, result_right) } diff --git a/crates/egui/src/introspection.rs b/crates/egui/src/introspection.rs index e21ddb3a5..8d0a24745 100644 --- a/crates/egui/src/introspection.rs +++ b/crates/egui/src/introspection.rs @@ -1,8 +1,10 @@ //! Showing UI:s for egui/epaint types. + use crate::{ epaint, memory, pos2, remap_clamp, vec2, Color32, CursorIcon, FontFamily, FontId, Label, Mesh, NumExt, Rect, Response, Sense, Shape, Slider, TextStyle, TextWrapMode, Ui, Widget, }; +use emath::Vec2; pub fn font_family_ui(ui: &mut Ui, font_family: &mut FontFamily) { let families = ui.fonts(|f| f.families()); @@ -42,7 +44,7 @@ pub(crate) fn font_texture_ui(ui: &mut Ui, [width, height]: [usize; 2]) -> Respo if size.x > ui.available_width() { size *= ui.available_width() / size.x; } - let (rect, response) = ui.allocate_at_least(size, Sense::hover()); + let (rect, response) = ui.allocate_at_least(size, Sense::hover(), Vec2::ZERO); // TODO let mut mesh = Mesh::default(); mesh.add_rect_with_uv(rect, [pos2(0.0, 0.0), pos2(1.0, 1.0)].into(), color); ui.painter().add(Shape::mesh(mesh)); @@ -53,7 +55,7 @@ pub(crate) fn font_texture_ui(ui: &mut Ui, [width, height]: [usize; 2]) -> Respo .on_hover_cursor(CursorIcon::ZoomIn) .on_hover_ui_at_pointer(|ui| { if let Some(pos) = ui.ctx().pointer_latest_pos() { - let (_id, zoom_rect) = ui.allocate_space(vec2(128.0, 128.0)); + let (_id, zoom_rect) = ui.allocate_space(vec2(128.0, 128.0), Vec2::ZERO); // TODO let u = remap_clamp(pos.x, rect.x_range(), 0.0..=tex_w); let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h); diff --git a/crates/egui/src/layout.rs b/crates/egui/src/layout.rs index d18a342da..cf165c281 100644 --- a/crates/egui/src/layout.rs +++ b/crates/egui/src/layout.rs @@ -46,7 +46,7 @@ pub(crate) struct Region { /// The cursor can thus be `style.spacing.item_spacing` pixels outside of the `min_rect`. pub(crate) cursor: Rect, - pub min_item_size: Vec2, + pub intrinsic_size: Vec2, } impl Region { @@ -428,7 +428,7 @@ impl Layout { min_rect: Rect::NOTHING, // temporary max_rect, cursor: self.initial_cursor(max_rect), - min_item_size: Vec2::default(), + intrinsic_size: Vec2::default(), }; let seed = self.next_widget_position(®ion); region.min_rect = Rect::from_center_size(seed, Vec2::ZERO); @@ -532,7 +532,7 @@ impl Layout { mut cursor, mut max_rect, min_rect, - min_item_size, + intrinsic_size: min_item_size, } = *region; match self.main_dir { @@ -594,7 +594,7 @@ impl Layout { min_rect, max_rect, cursor, - min_item_size, + intrinsic_size: min_item_size, }; self.next_frame_ignore_wrap(®ion, child_size) diff --git a/crates/egui/src/menu.rs b/crates/egui/src/menu.rs index fa99cebbd..c44cfbed2 100644 --- a/crates/egui/src/menu.rs +++ b/crates/egui/src/menu.rs @@ -563,7 +563,7 @@ impl SubMenuButton { let mut desired_size = text_and_icon_size + 2.0 * button_padding; desired_size.y = desired_size.y.at_least(ui.spacing().interact_size.y); - let (rect, response) = ui.allocate_at_least(desired_size, sense); + let (rect, response) = ui.allocate_at_least(desired_size, sense, Vec2::ZERO); // TODO response.widget_info(|| { crate::WidgetInfo::labeled( crate::WidgetType::Button, diff --git a/crates/egui/src/placer.rs b/crates/egui/src/placer.rs index f05ee9588..26e2365f9 100644 --- a/crates/egui/src/placer.rs +++ b/crates/egui/src/placer.rs @@ -1,4 +1,4 @@ -use crate::{grid, vec2, Layout, Painter, Pos2, Rect, Region, Vec2}; +use crate::{grid, vec2, Direction, Layout, Painter, Pos2, Rect, Region, Vec2}; #[cfg(debug_assertions)] use crate::{Align2, Color32, Stroke}; @@ -163,7 +163,7 @@ impl Placer { frame_rect: Rect, widget_rect: Rect, item_spacing: Vec2, - desired_size: Vec2, + intrinsic_size: Vec2, ) { debug_assert!(!frame_rect.any_nan()); debug_assert!(!widget_rect.any_nan()); @@ -180,15 +180,27 @@ impl Placer { ); } - self.region.min_item_size = self.region.min_item_size.max(desired_size); + if self.layout.is_horizontal() { + if self.region.intrinsic_size.x != 0.0 { + self.region.intrinsic_size.x += item_spacing.x; + } + self.region.intrinsic_size.x += intrinsic_size.x; + self.region.intrinsic_size.y = self.region.intrinsic_size.y.max(intrinsic_size.y); + } else { + if self.region.intrinsic_size.y != 0.0 { + self.region.intrinsic_size.y += item_spacing.y; + } + self.region.intrinsic_size.x = self.region.intrinsic_size.x.max(intrinsic_size.x); + self.region.intrinsic_size.y += intrinsic_size.y; + } self.expand_to_include_rect(frame_rect); // e.g. for centered layouts: pretend we used whole frame self.region.sanity_check(); } - pub(crate) fn min_item_size(&self) -> Vec2 { - self.region.min_item_size + pub(crate) fn intrinsic_size(&self) -> Vec2 { + self.region.intrinsic_size } /// Move to the next row in a grid layout or wrapping layout. diff --git a/crates/egui/src/style.rs b/crates/egui/src/style.rs index 4d227f63b..159916b68 100644 --- a/crates/egui/src/style.rs +++ b/crates/egui/src/style.rs @@ -2548,7 +2548,7 @@ impl Widget for &mut Stroke { ui.color_edit_button_srgba(color); // stroke preview: - let (_id, stroke_rect) = ui.allocate_space(ui.spacing().interact_size); + let (_id, stroke_rect) = ui.allocate_space(ui.spacing().interact_size, Vec2::ZERO); // TODO let left = stroke_rect.left_center(); let right = stroke_rect.right_center(); ui.painter().line_segment([left, right], (*width, *color)); diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 94c9d0411..99067eb31 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -1140,6 +1140,12 @@ impl Ui { if self.should_close() { response.set_close(); } + response.intrinsic_size = Some(self.intrinsic_size()); + // self.ctx().debug_painter().debug_rect( + // Rect::from_min_size(self.min_rect().min, self.intrinsic_size()), + // Color32::GREEN, + // "", + // ); response } @@ -1296,8 +1302,13 @@ impl Ui { /// ui.painter().rect_stroke(response.rect, 0.0, (1.0, egui::Color32::WHITE), egui::StrokeKind::Inside); /// # }); /// ``` - pub fn allocate_response(&mut self, desired_size: Vec2, sense: Sense) -> Response { - let (id, rect) = self.allocate_space(desired_size); + pub fn allocate_response( + &mut self, + desired_size: Vec2, + sense: Sense, + desired_size_2: Vec2, + ) -> Response { + let (id, rect) = self.allocate_space(desired_size, desired_size_2); let mut response = self.interact(rect, id, sense); response.intrinsic_size = Some(desired_size); response @@ -1309,7 +1320,7 @@ impl Ui { /// This means that if this is a narrow widget in a wide justified layout, then /// the widget will react to interactions outside the returned [`Rect`]. pub fn allocate_exact_size(&mut self, desired_size: Vec2, sense: Sense) -> (Rect, Response) { - let response = self.allocate_response(desired_size, sense); + let response = self.allocate_response(desired_size, sense, desired_size); // TODO? let rect = self .placer .align_size_within_rect(desired_size, response.rect); @@ -1319,8 +1330,15 @@ impl Ui { /// Allocate at least as much space as needed, and interact with that rect. /// /// The returned [`Rect`] will be the same size as `Response::rect`. - pub fn allocate_at_least(&mut self, desired_size: Vec2, sense: Sense) -> (Rect, Response) { - let response = self.allocate_response(desired_size, sense); + // TODO: Is this still needed? + // TODO: Awful naming conflict + pub fn allocate_at_least( + &mut self, + desired_size: Vec2, + sense: Sense, + desired_size_2: Vec2, + ) -> (Rect, Response) { + let response = self.allocate_response(desired_size, sense, desired_size_2); (response.rect, response) } @@ -1345,11 +1363,11 @@ impl Ui { /// let response = ui.interact(rect, id, egui::Sense::click()); /// # }); /// ``` - pub fn allocate_space(&mut self, desired_size: Vec2) -> (Id, Rect) { + pub fn allocate_space(&mut self, desired_size: Vec2, desired_size_2: Vec2) -> (Id, Rect) { #[cfg(debug_assertions)] let original_available = self.available_size_before_wrap(); - let rect = self.allocate_space_impl(desired_size); + let rect = self.allocate_space_impl(desired_size, desired_size_2); #[cfg(debug_assertions)] { @@ -1396,14 +1414,19 @@ impl Ui { /// Reserve this much space and move the cursor. /// Returns where to put the widget. - fn allocate_space_impl(&mut self, desired_size: Vec2) -> Rect { + fn allocate_space_impl(&mut self, desired_size: Vec2, desired_size_2: Vec2) -> Rect { + // self.ctx().debug_painter().debug_rect( + // Rect::from_min_size(self.cursor().min, desired_size_2), + // Color32::YELLOW, + // "", + // ); let item_spacing = self.spacing().item_spacing; let frame_rect = self.placer.next_space(desired_size, item_spacing); debug_assert!(!frame_rect.any_nan()); let widget_rect = self.placer.justify_and_align(frame_rect, desired_size); self.placer - .advance_after_rects(frame_rect, widget_rect, item_spacing, desired_size); + .advance_after_rects(frame_rect, widget_rect, item_spacing, desired_size_2); register_rect(self, widget_rect); @@ -1414,20 +1437,20 @@ impl Ui { /// /// Ignore the layout of the [`Ui`]: just put my widget here! /// The layout cursor will advance to past this `rect`. - pub fn allocate_rect(&mut self, rect: Rect, sense: Sense) -> Response { + pub fn allocate_rect(&mut self, rect: Rect, sense: Sense, intrinsic_size: Vec2) -> Response { let rect = rect.round_ui(); - let id = self.advance_cursor_after_rect(rect); + let id = self.advance_cursor_after_rect(rect, intrinsic_size); self.interact(rect, id, sense) } /// Allocate a rect without interacting with it. - pub fn advance_cursor_after_rect(&mut self, rect: Rect) -> Id { + pub fn advance_cursor_after_rect(&mut self, rect: Rect, intrinsic_size: Vec2) -> Id { debug_assert!(!rect.any_nan()); let rect = rect.round_ui(); let item_spacing = self.spacing().item_spacing; self.placer - .advance_after_rects(rect, rect, item_spacing, rect.size()); + .advance_after_rects(rect, rect, item_spacing, intrinsic_size); register_rect(self, rect); let id = Id::new(self.next_auto_id_salt); @@ -1555,7 +1578,7 @@ impl Ui { /// # }); /// ``` pub fn allocate_painter(&mut self, desired_size: Vec2, sense: Sense) -> (Response, Painter) { - let response = self.allocate_response(desired_size, sense); + let response = self.allocate_response(desired_size, sense, desired_size); // TODO? let clip_rect = self.clip_rect().intersect(response.rect); // Make sure we don't paint out of bounds let painter = self.painter().with_clip_rect(clip_rect); (response, painter) @@ -2414,24 +2437,17 @@ impl Ui { self.next_auto_id_salt = next_auto_id_salt; // HACK: we want `scope` to only increment this once, so that `ui.scope` is equivalent to `ui.allocate_space`. let ret = add_contents(&mut child_ui); let mut response = child_ui.remember_min_rect(); - self.advance_cursor_after_rect(child_ui.min_rect()); - match self.layout().is_horizontal() { - true => { - response.intrinsic_size = Some(Vec2::new( - response.rect.width(), - self.placer.min_item_size().y, - )); - } - false => { - response.intrinsic_size = Some(Vec2::new( - self.placer.min_item_size().x, - response.rect.height(), - )); - } - } + self.advance_cursor_after_rect( + child_ui.min_rect(), + response.intrinsic_size.unwrap_or(response.rect.size()), + ); InnerResponse::new(ret, response) } + pub(crate) fn intrinsic_size(&self) -> Vec2 { + self.placer.intrinsic_size() + } + /// Redirect shapes to another paint layer. /// /// ``` @@ -2520,7 +2536,11 @@ impl Ui { } } - let response = self.allocate_rect(child_ui.min_rect(), Sense::hover()); + let response = self.allocate_rect( + child_ui.min_rect(), + Sense::hover(), + child_ui.intrinsic_size(), + ); // TODO InnerResponse::new(ret, response) } @@ -2810,7 +2830,7 @@ impl Ui { let total_required_width = total_spacing + max_column_width * (num_columns as f32); let size = vec2(self.available_width().max(total_required_width), max_height); - self.advance_cursor_after_rect(Rect::from_min_size(top_left, size)); + self.advance_cursor_after_rect(Rect::from_min_size(top_left, size), Vec2::ZERO); // TODO result } @@ -2865,7 +2885,7 @@ impl Ui { let total_required_width = total_spacing + max_column_width * (NUM_COL as f32); let size = vec2(self.available_width().max(total_required_width), max_height); - self.advance_cursor_after_rect(Rect::from_min_size(top_left, size)); + self.advance_cursor_after_rect(Rect::from_min_size(top_left, size), Vec2::ZERO); // TODO result } diff --git a/crates/egui/src/widgets/button.rs b/crates/egui/src/widgets/button.rs index dcf37d203..bd12d2458 100644 --- a/crates/egui/src/widgets/button.rs +++ b/crates/egui/src/widgets/button.rs @@ -295,7 +295,25 @@ impl Widget for Button<'_> { } desired_size = desired_size.at_least(min_size); - let (rect, mut response) = ui.allocate_at_least(desired_size, sense); + // TODO: Missing a lot + let mut desired_size_2 = galley + .as_ref() + .map_or(Vec2::ZERO, |galley| galley.desired_size()); + let mut desired_right_galley_size = right_galley.as_ref().map_or(Vec2::ZERO, |galley| { + galley.desired_size() + Vec2::new(gap_before_right_text, 0.0) + }); + desired_size_2.x += desired_right_galley_size.x; + desired_size_2.y = desired_size_2.y.max(desired_right_galley_size.y); + desired_size_2 += 2.0 * button_padding; + + // dbg!(desired_size_2); + // ui.ctx().debug_painter().debug_rect( + // Rect::from_min_size(ui.cursor().min, desired_size_2), + // Color32::from_rgb(100, 0, 0), + // "", + // ); + + let (rect, mut response) = ui.allocate_at_least(desired_size, sense, desired_size_2); response.widget_info(|| { if let Some(galley) = &galley { WidgetInfo::labeled(WidgetType::Button, ui.is_enabled(), galley.text()) diff --git a/crates/egui/src/widgets/color_picker.rs b/crates/egui/src/widgets/color_picker.rs index a9906cef1..41ce8df97 100644 --- a/crates/egui/src/widgets/color_picker.rs +++ b/crates/egui/src/widgets/color_picker.rs @@ -58,7 +58,7 @@ pub fn show_color(ui: &mut Ui, color: impl Into, desired_size: Vec2) -> } fn show_color32(ui: &mut Ui, color: Color32, desired_size: Vec2) -> Response { - let (rect, response) = ui.allocate_at_least(desired_size, Sense::hover()); + let (rect, response) = ui.allocate_at_least(desired_size, Sense::hover(), desired_size); if ui.is_rect_visible(rect) { show_color_at(ui.painter(), color, rect); } @@ -116,7 +116,8 @@ fn color_slider_1d(ui: &mut Ui, value: &mut f32, color_at: impl Fn(f32) -> Color #![allow(clippy::identity_op)] let desired_size = vec2(ui.spacing().slider_width, ui.spacing().interact_size.y); - let (rect, response) = ui.allocate_at_least(desired_size, Sense::click_and_drag()); + let (rect, response) = + ui.allocate_at_least(desired_size, Sense::click_and_drag(), desired_size); if let Some(mpos) = response.interact_pointer_pos() { *value = remap_clamp(mpos.x, rect.left()..=rect.right(), 0.0..=1.0); @@ -183,7 +184,8 @@ fn color_slider_2d( color_at: impl Fn(f32, f32) -> Color32, ) -> Response { let desired_size = Vec2::splat(ui.spacing().slider_width); - let (rect, response) = ui.allocate_at_least(desired_size, Sense::click_and_drag()); + let (rect, response) = + ui.allocate_at_least(desired_size, Sense::click_and_drag(), desired_size); if let Some(mpos) = response.interact_pointer_pos() { *x_value = remap_clamp(mpos.x, rect.left()..=rect.right(), 0.0..=1.0); diff --git a/crates/egui/src/widgets/label.rs b/crates/egui/src/widgets/label.rs index 34b684df6..1a4c49c78 100644 --- a/crates/egui/src/widgets/label.rs +++ b/crates/egui/src/widgets/label.rs @@ -214,10 +214,10 @@ impl Label { assert!(!galley.rows.is_empty(), "Galleys are never empty"); // collect a response from many rows: let rect = galley.rows[0].rect.translate(vec2(pos.x, pos.y)); - let mut response = ui.allocate_rect(rect, sense); + let mut response = ui.allocate_rect(rect, sense, galley.desired_size()); for row in galley.rows.iter().skip(1) { let rect = row.rect.translate(vec2(pos.x, pos.y)); - response |= ui.allocate_rect(rect, sense); + response |= ui.allocate_rect(rect, sense, galley.desired_size()); } (pos, galley, response) } else { diff --git a/crates/egui/src/widgets/selected_label.rs b/crates/egui/src/widgets/selected_label.rs index dfed4d2ba..2b7a8f16e 100644 --- a/crates/egui/src/widgets/selected_label.rs +++ b/crates/egui/src/widgets/selected_label.rs @@ -48,7 +48,8 @@ impl Widget for SelectableLabel { let mut desired_size = total_extra + galley.size(); desired_size.y = desired_size.y.at_least(ui.spacing().interact_size.y); - let (rect, response) = ui.allocate_at_least(desired_size, Sense::click()); + let (rect, response) = + ui.allocate_at_least(desired_size, Sense::click(), galley.desired_size()); response.widget_info(|| { WidgetInfo::selected( WidgetType::SelectableLabel, diff --git a/crates/egui/src/widgets/separator.rs b/crates/egui/src/widgets/separator.rs index d018cfa4d..eabd98d3e 100644 --- a/crates/egui/src/widgets/separator.rs +++ b/crates/egui/src/widgets/separator.rs @@ -108,7 +108,7 @@ impl Widget for Separator { vec2(spacing, available_space.y) }; - let (rect, response) = ui.allocate_at_least(size, Sense::hover()); + let (rect, response) = ui.allocate_at_least(size, Sense::hover(), size); if ui.is_rect_visible(response.rect) { let stroke = ui.visuals().widgets.noninteractive.bg_stroke; diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index 590282074..1df7a0653 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -650,7 +650,7 @@ impl Slider<'_> { SliderOrientation::Horizontal => vec2(ui.spacing().slider_width, thickness), SliderOrientation::Vertical => vec2(thickness, ui.spacing().slider_width), }; - ui.allocate_response(desired_size, Sense::drag()) + ui.allocate_response(desired_size, Sense::drag(), desired_size) } /// Just the slider, no text diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index b3ac4cd8b..a9e212b2e 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -541,7 +541,7 @@ impl TextEdit<'_> { let desired_height = (desired_height_rows.at_least(1) as f32) * row_height; let desired_inner_size = vec2(desired_inner_width, galley.size().y.max(desired_height)); let desired_outer_size = (desired_inner_size + margin.sum()).at_least(min_size); - let (auto_id, outer_rect) = ui.allocate_space(desired_outer_size); + let (auto_id, outer_rect) = ui.allocate_space(desired_outer_size, desired_outer_size); let rect = outer_rect - margin; // inner rect (excluding frame/margin). let id = id.unwrap_or_else(|| { @@ -739,6 +739,7 @@ impl TextEdit<'_> { ui.allocate_rect( Rect::from_min_size(outer_rect.max, extra_size), Sense::hover(), + response.intrinsic_size.unwrap(), ); } } diff --git a/crates/egui_demo_app/src/frame_history.rs b/crates/egui_demo_app/src/frame_history.rs index 231ba4a4f..30b3458ab 100644 --- a/crates/egui_demo_app/src/frame_history.rs +++ b/crates/egui_demo_app/src/frame_history.rs @@ -1,3 +1,4 @@ +use eframe::emath::Vec2; use egui::util::History; pub struct FrameHistory { @@ -62,7 +63,7 @@ impl FrameHistory { // TODO(emilk): we should not use `slider_width` as default graph width. let height = ui.spacing().slider_width; let size = vec2(ui.available_size_before_wrap().x, height); - let (rect, response) = ui.allocate_at_least(size, Sense::hover()); + let (rect, response) = ui.allocate_at_least(size, Sense::hover(), Vec2::ZERO); // TODO let style = ui.style().noninteractive(); let graph_top_cpu_usage = 0.010; diff --git a/crates/egui_demo_lib/src/demo/dancing_strings.rs b/crates/egui_demo_lib/src/demo/dancing_strings.rs index dd480181d..c385f10e6 100644 --- a/crates/egui_demo_lib/src/demo/dancing_strings.rs +++ b/crates/egui_demo_lib/src/demo/dancing_strings.rs @@ -2,7 +2,7 @@ use egui::{ containers::{Frame, Window}, emath, epaint, epaint::PathStroke, - hex_color, lerp, pos2, remap, vec2, Color32, Context, Pos2, Rect, Ui, + hex_color, lerp, pos2, remap, vec2, Color32, Context, Pos2, Rect, Ui, Vec2, }; #[derive(Default)] @@ -43,7 +43,7 @@ impl crate::View for DancingStrings { let time = ui.input(|i| i.time); let desired_size = ui.available_width() * vec2(1.0, 0.35); - let (_id, rect) = ui.allocate_space(desired_size); + let (_id, rect) = ui.allocate_space(desired_size, Vec2::ZERO); // TODO let to_screen = emath::RectTransform::from_to(Rect::from_x_y_ranges(0.0..=1.0, -1.0..=1.0), rect); diff --git a/crates/egui_demo_lib/src/demo/misc_demo_window.rs b/crates/egui_demo_lib/src/demo/misc_demo_window.rs index edb19c3ea..454737aba 100644 --- a/crates/egui_demo_lib/src/demo/misc_demo_window.rs +++ b/crates/egui_demo_lib/src/demo/misc_demo_window.rs @@ -189,7 +189,8 @@ impl View for MiscDemoWindow { for i in 0..100 { let r = i as f32 * 0.5; let size = Vec2::splat(2.0 * r + 5.0); - let (rect, _response) = ui.allocate_at_least(size, Sense::hover()); + let (rect, _response) = + ui.allocate_at_least(size, Sense::hover(), Vec2::ZERO); // TODO ui.painter() .circle_filled(rect.center(), r, ui.visuals().text_color()); } @@ -384,7 +385,7 @@ impl BoxPainting { ui.horizontal_wrapped(|ui| { for _ in 0..self.num_boxes { - let (rect, _response) = ui.allocate_at_least(self.size, Sense::hover()); + let (rect, _response) = ui.allocate_at_least(self.size, Sense::hover(), Vec2::ZERO); // TODO ui.painter().rect( rect, self.corner_radius, diff --git a/crates/egui_demo_lib/src/demo/scrolling.rs b/crates/egui_demo_lib/src/demo/scrolling.rs index 7a2ca4d7c..2ffcdbb0d 100644 --- a/crates/egui_demo_lib/src/demo/scrolling.rs +++ b/crates/egui_demo_lib/src/demo/scrolling.rs @@ -225,7 +225,7 @@ fn huge_content_painter(ui: &mut egui::Ui) { used_rect = used_rect.union(text_rect); } - ui.allocate_rect(used_rect, Sense::hover()); // make sure it is visible! + ui.allocate_rect(used_rect, Sense::hover(), Vec2::ZERO); // TODO // make sure it is visible! }); } diff --git a/crates/egui_demo_lib/src/demo/tests/window_resize_test.rs b/crates/egui_demo_lib/src/demo/tests/window_resize_test.rs index 39a189a39..2d550fb11 100644 --- a/crates/egui_demo_lib/src/demo/tests/window_resize_test.rs +++ b/crates/egui_demo_lib/src/demo/tests/window_resize_test.rs @@ -1,3 +1,5 @@ +use egui::Vec2; + pub struct WindowResizeTest { text: String, } @@ -91,7 +93,7 @@ impl crate::Demo for WindowResizeTest { ui.vertical_centered(|ui| { ui.add(crate::egui_github_link_file!()); }); - ui.allocate_space(ui.available_size()); + ui.allocate_space(ui.available_size(), Vec2::ZERO); // TODO }); } } diff --git a/crates/egui_demo_lib/src/rendering_test.rs b/crates/egui_demo_lib/src/rendering_test.rs index e83e643bb..5e48ae996 100644 --- a/crates/egui_demo_lib/src/rendering_test.rs +++ b/crates/egui_demo_lib/src/rendering_test.rs @@ -269,7 +269,7 @@ impl ColorTest { } fn vertex_gradient(ui: &mut Ui, bg_fill: Color32, gradient: &Gradient) -> Response { - let (rect, response) = ui.allocate_at_least(GRADIENT_SIZE, Sense::hover()); + let (rect, response) = ui.allocate_at_least(GRADIENT_SIZE, Sense::hover(), Vec2::ZERO); // TODO let rect = rect.round_to_pixels(ui.pixels_per_point()); if bg_fill != Default::default() { let mut mesh = Mesh::default(); diff --git a/crates/egui_extras/src/layout.rs b/crates/egui_extras/src/layout.rs index fb84169f3..860c9e071 100644 --- a/crates/egui_extras/src/layout.rs +++ b/crates/egui_extras/src/layout.rs @@ -1,4 +1,4 @@ -use egui::{emath::GuiRounding, Id, Pos2, Rect, Response, Sense, Ui, UiBuilder}; +use egui::{emath::GuiRounding, Id, Pos2, Rect, Response, Sense, Ui, UiBuilder, Vec2}; #[derive(Clone, Copy)] pub(crate) enum CellSize { @@ -166,7 +166,8 @@ impl<'l> StripLayout<'l> { self.set_pos(allocation_rect); - self.ui.advance_cursor_after_rect(allocation_rect); + self.ui + .advance_cursor_after_rect(allocation_rect, Vec2::ZERO); // TODO let response = child_ui.response(); @@ -192,7 +193,7 @@ impl<'l> StripLayout<'l> { let before = self.cursor; self.cursor += delta; let rect = Rect::from_two_pos(before, self.cursor); - self.ui.allocate_rect(rect, Sense::hover()); + self.ui.allocate_rect(rect, Sense::hover(), Vec2::ZERO); // TODO } /// Return the Ui to which the contents where added @@ -243,6 +244,6 @@ impl<'l> StripLayout<'l> { rect.set_right(self.max.x); rect.set_bottom(self.max.y); - self.ui.allocate_rect(rect, Sense::hover()) + self.ui.allocate_rect(rect, Sense::hover(), Vec2::ZERO) // TODO } } diff --git a/crates/epaint/src/text/text_layout_types.rs b/crates/epaint/src/text/text_layout_types.rs index b228d023e..1b07d0ebb 100644 --- a/crates/epaint/src/text/text_layout_types.rs +++ b/crates/epaint/src/text/text_layout_types.rs @@ -726,6 +726,31 @@ impl Galley { pub fn size(&self) -> Vec2 { self.rect.size() } + + // TODO: Instead return Option? + pub fn desired_size(&self) -> Vec2 { + let mut current_width: f32 = 0.0; + let mut widest_width: f32 = 0.0; + let mut height = self.rows.first().map_or(0.0, |row| row.height()); + for row in &self.rows { + if current_width != 0.0 { + let space = row.glyphs.last(); + if let Some(space) = space { + if space.chr.is_whitespace() { + // TODO: Needed or not? Doesn't seem like it's needed + // current_width += space.advance_width; + } + } + } + current_width += row.rect.width(); + widest_width = widest_width.max(current_width); + if row.ends_with_newline { + height += row.height(); + current_width = 0.0; + } + } + vec2(widest_width, height) + } } impl AsRef for Galley { diff --git a/examples/hello_world_simple/src/main.rs b/examples/hello_world_simple/src/main.rs index 2a3006c22..4e2fcd8c3 100644 --- a/examples/hello_world_simple/src/main.rs +++ b/examples/hello_world_simple/src/main.rs @@ -19,6 +19,7 @@ fn main() -> eframe::Result { let mut checked = true; eframe::run_simple_native("My egui App", options, move |ctx, _frame| { + ctx.options_mut(|o| o.max_passes = 1.try_into().unwrap()); egui::CentralPanel::default().show(ctx, |ui| { // ui.heading("My egui Application"); // ui.horizontal(|ui| { @@ -32,6 +33,7 @@ fn main() -> eframe::Result { // } // ui.label(format!("Hello '{name}', age {age}")); + std::thread::sleep(std::time::Duration::from_millis(100)); let response = ui.button("Hiiii"); let text = if checked { @@ -46,13 +48,20 @@ fn main() -> eframe::Result { ui.button("Hiiii"); - if Button::new(text) - .wrap_mode(TextWrapMode::Extend) - .ui(ui) - .clicked() - { - checked = !checked; - } + ui.horizontal(|ui| { + ui.vertical(|ui| { + if Button::new(text) + // .wrap_mode(TextWrapMode::Extend) + .ui(ui) + .clicked() + { + checked = !checked; + } + ui.button("Button1"); + }); + + ui.button("Button2") + }); ui.button("Some other button"); });