aboutsummaryrefslogtreecommitdiff
path: root/src/text
diff options
context:
space:
mode:
authoralex-ds13 <145657253+alex-ds13@users.noreply.github.com>2025-12-04 02:40:12 +0000
committerPolesznyák Márk <contact@pml68.dev>2025-12-30 18:13:59 +0100
commitde65c1dc7285b15c87862198b98b435345715d7d (patch)
treeb864fda857f039595990405c2143d80ebbe8029a /src/text
parentfeat: implement selection across bounds with hacky copy solution (diff)
downloadiced_selection-de65c1dc7285b15c87862198b98b435345715d7d.tar.gz
feat(selectable): draft implementation of selectable widget
Diffstat (limited to 'src/text')
-rw-r--r--src/text/rich.rs85
1 files changed, 63 insertions, 22 deletions
diff --git a/src/text/rich.rs b/src/text/rich.rs
index 2285b4e..b49adbd 100644
--- a/src/text/rich.rs
+++ b/src/text/rich.rs
@@ -10,6 +10,7 @@ use crate::core::mouse;
use crate::core::renderer;
use crate::core::text::{Paragraph as _, Span};
use crate::core::touch;
+use crate::core::widget::Operation;
use crate::core::widget::text::{Alignment, LineHeight, Shaping, Wrapping};
use crate::core::widget::tree::{self, Tree};
use crate::core::{
@@ -44,6 +45,7 @@ pub struct Rich<
on_link_click: Option<Box<dyn Fn(Link) -> Message + 'a>>,
on_link_hover: Option<Box<dyn Fn(Link) -> Message + 'a>>,
on_hover_lost: Option<Box<dyn Fn() -> Message + 'a>>,
+ independent_selection: bool,
}
impl<'a, Link, Message, Theme, Renderer>
@@ -70,6 +72,7 @@ where
on_link_click: None,
on_link_hover: None,
on_hover_lost: None,
+ independent_selection: true,
}
}
@@ -184,6 +187,15 @@ where
self
}
+ /// Makes this [`Rich`] selection independent of others.
+ ///
+ /// Independent texts handle their own selection copy and don't allow being selected from
+ /// outside its bounds.
+ pub fn independent(mut self, independent_selection: bool) -> Self {
+ self.independent_selection = independent_selection;
+ self
+ }
+
/// Sets the default style of the [`Rich`] text.
#[must_use]
pub fn style(mut self, style: impl Fn(&Theme) -> Style + 'a) -> Self
@@ -225,7 +237,6 @@ struct State<Link> {
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>,
}
@@ -367,7 +378,6 @@ where
dragging: None,
last_click: None,
potential_click: None,
- has_cleared_clipboard: false,
keyboard_modifiers: keyboard::Modifiers::default(),
visual_lines_bounds: Vec::new(),
})
@@ -632,7 +642,9 @@ where
shell.capture_event();
} else {
- if let Some(position) = cursor.land().position() {
+ if let Some(position) = cursor.land().position()
+ && !self.independent_selection
+ {
let potential_click = mouse::Click::new(
position,
mouse::Button::Left,
@@ -756,33 +768,20 @@ where
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, .. }) => {
match key.as_ref() {
keyboard::Key::Character("c")
if state.keyboard_modifiers.command()
+ && !shell.is_event_captured()
+ && self.independent_selection
&& !state.selection.is_empty() =>
{
- 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);
+ clipboard.write(
+ clipboard::Kind::Standard,
+ state.selection.text(&state.paragraph),
+ );
shell.capture_event();
}
@@ -921,6 +920,48 @@ where
}
}
+ fn operate(
+ &mut self,
+ state: &mut Tree,
+ layout: Layout<'_>,
+ _renderer: &Renderer,
+ operation: &mut dyn Operation,
+ ) {
+ let state = state.state.downcast_ref::<State<Link>>();
+ operation.text(
+ None,
+ layout.bounds(),
+ &state.paragraph.buffer().lines.iter().fold(
+ String::new(),
+ |mut str, l| {
+ if !str.is_empty() {
+ str.push('\n');
+ }
+ str.push_str(l.text());
+ str
+ },
+ ),
+ );
+
+ if !self.independent_selection {
+ let selection = state.selection.text(&state.paragraph);
+ if !selection.is_empty() {
+ operation.custom(
+ None,
+ layout.bounds(),
+ &mut crate::operation::Selection(selection),
+ );
+ }
+ }
+
+ // let mut isel = crate::operation::IndependentSelection::new(&mut self.independent_selection);
+ operation.custom(
+ None,
+ layout.bounds(),
+ &mut self.independent_selection,
+ );
+ }
+
fn mouse_interaction(
&self,
tree: &Tree,