aboutsummaryrefslogtreecommitdiff
path: root/src/text/rich.rs
diff options
context:
space:
mode:
authoralex-ds13 <145657253+alex-ds13@users.noreply.github.com>2025-11-26 16:11:18 +0000
committerPolesznyák Márk <contact@pml68.dev>2025-12-30 18:13:59 +0100
commit688b6b58b2ccf7006ec53acb63e69fa9469c1e11 (patch)
treee1a7c62e4e4f2028cd3b0ce0208c388ae29475ff /src/text/rich.rs
parentdocs: update changelog (diff)
downloadiced_selection-688b6b58b2ccf7006ec53acb63e69fa9469c1e11.tar.gz
feat: implement selection across bounds with hacky copy solution
- This commit implements the selection across bounds, which is it allows a selection to start out of bounds and allows a selection that started on another widget to be dragged in bounds and select multiple different widgets. However in order to get the copy working on `ctrl/cmd + c` it resorts to a hacky solution where each widget clears the clipboard when a drag movement comes into its bounds and when the user presses `ctrl/cmd + c` it appends it's selected text to the clipboard.
Diffstat (limited to 'src/text/rich.rs')
-rw-r--r--src/text/rich.rs90
1 files changed, 86 insertions, 4 deletions
diff --git a/src/text/rich.rs b/src/text/rich.rs
index 865f64a..2285b4e 100644
--- a/src/text/rich.rs
+++ b/src/text/rich.rs
@@ -224,6 +224,8 @@ struct State<Link> {
selection: Selection,
dragging: Option<Dragging>,
last_click: Option<mouse::Click>,
+ potential_click: Option<mouse::Click>,
+ has_cleared_clipboard: bool,
keyboard_modifiers: keyboard::Modifiers,
visual_lines_bounds: Vec<core::Rectangle>,
}
@@ -364,6 +366,8 @@ where
selection: Selection::default(),
dragging: None,
last_click: None,
+ potential_click: None,
+ has_cleared_clipboard: false,
keyboard_modifiers: keyboard::Modifiers::default(),
visual_lines_bounds: Vec::new(),
})
@@ -628,6 +632,14 @@ where
shell.capture_event();
} else {
+ if let Some(position) = cursor.land().position() {
+ let potential_click = mouse::Click::new(
+ position,
+ mouse::Button::Left,
+ state.potential_click,
+ );
+ state.potential_click = Some(potential_click);
+ }
state.selection = Selection::default();
}
}
@@ -635,6 +647,7 @@ where
| Event::Touch(touch::Event::FingerLifted { .. })
| Event::Touch(touch::Event::FingerLost { .. }) => {
state.dragging = None;
+ state.potential_click = None;
if !matches!(
event,
Event::Touch(touch::Event::FingerLost { .. })
@@ -689,6 +702,65 @@ where
);
}
};
+ } else if let Some(potential_click) = state.potential_click
+ && let Some(position) = cursor.position_over(bounds)
+ {
+ // We had a click outside of bounds that dragged inside bounds
+ let (line, index) = state
+ .grapheme_line_and_index(
+ potential_click.position(),
+ bounds,
+ )
+ .unwrap_or((0, 0));
+ let new_start = SelectionEnd { line, index };
+ state.selection.select_range(new_start, new_start);
+
+ let (line, index) = state
+ .grapheme_line_and_index(position, bounds)
+ .unwrap_or((0, 0));
+
+ match potential_click.kind() {
+ mouse::click::Kind::Single => {
+ let new_end = SelectionEnd { line, index };
+
+ state.selection.change_selection(new_end);
+
+ state.dragging = Some(Dragging::Grapheme);
+ }
+ mouse::click::Kind::Double => {
+ let new_end = SelectionEnd { line, index };
+
+ state.selection.select_word(
+ new_start.line,
+ new_start.index,
+ &state.paragraph,
+ );
+ state.selection.change_selection_by_word(
+ new_end,
+ &state.paragraph,
+ );
+
+ state.dragging = Some(Dragging::Word);
+ }
+ mouse::click::Kind::Triple => {
+ state
+ .selection
+ .select_line(new_start.line, &state.paragraph);
+ state.selection.change_selection_by_line(
+ line,
+ &state.paragraph,
+ );
+ state.dragging = Some(Dragging::Line);
+ }
+ }
+
+ state.last_click = Some(potential_click);
+ state.potential_click = None;
+
+ // Clear the clipboard so that we can append to it if the user presses the copy
+ // shortcut to be able to include all selected texts.
+ clipboard.write(clipboard::Kind::Standard, String::new());
+ state.has_cleared_clipboard = true;
}
}
Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => {
@@ -697,10 +769,20 @@ where
if state.keyboard_modifiers.command()
&& !state.selection.is_empty() =>
{
- clipboard.write(
- clipboard::Kind::Standard,
- state.selection.text(&state.paragraph),
- );
+ let contents =
+ if state.has_cleared_clipboard {
+ state.has_cleared_clipboard = false;
+ clipboard
+ .read(clipboard::Kind::Standard)
+ .map(|c| {
+ if !c.is_empty() { c + "\n" } else { c }
+ })
+ .unwrap_or_default()
+ + &state.selection.text(&state.paragraph)
+ } else {
+ state.selection.text(&state.paragraph)
+ };
+ clipboard.write(clipboard::Kind::Standard, contents);
shell.capture_event();
}