Keyboard input, text input elements
This commit is contained in:
@@ -228,6 +228,18 @@ impl PreparedText {
|
||||
rects
|
||||
}
|
||||
|
||||
pub fn caret_rect(&self, offset: usize, width: f32) -> Option<Rect> {
|
||||
let width = width.max(0.0);
|
||||
let line = self.line_for_offset(offset)?;
|
||||
let x = self.caret_x_for_line_offset(line, offset);
|
||||
Some(Rect::new(
|
||||
x,
|
||||
line.rect.origin.y,
|
||||
width,
|
||||
line.rect.size.height,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn apply_selected_text_color(&mut self, start: usize, end: usize) {
|
||||
let Some(selected_color) = self.selection_style.text_color else {
|
||||
return;
|
||||
@@ -260,6 +272,18 @@ impl PreparedText {
|
||||
Some(last)
|
||||
}
|
||||
|
||||
fn line_for_offset(&self, offset: usize) -> Option<&PreparedTextLine> {
|
||||
let offset = offset.min(self.text.len());
|
||||
let mut lines = self.lines.iter();
|
||||
let first = lines.next()?;
|
||||
for line in std::iter::once(first).chain(lines) {
|
||||
if offset <= line.text_end {
|
||||
return Some(line);
|
||||
}
|
||||
}
|
||||
Some(self.lines.last().unwrap_or(first))
|
||||
}
|
||||
|
||||
fn byte_offset_for_line_position(&self, line: &PreparedTextLine, x: f32) -> usize {
|
||||
if line.glyph_start == line.glyph_end {
|
||||
return line.text_start;
|
||||
@@ -285,6 +309,33 @@ impl PreparedText {
|
||||
|
||||
line.text_end
|
||||
}
|
||||
|
||||
fn caret_x_for_line_offset(&self, line: &PreparedTextLine, offset: usize) -> f32 {
|
||||
if line.glyph_start == line.glyph_end {
|
||||
return line.rect.origin.x;
|
||||
}
|
||||
|
||||
let offset = offset.min(self.text.len());
|
||||
let line_glyphs = &self.glyphs[line.glyph_start..line.glyph_end];
|
||||
let first_glyph = &line_glyphs[0];
|
||||
if offset <= first_glyph.text_start {
|
||||
return first_glyph.position.x;
|
||||
}
|
||||
|
||||
for glyph in line_glyphs {
|
||||
if offset <= glyph.text_start {
|
||||
return glyph.position.x;
|
||||
}
|
||||
if offset <= glyph.text_end {
|
||||
return glyph.position.x + glyph.advance.max(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
line_glyphs
|
||||
.last()
|
||||
.map(|glyph| glyph.position.x + glyph.advance.max(0.0))
|
||||
.unwrap_or(line.rect.origin.x)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@@ -409,4 +460,28 @@ mod tests {
|
||||
assert_eq!(text.glyphs[1].color, Color::rgb(0x11, 0x12, 0x1A));
|
||||
assert_eq!(text.glyphs[2].color, Color::rgb(0x11, 0x12, 0x1A));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prepared_text_caret_rect_tracks_cluster_boundaries() {
|
||||
let text = PreparedText::monospace(
|
||||
"abcd",
|
||||
Point::new(10.0, 20.0),
|
||||
16.0,
|
||||
8.0,
|
||||
Color::rgb(0xFF, 0xFF, 0xFF),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
text.caret_rect(0, 2.0),
|
||||
Some(Rect::new(10.0, 20.0, 2.0, 16.0))
|
||||
);
|
||||
assert_eq!(
|
||||
text.caret_rect(2, 2.0),
|
||||
Some(Rect::new(26.0, 20.0, 2.0, 16.0))
|
||||
);
|
||||
assert_eq!(
|
||||
text.caret_rect(4, 2.0),
|
||||
Some(Rect::new(42.0, 20.0, 2.0, 16.0))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user