Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 38 additions & 24 deletions plotters/src/element/text.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::borrow::Borrow;
use std::{borrow::Borrow, ops::Range};

use super::{Drawable, PointCollection};
use crate::style::{FontDesc, FontResult, LayoutBox, TextStyle};
Expand Down Expand Up @@ -129,33 +129,45 @@ fn layout_multiline_text<'a, F: FnMut(&'a str)>(
if max_width == 0 || line.is_empty() {
func(line);
} else {
let mut indices = line.char_indices().map(|(idx, _)| idx).peekable();
let indices: Vec<_> = line.char_indices().map(|(idx, _)| idx).collect();
// The index span for each character:
let mut spans = indices
.iter()
.cloned()
.zip(indices[1..].iter().cloned().chain([line.len()]))
.map(|(start, end)| start..end)
.peekable();

let it = std::iter::from_fn(|| {
let start_idx = match indices.next() {
Some(idx) => idx,
None => return None,
};

// iterate over indices
for idx in indices.by_ref() {
let substring = &line[start_idx..idx];
let width = font.box_size(substring).unwrap_or((0, 0)).0 as i32;
if width > max_width as i32 {
break;
}
}
// println!(
// "Accumulated width of \"{line}\": {:?}",
// spans
// .clone()
// .map(|span| font.box_size(&line[0..span.end]).unwrap().0)
// .collect::<Vec<_>>()
// );

let end_idx = match indices.peek() {
Some(idx) => *idx,
None => line.len(),
let it = std::iter::from_fn(|| loop {
// Include the first character regardless of width:
let Some(Range { start, mut end }) = spans.next() else {
return None;
};

Some(&line[start_idx..end_idx])
loop {
// Add subsequent characters unless they cause width to be exceeded:
if let Some(check) = spans.next_if(|check| {
let Ok((width, _)) = font.box_size(&line[start..check.end]) else {
return true;
};
width <= max_width
}) {
end = check.end;
} else {
return Some(start..end);
};
}
});

for chunk in it {
func(chunk);
func(&line[chunk]);
}
}
}
Expand All @@ -170,10 +182,12 @@ fn test_multi_layout() {

let font = FontDesc::new(FontFamily::SansSerif, 20 as f64, FontStyle::Bold);

// Accumulated width of "öäabcde": [10, 19, 29, 39, 47, 58, 67]
let mut lines = Vec::new();
layout_multiline_text("öäabcde", 40, font, |txt| {
println!("Got: {}", txt);
assert!(txt == "öäabc" || txt == "de");
lines.push(txt);
});
assert_eq!(lines, ["öäab", "cde"]);

let font = FontDesc::new(FontFamily::SansSerif, 20 as f64, FontStyle::Bold);
layout_multiline_text("öä", 100, font, |txt| {
Expand Down