1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use femtovg::{Align, Baseline, Canvas, Paint, Path, Renderer};
pub struct CursorSettings {
pub width: f32,
pub index: usize,
}
pub fn render_text<R: Renderer>(
text: &str,
x: f32,
y: f32,
text_width: f32,
text_height: f32,
paint: &Paint,
cursor: Option<CursorSettings>,
max_lines: Option<usize>,
canvas: &mut Canvas<R>,
) -> usize {
let Ok(split_text) = canvas.break_text_vec(text_width, text, paint) else {
return 0;
};
let mut count = split_text.len();
if let Some(line_count) = max_lines {
if line_count < count {
count = line_count;
}
}
let offset_ratio = match paint.text_baseline() {
Baseline::Top => 0.0,
Baseline::Bottom => 1.0,
_ => 0.5,
};
for (i, range) in split_text.into_iter().take(count).enumerate() {
let y = y + text_height * (i as f32 - (count - 1) as f32 * offset_ratio);
let _ = canvas.fill_text(x, y, &text[range.clone()], paint);
let Some(CursorSettings {
width: cursor_width,
index: text_cursor,
}) = cursor else {
continue;
};
if !range.contains(&text_cursor) && (text.len() != range.end || text_cursor != range.end) {
continue;
}
let row_cursor = text_cursor - range.start;
let text = &text[range];
let (Ok(metrics), Ok(full_metrics)) = (
canvas.measure_text(x, y, &text[0..row_cursor], paint),
canvas.measure_text(x, y, text, paint),
) else {
continue;
};
let cursor_ratio = match paint.text_align() {
Align::Left => 0.0,
Align::Center => 0.5,
Align::Right => 1.0,
};
let x = x + metrics.width() - full_metrics.width() * cursor_ratio;
let y = y - text_height * offset_ratio;
let mut path = Path::new();
path.move_to(x, y);
path.line_to(x, y + text_height);
let mut cursor_paint = paint.clone();
cursor_paint.set_line_width(cursor_width);
canvas.stroke_path(&mut path, &cursor_paint);
}
count
}