diff --git a/api/rs/slint/tests/partial_renderer.rs b/api/rs/slint/tests/partial_renderer.rs index fac85dc8920..ded25546e6a 100644 --- a/api/rs/slint/tests/partial_renderer.rs +++ b/api/rs/slint/tests/partial_renderer.rs @@ -681,3 +681,42 @@ fn text_alignment() { Some(slint::LogicalPosition { x: 10., y: 10. }) ); } + +#[test] +fn nowrap_text_change_doesnt_change_height() { + slint::slint! { + export component Ui inherits Window { + in property first-text: "First text"; + out property first-label-width: first-label.width; + out property first-label-height: first-label.height; + background: black; + VerticalLayout { + first-label := Text { + text: root.first-text; + } + Text { + text: "Second text"; + } + } + } + } + + slint::platform::set_platform(Box::new(TestPlatform)).ok(); + let ui = Ui::new().unwrap(); + let window = WINDOW.with(|x| x.clone()); + window.set_size(slint::PhysicalSize::new(180, 260)); + ui.show().unwrap(); + assert!(window.draw_if_needed(|renderer| { + do_test_render_region(renderer, 0, 0, 180, 260); + })); + assert!(!window.draw_if_needed(|_| { unreachable!() })); + ui.set_first_text("Hello World longer".into()); + + let expected_width = ui.get_first_label_width().ceil() as _; + let expected_height = ui.get_first_label_height().ceil() as _; + + assert!(window.draw_if_needed(|renderer| { + do_test_render_region(renderer, 0, 0, expected_width, expected_height); + })); + assert!(!window.draw_if_needed(|_| { unreachable!() })); +} diff --git a/internal/core/items/text.rs b/internal/core/items/text.rs index 6f30a6c04d5..7960fbffafe 100644 --- a/internal/core/items/text.rs +++ b/internal/core/items/text.rs @@ -396,13 +396,12 @@ fn text_layout_info( width: Pin<&Property>, ) -> LayoutInfo { let window_inner = WindowInner::from_pub(window_adapter.window()); - let text_string = text.text(); let font_request = text.font_request(self_rc); let scale_factor = ScaleFactor::new(window_inner.scale_factor()); let implicit_size = |max_width, text_wrap| { window_adapter.renderer().text_size( font_request.clone(), - text_string.as_str(), + text.text().as_str(), max_width, scale_factor, text_wrap, @@ -435,7 +434,13 @@ fn text_layout_info( } Orientation::Vertical => { let h = match text.wrap() { - TextWrap::NoWrap => implicit_size(None, TextWrap::NoWrap).height, + TextWrap::NoWrap => { + // For unwrapped text, the height depends only on the font, not on the text - avoid a dependency + // on the text property, so that text changes result in less repaints when placed in layouts. + let metrics = + window_adapter.renderer().font_metrics(font_request.clone(), scale_factor); + metrics.ascent - metrics.descent + } TextWrap::WordWrap => implicit_size(Some(width.get()), TextWrap::WordWrap).height, TextWrap::CharWrap => implicit_size(Some(width.get()), TextWrap::CharWrap).height, }