remove highlight_blocks, add LayoutRun::highlight
This commit is contained in:
parent
25d04ace1c
commit
210ca61f13
1 changed files with 37 additions and 83 deletions
120
src/buffer.rs
120
src/buffer.rs
|
|
@ -20,7 +20,7 @@ use crate::Color;
|
||||||
pub struct Cursor {
|
pub struct Cursor {
|
||||||
/// Text line the cursor is on
|
/// Text line the cursor is on
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
/// Index of glyph at cursor (will insert behind this glyph)
|
/// First-byte-index of glyph at cursor (will insert behind this glyph)
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,6 +59,42 @@ pub struct LayoutRun<'a> {
|
||||||
pub line_w: f32,
|
pub line_w: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> LayoutRun<'a> {
|
||||||
|
/// Return the pixel span Some((x_start, x_width)) of the highlighted area between cursor_start
|
||||||
|
/// and cursor_end within this run, or None if the cursor range does not intersect this run.
|
||||||
|
/// This may return widths of zero if cursor_start == cursor_end, if the run is empty, or if the
|
||||||
|
/// region's left start boundary is the same as the cursor's end boundary or vice versa.
|
||||||
|
pub fn highlight(&self, cursor_start: Cursor, cursor_end: Cursor) -> Option<(f32, f32)> {
|
||||||
|
let mut x_start = None;
|
||||||
|
let mut x_end = None;
|
||||||
|
let rtl_factor = if self.rtl { 1. } else { 0. };
|
||||||
|
let ltr_factor = 1. - rtl_factor;
|
||||||
|
for glyph in self.glyphs.iter() {
|
||||||
|
let cursor = Cursor::new(self.line_i, glyph.start);
|
||||||
|
if cursor >= cursor_start && cursor <= cursor_end {
|
||||||
|
if x_start.is_none() {
|
||||||
|
x_start = Some(glyph.x + glyph.w * rtl_factor);
|
||||||
|
}
|
||||||
|
x_end = Some(glyph.x + glyph.w * rtl_factor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let cursor = Cursor::new(self.line_i, self.glyphs.last().map_or(0, |glyph| glyph.end));
|
||||||
|
if cursor >= cursor_start && cursor <= cursor_end {
|
||||||
|
if x_start.is_none() {
|
||||||
|
x_start = Some(self.glyphs.last().map_or(0., |glyph| glyph.x + glyph.w * ltr_factor));
|
||||||
|
}
|
||||||
|
x_end = Some(self.glyphs.last().map_or(0., |glyph| glyph.x + glyph.w * ltr_factor));
|
||||||
|
}
|
||||||
|
if let Some(x_start) = x_start {
|
||||||
|
let x_end = x_end.unwrap();
|
||||||
|
let (x_start, x_end) = if x_start < x_end { (x_start, x_end) } else { (x_end, x_start) };
|
||||||
|
Some((x_start, x_end - x_start))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An iterator of visible text lines, see [`LayoutRun`]
|
/// An iterator of visible text lines, see [`LayoutRun`]
|
||||||
pub struct LayoutRunIter<'a, 'b> {
|
pub struct LayoutRunIter<'a, 'b> {
|
||||||
buffer: &'b Buffer<'a>,
|
buffer: &'b Buffer<'a>,
|
||||||
|
|
@ -567,17 +603,6 @@ impl<'a> Buffer<'a> {
|
||||||
new_cursor_opt
|
new_cursor_opt
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn highlight_blocks<'b>(&'b self, cursor_start: Cursor, cursor_end: Cursor) -> HighlightBlocksIter<'a, 'b> {
|
|
||||||
HighlightBlocksIter {
|
|
||||||
cursor_start,
|
|
||||||
cursor_end,
|
|
||||||
line: 0,
|
|
||||||
layout_line: 0,
|
|
||||||
run_line: 0,
|
|
||||||
buffer: self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Draw the buffer
|
/// Draw the buffer
|
||||||
#[cfg(feature = "swash")]
|
#[cfg(feature = "swash")]
|
||||||
pub fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, mut f: F)
|
pub fn draw<F>(&self, cache: &mut crate::SwashCache, color: Color, mut f: F)
|
||||||
|
|
@ -599,74 +624,3 @@ impl<'a> Buffer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct HighlightBlocksIter<'a, 'b> {
|
|
||||||
cursor_start: Cursor,
|
|
||||||
cursor_end: Cursor,
|
|
||||||
line: usize,
|
|
||||||
layout_line: usize,
|
|
||||||
run_line: usize,
|
|
||||||
buffer: &'b Buffer<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> Iterator for HighlightBlocksIter<'a, 'b> {
|
|
||||||
type Item = (i32, i32, u32, u32);
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while !self.is_done() {
|
|
||||||
if let Some(result) = self.peek() {
|
|
||||||
self.advance();
|
|
||||||
return Some(result);
|
|
||||||
}
|
|
||||||
self.advance();
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b> HighlightBlocksIter<'a, 'b> {
|
|
||||||
pub fn peek(&self) -> Option<(i32, i32, u32, u32)> {
|
|
||||||
let Some(line) = self.buffer.lines.get(self.line) else { return None; };
|
|
||||||
let line: &BufferLine = line;
|
|
||||||
let run: &LayoutLine = line.layout_opt().as_ref().unwrap().get(self.run_line).unwrap();
|
|
||||||
let mut x_start = None;
|
|
||||||
let mut x_end = None;
|
|
||||||
for glyph in run.glyphs.iter() {
|
|
||||||
let cursor = Cursor::new(self.line, glyph.start);
|
|
||||||
if cursor >= self.cursor_start && cursor <= self.cursor_end {
|
|
||||||
if x_start.is_none() {
|
|
||||||
x_start = Some(glyph.x.round() as i32);
|
|
||||||
}
|
|
||||||
x_end = Some(glyph.x.round() as i32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let cursor = Cursor::new(self.line, run.glyphs.last().map_or(0, |glyph| glyph.end));
|
|
||||||
if cursor >= self.cursor_start && cursor <= self.cursor_end {
|
|
||||||
if x_start.is_none() {
|
|
||||||
x_start = Some(run.glyphs.last().map_or(0, |glyph| (glyph.x + glyph.w).round() as i32));
|
|
||||||
}
|
|
||||||
x_end = Some(run.glyphs.last().map_or(0, |glyph| (glyph.x + glyph.w).round() as i32));
|
|
||||||
}
|
|
||||||
if let Some(x_start) = x_start {
|
|
||||||
let x_end = x_end.unwrap();
|
|
||||||
Some((x_start, self.layout_line as i32 * self.buffer.metrics.line_height, (x_end - x_start) as u32, self.buffer.metrics.line_height as u32))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn advance(&mut self) {
|
|
||||||
let Some(line) = self.buffer.lines.get(self.line) else { return; };
|
|
||||||
let line: &BufferLine = line;
|
|
||||||
self.layout_line += 1;
|
|
||||||
self.run_line += 1;
|
|
||||||
if self.run_line >= line.layout_opt().as_ref().unwrap().len() {
|
|
||||||
self.run_line = 0;
|
|
||||||
self.line += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_done(&self) -> bool {
|
|
||||||
self.buffer.lines.get(self.line).is_none()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue