Fix text wrapping when a child of a v_stack() (#3362)
Previously text that was rendered in a flex-column would reserve the correct amount of space during layout, and then paint itself incorrectly. Release Notes: - N/A
This commit is contained in:
@@ -64,19 +64,34 @@ impl<V: 'static> Element<V> for Text {
|
||||
|
||||
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
|
||||
let element_state = element_state.clone();
|
||||
move |known_dimensions, _| {
|
||||
move |known_dimensions, available_space| {
|
||||
let wrap_width = known_dimensions.width.or(match available_space.width {
|
||||
crate::AvailableSpace::Definite(x) => Some(x),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
if let Some(text_state) = element_state.0.lock().as_ref() {
|
||||
if text_state.size.is_some()
|
||||
&& (wrap_width.is_none() || wrap_width == text_state.wrap_width)
|
||||
{
|
||||
return text_state.size.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let Some(lines) = text_system
|
||||
.shape_text(
|
||||
&text,
|
||||
font_size,
|
||||
&runs[..],
|
||||
known_dimensions.width, // Wrap if we know the width.
|
||||
wrap_width, // Wrap if we know the width.
|
||||
)
|
||||
.log_err()
|
||||
else {
|
||||
element_state.lock().replace(TextStateInner {
|
||||
lines: Default::default(),
|
||||
line_height,
|
||||
wrap_width,
|
||||
size: Some(Size::default()),
|
||||
});
|
||||
return Size::default();
|
||||
};
|
||||
@@ -88,9 +103,12 @@ impl<V: 'static> Element<V> for Text {
|
||||
size.width = size.width.max(line_size.width);
|
||||
}
|
||||
|
||||
element_state
|
||||
.lock()
|
||||
.replace(TextStateInner { lines, line_height });
|
||||
element_state.lock().replace(TextStateInner {
|
||||
lines,
|
||||
line_height,
|
||||
wrap_width,
|
||||
size: Some(size),
|
||||
});
|
||||
|
||||
size
|
||||
}
|
||||
@@ -133,6 +151,8 @@ impl TextState {
|
||||
struct TextStateInner {
|
||||
lines: SmallVec<[WrappedLine; 1]>,
|
||||
line_height: Pixels,
|
||||
wrap_width: Option<Pixels>,
|
||||
size: Option<Size<Pixels>>,
|
||||
}
|
||||
|
||||
struct InteractiveText {
|
||||
|
||||
+22
-24
@@ -5,12 +5,14 @@ use std::fmt::Debug;
|
||||
use taffy::{
|
||||
geometry::{Point as TaffyPoint, Rect as TaffyRect, Size as TaffySize},
|
||||
style::AvailableSpace as TaffyAvailableSpace,
|
||||
tree::{Measurable, MeasureFunc, NodeId},
|
||||
tree::NodeId,
|
||||
Taffy,
|
||||
};
|
||||
|
||||
type Measureable = dyn Fn(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels> + Send + Sync;
|
||||
|
||||
pub struct TaffyLayoutEngine {
|
||||
taffy: Taffy,
|
||||
taffy: Taffy<Box<Measureable>>,
|
||||
children_to_parents: HashMap<LayoutId, LayoutId>,
|
||||
absolute_layout_bounds: HashMap<LayoutId, Bounds<Pixels>>,
|
||||
computed_layouts: HashSet<LayoutId>,
|
||||
@@ -70,9 +72,9 @@ impl TaffyLayoutEngine {
|
||||
) -> LayoutId {
|
||||
let style = style.to_taffy(rem_size);
|
||||
|
||||
let measurable = Box::new(Measureable(measure)) as Box<dyn Measurable>;
|
||||
let measurable = Box::new(measure);
|
||||
self.taffy
|
||||
.new_leaf_with_measure(style, MeasureFunc::Boxed(measurable))
|
||||
.new_leaf_with_context(style, measurable)
|
||||
.expect(EXPECT_MESSAGE)
|
||||
.into()
|
||||
}
|
||||
@@ -154,7 +156,22 @@ impl TaffyLayoutEngine {
|
||||
|
||||
// let started_at = std::time::Instant::now();
|
||||
self.taffy
|
||||
.compute_layout(id.into(), available_space.into())
|
||||
.compute_layout_with_measure(
|
||||
id.into(),
|
||||
available_space.into(),
|
||||
|known_dimensions, available_space, _node_id, context| {
|
||||
let Some(measure) = context else {
|
||||
return taffy::geometry::Size::default();
|
||||
};
|
||||
|
||||
let known_dimensions = Size {
|
||||
width: known_dimensions.width.map(Pixels),
|
||||
height: known_dimensions.height.map(Pixels),
|
||||
};
|
||||
|
||||
measure(known_dimensions, available_space.into()).into()
|
||||
},
|
||||
)
|
||||
.expect(EXPECT_MESSAGE);
|
||||
// println!("compute_layout took {:?}", started_at.elapsed());
|
||||
}
|
||||
@@ -202,25 +219,6 @@ impl From<LayoutId> for NodeId {
|
||||
}
|
||||
}
|
||||
|
||||
struct Measureable<F>(F);
|
||||
|
||||
impl<F> taffy::tree::Measurable for Measureable<F>
|
||||
where
|
||||
F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels> + Send + Sync,
|
||||
{
|
||||
fn measure(
|
||||
&self,
|
||||
known_dimensions: TaffySize<Option<f32>>,
|
||||
available_space: TaffySize<TaffyAvailableSpace>,
|
||||
) -> TaffySize<f32> {
|
||||
let known_dimensions: Size<Option<f32>> = known_dimensions.into();
|
||||
let known_dimensions: Size<Option<Pixels>> = known_dimensions.map(|d| d.map(Into::into));
|
||||
let available_space = available_space.into();
|
||||
let size = (self.0)(known_dimensions, available_space);
|
||||
size.into()
|
||||
}
|
||||
}
|
||||
|
||||
trait ToTaffy<Output> {
|
||||
fn to_taffy(&self, rem_size: Pixels) -> Output;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user