Compare commits

1 Commits

Author SHA1 Message Date
bf3ade840b triple click to select line + fix highlighting 2025-11-22 20:49:38 -05:00
2 changed files with 35 additions and 9 deletions

View File

@@ -92,11 +92,7 @@ impl TextBuilderOutput for TextEditOutput {
builder.attrs.font_size, builder.attrs.font_size,
builder.attrs.line_height, builder.attrs.line_height,
)); ));
let mut text = TextEdit { let mut text = TextEdit::new(TextView::new(buf, builder.attrs, builder.hint.get(ui)));
view: TextView::new(buf, builder.attrs, builder.hint.get(ui)),
selection: Default::default(),
history: Default::default(),
};
let font_system = &mut ui.data.text.font_system; let font_system = &mut ui.data.text.font_system;
text.buf text.buf
.set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None); .set_text(font_system, &builder.content, &Attrs::new(), SHAPING, None);

View File

@@ -9,12 +9,21 @@ use winit::{
}; };
pub struct TextEdit { pub struct TextEdit {
pub(super) view: TextView, view: TextView,
pub(super) selection: TextSelection, selection: TextSelection,
pub(super) history: Vec<(String, TextSelection)>, history: Vec<(String, TextSelection)>,
double_hit: Option<Cursor>,
} }
impl TextEdit { impl TextEdit {
pub fn new(view: TextView) -> Self {
Self {
view,
selection: Default::default(),
history: Default::default(),
double_hit: None,
}
}
pub fn select_content(&self, start: Cursor, end: Cursor) -> String { pub fn select_content(&self, start: Cursor, end: Cursor) -> String {
let (start, end) = sort_cursors(start, end); let (start, end) = sort_cursors(start, end);
let mut iter = self.buf.lines.iter().skip(start.line); let mut iter = self.buf.lines.iter().skip(start.line);
@@ -106,6 +115,9 @@ fn iter_layout_lines(
} }
} }
for line in iter { for line in iter {
if line.line_i > end.line {
return;
}
if line.line_i == end.line if line.line_i == end.line
&& let Some(end_x) = index_x(&line, end.index) && let Some(end_x) = index_x(&line, end.index)
{ {
@@ -339,6 +351,14 @@ impl<'a> TextEditCtx<'a> {
} }
} }
pub fn select_line_at(&mut self, cursor: Cursor) {
let end = self.text.buf.lines[cursor.line].text().len();
self.text.selection = TextSelection::Span {
start: Cursor::new(cursor.line, 0),
end: Cursor::new(cursor.line, end),
}
}
pub fn select(&mut self, pos: Vec2, size: Vec2, drag: bool, recent: bool) { pub fn select(&mut self, pos: Vec2, size: Vec2, drag: bool, recent: bool) {
let pos = pos - self.text.region().top_left().to_abs(size); let pos = pos - self.text.region().top_left().to_abs(size);
let hit = self.text.buf.hit(pos.x, pos.y); let hit = self.text.buf.hit(pos.x, pos.y);
@@ -354,6 +374,7 @@ impl<'a> TextEditCtx<'a> {
(None, true) => (), (None, true) => (),
(Some(hit), false) => { (Some(hit), false) => {
if recent && hit == *pos { if recent && hit == *pos {
self.text.double_hit = Some(hit);
return self.select_word_at(hit); return self.select_word_at(hit);
} else { } else {
*pos = hit *pos = hit
@@ -364,7 +385,16 @@ impl<'a> TextEditCtx<'a> {
TextSelection::Span { start, end } => match (hit, drag) { TextSelection::Span { start, end } => match (hit, drag) {
(None, false) => *sel = TextSelection::None, (None, false) => *sel = TextSelection::None,
(None, true) => *sel = TextSelection::Pos(*start), (None, true) => *sel = TextSelection::Pos(*start),
(Some(hit), false) => *sel = TextSelection::Pos(hit), (Some(hit), false) => {
if recent
&& let Some(double) = self.text.double_hit
&& double == hit
{
return self.select_line_at(hit);
} else {
*sel = TextSelection::Pos(hit)
}
}
(Some(hit), true) => *end = hit, (Some(hit), true) => *end = hit,
}, },
} }