Implement Cursor::Selection calculation in Editor::cursor
This commit is contained in:
parent
a28ed825c1
commit
40eb648f1e
2 changed files with 120 additions and 4 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::core::text::editor::{self, Action, Cursor};
|
use crate::core::text::editor::{self, Action, Cursor};
|
||||||
use crate::core::text::LineHeight;
|
use crate::core::text::LineHeight;
|
||||||
use crate::core::{Font, Pixels, Point, Size};
|
use crate::core::{Font, Pixels, Point, Rectangle, Size, Vector};
|
||||||
use crate::text;
|
use crate::text;
|
||||||
|
|
||||||
use cosmic_text::Edit;
|
use cosmic_text::Edit;
|
||||||
|
|
@ -80,8 +80,70 @@ impl editor::Editor for Editor {
|
||||||
if cursor.line != selection.line
|
if cursor.line != selection.line
|
||||||
|| cursor.index != selection.index =>
|
|| cursor.index != selection.index =>
|
||||||
{
|
{
|
||||||
// TODO
|
let line_height = buffer.metrics().line_height;
|
||||||
Cursor::Selection(vec![])
|
let scroll_offset = buffer.scroll() as f32 * line_height;
|
||||||
|
|
||||||
|
let (start, end) = if cursor < selection {
|
||||||
|
(cursor, selection)
|
||||||
|
} else {
|
||||||
|
(selection, cursor)
|
||||||
|
};
|
||||||
|
|
||||||
|
let visual_lines_before_start: usize = buffer
|
||||||
|
.lines
|
||||||
|
.iter()
|
||||||
|
.take(start.line)
|
||||||
|
.map(|line| {
|
||||||
|
line.layout_opt()
|
||||||
|
.as_ref()
|
||||||
|
.expect("Line layout should be cached")
|
||||||
|
.len()
|
||||||
|
})
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
let selected_lines = end.line - start.line + 1;
|
||||||
|
|
||||||
|
let regions = buffer
|
||||||
|
.lines
|
||||||
|
.iter()
|
||||||
|
.skip(start.line)
|
||||||
|
.take(selected_lines)
|
||||||
|
.enumerate()
|
||||||
|
.flat_map(|(i, line)| {
|
||||||
|
highlight_line(
|
||||||
|
line,
|
||||||
|
if i == 0 { start.index } else { 0 },
|
||||||
|
if i == selected_lines - 1 {
|
||||||
|
end.index
|
||||||
|
} else {
|
||||||
|
line.text().len()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(visual_line, (x, width))| {
|
||||||
|
if width > 0.0 {
|
||||||
|
Some(Rectangle {
|
||||||
|
x,
|
||||||
|
width,
|
||||||
|
y: visual_line as f32 * line_height,
|
||||||
|
height: line_height,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|region| {
|
||||||
|
region
|
||||||
|
+ Vector::new(
|
||||||
|
0.0,
|
||||||
|
visual_lines_before_start as f32 * line_height
|
||||||
|
+ scroll_offset,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Cursor::Selection(regions)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let lines_before_cursor: usize = buffer
|
let lines_before_cursor: usize = buffer
|
||||||
|
|
@ -332,3 +394,53 @@ impl PartialEq for Weak {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn highlight_line<'a>(
|
||||||
|
line: &'a cosmic_text::BufferLine,
|
||||||
|
from: usize,
|
||||||
|
to: usize,
|
||||||
|
) -> impl Iterator<Item = (f32, f32)> + 'a {
|
||||||
|
let layout = line
|
||||||
|
.layout_opt()
|
||||||
|
.as_ref()
|
||||||
|
.expect("Line layout should be cached");
|
||||||
|
|
||||||
|
layout.iter().map(move |visual_line| {
|
||||||
|
let start = visual_line
|
||||||
|
.glyphs
|
||||||
|
.first()
|
||||||
|
.map(|glyph| glyph.start)
|
||||||
|
.unwrap_or(0);
|
||||||
|
let end = visual_line
|
||||||
|
.glyphs
|
||||||
|
.last()
|
||||||
|
.map(|glyph| glyph.end)
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let range = start.max(from)..end.min(to);
|
||||||
|
|
||||||
|
if range.is_empty() {
|
||||||
|
(0.0, 0.0)
|
||||||
|
} else if range.start == start && range.end == end {
|
||||||
|
(0.0, visual_line.w)
|
||||||
|
} else {
|
||||||
|
let first_glyph = visual_line
|
||||||
|
.glyphs
|
||||||
|
.iter()
|
||||||
|
.position(|glyph| range.start <= glyph.start)
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let mut glyphs = visual_line.glyphs.iter();
|
||||||
|
|
||||||
|
let x =
|
||||||
|
glyphs.by_ref().take(first_glyph).map(|glyph| glyph.w).sum();
|
||||||
|
|
||||||
|
let width: f32 = glyphs
|
||||||
|
.take_while(|glyph| range.end > glyph.start)
|
||||||
|
.map(|glyph| glyph.w)
|
||||||
|
.sum();
|
||||||
|
|
||||||
|
(x, width)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,11 @@ where
|
||||||
for range in ranges {
|
for range in ranges {
|
||||||
renderer.fill_quad(
|
renderer.fill_quad(
|
||||||
renderer::Quad {
|
renderer::Quad {
|
||||||
bounds: range + Vector::new(bounds.x, bounds.y),
|
bounds: range
|
||||||
|
+ Vector::new(
|
||||||
|
bounds.x + self.padding.left,
|
||||||
|
bounds.y + self.padding.top,
|
||||||
|
),
|
||||||
border_radius: 0.0.into(),
|
border_radius: 0.0.into(),
|
||||||
border_width: 0.0,
|
border_width: 0.0,
|
||||||
border_color: Color::TRANSPARENT,
|
border_color: Color::TRANSPARENT,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue