Newer
Older
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use bevy::reflect::Reflect;
use crate::layout::grapheme::Grapheme;
use std::cmp::Ordering;
use std::ops::Index;
use std::slice::SliceIndex;
/// Contains details for a calculated line of text.
#[derive(Clone, Reflect, Debug, PartialEq)]
pub struct Line {
grapheme_index: usize,
graphemes: Vec<Grapheme>,
width: f32,
}
/// A reference to the grapheme at a specific row and column of a given line of text.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct RowCol {
/// The row this line belongs to (zero-indexed).
pub row: usize,
/// The column this grapheme belongs to (zero-indexed).
///
/// This is the same as the grapheme index localized to within a line.
pub col: usize,
/// The grapheme at this row and column.
pub grapheme: Grapheme,
}
impl Line {
/// Creates a new [`Line`] starting at the given grapheme cluster index.
pub fn new(grapheme_index: usize) -> Self {
Self {
grapheme_index,
graphemes: Vec::new(),
width: 0.0,
}
}
/// Creates a new [`Line`] following the given one.
///
/// This essentially means that it starts out pointing to the next [grapheme index].
///
/// [grapheme index]: Self::grapheme_index
pub fn new_after(previous: &Self) -> Self {
Self::new(previous.grapheme_index + previous.total_graphemes())
}
/// The total width of this line (in pixels).
pub fn width(&self) -> f32 {
self.width
}
/// Returns the grapheme at the given index within this line, if any.
///
/// If the grapheme does
pub fn get_grapheme<I: SliceIndex<[Grapheme]>>(&self, index: I) -> Option<&I::Output> {
self.graphemes.get(index)
}
/// Returns the grapheme at the given index within this line.
///
/// # Panics
///
/// Will panic if the given index is out of bounds of this line.
pub fn grapheme<I: SliceIndex<[Grapheme]>>(&self, index: I) -> &I::Output {
&self.graphemes[index]
}
/// The list of grapheme clusters in this line.
pub fn graphemes(&self) -> &[Grapheme] {
&self.graphemes
}
/// The index of the starting grapheme cluster within this line, relative to the entire text content.
pub fn grapheme_index(&self) -> usize {
self.grapheme_index
}
/// The total number of graphemes in this line.
pub fn total_graphemes(&self) -> usize {
self.graphemes.len()
}
/// The index of the starting glyph within this line, relative to the entire text content.
pub fn glyph_index(&self) -> usize {
self.graphemes
.first()
.map(|grapheme| grapheme.glyph_index)
.unwrap_or_default()
}
/// The total number of glyphs in this line.
pub fn total_glyphs(&self) -> usize {
let end = self
.graphemes
.last()
.map(|grapheme| grapheme.glyph_index + grapheme.glyph_total);
match end {
Some(index) if index > 0 => index - self.glyph_index(),
_ => 0,
}
}
/// The index of the starting char within this line, relative to the entire text content.
pub fn char_index(&self) -> usize {
self.graphemes
.first()
.map(|grapheme| grapheme.char_index)
.unwrap_or_default()
}
/// The total number of chars in this line.
pub fn total_chars(&self) -> usize {
let end = self
.graphemes
.last()
.map(|grapheme| grapheme.char_index + grapheme.char_total);
match end {
Some(index) if index > 0 => index - self.char_index(),
_ => 0,
}
}
/// Add a new grapheme to this line.
pub fn add_grapheme(&mut self, grapheme: Grapheme) {
self.width += grapheme.size.0;
self.graphemes.push(grapheme)
}
}
impl PartialOrd for Line {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.grapheme_index.partial_cmp(&other.grapheme_index)
}
}
impl<I: SliceIndex<[Grapheme]>> Index<I> for Line {
type Output = I::Output;
fn index(&self, index: I) -> &Self::Output {
self.grapheme(index)
}
}