aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/text.rs60
-rw-r--r--src/text/rich.rs57
2 files changed, 108 insertions, 9 deletions
diff --git a/src/text.rs b/src/text.rs
index bef9ed4..204587b 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -178,6 +178,7 @@ pub struct State {
dragging: Option<Dragging>,
last_click: Option<mouse::Click>,
keyboard_modifiers: keyboard::Modifiers,
+ visual_lines_bounds: Vec<core::Rectangle>,
}
/// The type of dragging selection.
@@ -204,10 +205,31 @@ impl State {
};
let bounded_y = point.y.max(bounds.y).min(bounds.y + bounds.height);
let bounded_point = Point::new(bounded_x, bounded_y);
- let relative_point =
+ let mut relative_point =
bounded_point - core::Vector::new(bounds.x, bounds.y);
let buffer = self.paragraph.buffer();
+ let line_height = buffer.metrics().line_height;
+ let visual_line = (relative_point.y / line_height).floor() as usize;
+ let visual_line_start_offset = self
+ .visual_lines_bounds
+ .get(visual_line)
+ .map(|r| r.x)
+ .unwrap_or_default();
+ let visual_line_end = self
+ .visual_lines_bounds
+ .get(visual_line)
+ .map(|r| r.x + r.width)
+ .unwrap_or_default();
+
+ if relative_point.x < visual_line_start_offset {
+ relative_point.x = visual_line_start_offset;
+ }
+
+ if relative_point.x > visual_line_end {
+ relative_point.x = visual_line_end;
+ }
+
let cursor = buffer.hit(relative_point.x, relative_point.y)?;
let value = buffer.lines[cursor.line].text();
@@ -269,17 +291,39 @@ impl State {
if self.content != text.content {
text.content.clone_into(&mut self.content);
self.paragraph = Paragraph::with_text(text);
+ self.update_visual_bounds();
return;
}
match self.paragraph.compare(text.with_content(())) {
text::Difference::None => {}
- text::Difference::Bounds => self.paragraph.resize(text.bounds),
+ text::Difference::Bounds => {
+ self.paragraph.resize(text.bounds);
+ self.update_visual_bounds();
+ }
text::Difference::Shape => {
self.paragraph = Paragraph::with_text(text);
+ self.update_visual_bounds();
}
}
}
+
+ fn update_visual_bounds(&mut self) {
+ let buffer = self.paragraph.buffer();
+ let line_height = buffer.metrics().line_height;
+ self.visual_lines_bounds = buffer
+ .lines
+ .iter()
+ .flat_map(|line| highlight_line(line, 0, line.text().len()))
+ .enumerate()
+ .map(|(visual_line, (x, width))| core::Rectangle {
+ x,
+ width,
+ y: visual_line as f32 * line_height - buffer.scroll().vertical,
+ height: line_height,
+ })
+ .collect();
+ }
}
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
@@ -788,10 +832,16 @@ fn highlight_line(
let range = start.max(from)..end.min(to);
+ let x_offset = visual_line
+ .glyphs
+ .first()
+ .map(|glyph| glyph.x)
+ .unwrap_or_default();
+
if range.is_empty() {
- (0.0, 0.0)
+ (x_offset, 0.0)
} else if range.start == start && range.end == end {
- (0.0, visual_line.w)
+ (x_offset, visual_line.w)
} else {
let first_glyph = visual_line
.glyphs
@@ -809,7 +859,7 @@ fn highlight_line(
.map(|glyph| glyph.w)
.sum();
- (x, width)
+ (x_offset + x, width)
}
})
}
diff --git a/src/text/rich.rs b/src/text/rich.rs
index 6815a44..e54b64a 100644
--- a/src/text/rich.rs
+++ b/src/text/rich.rs
@@ -221,6 +221,7 @@ struct State<Link> {
dragging: Option<Dragging>,
last_click: Option<mouse::Click>,
keyboard_modifiers: keyboard::Modifiers,
+ visual_lines_bounds: Vec<core::Rectangle>,
}
impl<Link> State<Link> {
@@ -238,10 +239,31 @@ impl<Link> State<Link> {
};
let bounded_y = point.y.max(bounds.y).min(bounds.y + bounds.height);
let bounded_point = Point::new(bounded_x, bounded_y);
- let relative_point =
+ let mut relative_point =
bounded_point - core::Vector::new(bounds.x, bounds.y);
let buffer = self.paragraph.buffer();
+ let line_height = buffer.metrics().line_height;
+ let visual_line = (relative_point.y / line_height).floor() as usize;
+ let visual_line_start_offset = self
+ .visual_lines_bounds
+ .get(visual_line)
+ .map(|r| r.x)
+ .unwrap_or_default();
+ let visual_line_end = self
+ .visual_lines_bounds
+ .get(visual_line)
+ .map(|r| r.x + r.width)
+ .unwrap_or_default();
+
+ if relative_point.x < visual_line_start_offset {
+ relative_point.x = visual_line_start_offset;
+ }
+
+ if relative_point.x > visual_line_end {
+ relative_point.x = visual_line_end;
+ }
+
let cursor = buffer.hit(relative_point.x, relative_point.y)?;
let value = buffer.lines[cursor.line].text();
@@ -298,6 +320,23 @@ impl<Link> State<Link> {
})
.collect()
}
+
+ fn update_visual_bounds(&mut self) {
+ let buffer = self.paragraph.buffer();
+ let line_height = buffer.metrics().line_height;
+ self.visual_lines_bounds = buffer
+ .lines
+ .iter()
+ .flat_map(|line| highlight_line(line, 0, line.text().len()))
+ .enumerate()
+ .map(|(visual_line, (x, width))| core::Rectangle {
+ x,
+ width,
+ y: visual_line as f32 * line_height - buffer.scroll().vertical,
+ height: line_height,
+ })
+ .collect();
+ }
}
impl<Link, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
@@ -322,6 +361,7 @@ where
dragging: None,
last_click: None,
keyboard_modifiers: keyboard::Modifiers::default(),
+ visual_lines_bounds: Vec::new(),
})
}
@@ -856,6 +896,7 @@ where
state.paragraph =
Renderer::Paragraph::with_spans(text_with_spans());
state.spans = spans.iter().cloned().map(Span::to_static).collect();
+ state.update_visual_bounds();
} else {
match state.paragraph.compare(core::Text {
content: (),
@@ -871,10 +912,12 @@ where
core::text::Difference::None => {}
core::text::Difference::Bounds => {
state.paragraph.resize(bounds);
+ state.update_visual_bounds();
}
core::text::Difference::Shape => {
state.paragraph =
Renderer::Paragraph::with_spans(text_with_spans());
+ state.update_visual_bounds();
}
}
}
@@ -936,10 +979,16 @@ fn highlight_line(
let range = start.max(from)..end.min(to);
+ let x_offset = visual_line
+ .glyphs
+ .first()
+ .map(|glyph| glyph.x)
+ .unwrap_or_default();
+
if range.is_empty() {
- (0.0, 0.0)
+ (x_offset, 0.0)
} else if range.start == start && range.end == end {
- (0.0, visual_line.w)
+ (x_offset, visual_line.w)
} else {
let first_glyph = visual_line
.glyphs
@@ -957,7 +1006,7 @@ fn highlight_line(
.map(|glyph| glyph.w)
.sum();
- (x, width)
+ (x_offset + x, width)
}
})
}