-
Notifications
You must be signed in to change notification settings - Fork 49
Description
Even when the text is empty, a layout needs to have some proper line metrics, so that for example Cursor::geometry(&layout)
can give a cursor of the correct size. RangedBuilder
does this correctly, but TreeBuilder
just fills the whole LineMetrics
with zeroes. This results in an invisible cursor for any TreeBuilder
-based text edit box when the text is empty.
This is a minimal example:
use parley::*;
fn main() {
let mut font_cx = FontContext::new();
let mut layout_cx = LayoutContext::new();
let style: TextStyle<[u8; 4]> = TextStyle::default();
println!("RangedBuilder with empty text ");
test_cursor_geometry_ranged(&mut layout_cx, &mut font_cx, &style, "");
println!();
println!("TreeBuilder with empty text ");
test_cursor_geometry(&mut layout_cx, &mut font_cx, &style, "");
}
fn test_cursor_geometry(layout_cx: &mut LayoutContext, font_cx: &mut FontContext, style: &TextStyle<[u8; 4]>, text: &str) {
let mut builder = layout_cx.tree_builder(font_cx, 1.0, true, style);
builder.push_text(text);
let (mut layout, _) = builder.build();
layout.break_all_lines(Some(400.0));
for (i, line) in layout.lines().enumerate() {
println!("Line {}: metrics = {:?}", i, line.metrics());
}
let cursor = Cursor::from_byte_index(&layout, 0, Affinity::Downstream);
let geometry = cursor.geometry(&layout, 1.0);
println!("Cursor geometry: {:?}", geometry);
}
fn test_cursor_geometry_ranged(layout_cx: &mut LayoutContext, font_cx: &mut FontContext, style: &TextStyle<[u8; 4]>, text: &str) {
let mut builder = layout_cx.ranged_builder(font_cx, text, 1.0, true);
builder.push_default(StyleProperty::FontStack(FontStack::from(&[FontFamily::Named("system-ui".into())] as &[FontFamily])));
builder.push_default(StyleProperty::FontSize(style.font_size));
let mut layout = builder.build(text);
layout.break_all_lines(Some(400.0));
for (i, line) in layout.lines().enumerate() {
println!("Line {}: metrics = {:?}", i, line.metrics());
}
let cursor = Cursor::from_byte_index(&layout, 0, Affinity::Downstream);
let geometry = cursor.geometry(&layout, 1.0);
println!("Cursor geometry: {:?}", geometry);
}
Output:
RangedBuilder with empty text
Line 0: metrics = LineMetrics { ascent: 17.104, descent: 4.688, leading: 0.0, line_height: 21.792, baseline: 16.0, offset: 0.0, advance: 4.1600003, trailing_whitespace: 4.1600003, min_coord: -1.0, max_coord: 22.0 }
Cursor geometry: Rect { x0: 0.0, y0: -1.0, x1: 1.0, y1: 22.0 }
TreeBuilder with empty text
Line 0: metrics = LineMetrics { ascent: 0.0, descent: 0.0, leading: 0.0, line_height: 0.0, baseline: 0.0, offset: 0.0, advance: 0.0, trailing_whitespace: 0.0, min_coord: 0.0, max_coord: 0.0 }
Cursor geometry: Rect { x0: 0.0, y0: 0.0, x1: 1.0, y1: 0.0 }
I blindly stumbled into a "fix" that looks like this: in TreeStyleBuilder::finish()
, right before returning, do
if styles.is_empty() && self.text.is_empty() {
styles.push(RangedStyle {
style: self.tree[0].style.clone(),
range: 0..0,
});
}
This makes the style available even when the text is empty. I don't know if this can be a proper solution.
Metadata
Metadata
Assignees
Labels
No labels